Skip to content

3. Prototype Pollution via Browser

Prototype pollution via browser APIs

Es gibt eine Reihe von verbreiteten Prototype-Gadgets in den Javascript-APIs die der Browser üblicherweise bereitstellt.

Prototype pollution via fetch()

Die Fetch API ermöglicht es, HTTP-Requests per JavaScript abzusetzen. fetch() nimmt zwei Argumente: 1. Die URL, an die die Anfrage gesendet wird. 2. Ein Options-Objekt, mit dem du Teile der Anfrage steuerst (Methode, Header, Body-Parameter usw.).

Beispiel für einen POST-Request mit fetch():

fetch('https://normal-website.com/my-account/change-email', {
    method: 'POST',
    body: 'user=carlos&email=carlos%40ginandjuice.shop'
})

Der folgende Code ist potenziell über Prototype Pollution für DOM-XSS verwundbar:

fetch('/my-products.json',{method:"GET"})
    .then((response) => response.json())
    .then((data) => {
        let username = data['x-username'];
        let message = document.querySelector('.message');
        if(username) {
            message.innerHTML = `My products. Logged in as <b>${username}</b>`;
        }
        let productList = document.querySelector('ul.products');
        for(let product of data) {
            let product = document.createElement('li');
            product.append(product.name);
            productList.append(product);
        }
    })
    .catch(console.error);

Um dies auszunutzen, könnte ein Angreifer Object.prototype mit einer headers-Property vergiften, die einen bösartigen Header x-username enthält:

?__proto__[headers][x-username]=<img/src/onerror=alert(1)>

Prototype Pollution über Object.defineProperty()

Entwickler, die Prototype Pollution kennen, versuchen manchmal, potenzielle Gadgets zu blockieren, indem sie Object.defineProperty() nutzen. Damit setzen sie eine nicht konfigurierbare und nicht schreibbare Property direkt auf dem betroffenen Objekt:

Object.defineProperty(vulnerableObject, 'gadgetProperty', {
    configurable: false,
    writable: false
})

An sich schön und gut, aber Fehleranfällig. Ähnlich wie fetch() nimmt Object.defineProperty() ein Options-Objekt entgegen – den sogenannten Descriptor (siehe oben). Darüber können Entwickler u. a. auch einen Initialwert für die definierte Property setzen. Wenn sie die Property aber nur definieren, um gegen Prototype Pollution abzusichern, setzen sie oft keinen Wert.

In diesem Fall kann ein Angreifer die Abwehr umgehen, indem er Object.prototype mit einer bösartigen value-Property verschmutzt. Wenn der Descriptor, der an Object.defineProperty() übergeben wird, diese value-Property erbt, wird der angreiferkontrollierte Wert am Ende doch der Gadget-Property zugewiesen.