Lab: DOM XSS via client side prototype pollution

Manual Solution

Find a prototype pollution source

After starting the exercise, the blog should be similar to the one shown in the following illustration.

In the address line of the browser, we insert the property /?__proto__[foo]=bar at the end of the address and confirm the entry with ENTER.

As you can see, nothing changes on the website for the time being. We now open the DevTools. The easiest way to do this is to move the mouse over the blog and press the right mouse button. Then select Inspect from the context menu. In my case, the context menu is in German. Examine is the same as Inspect. In the DevTools we switch to the Console tab.

As I am using the Built-In Browser from Burp Suite, you will see the message "DOM Invader is NOT enabled." In the console, we now enter Object.prototype to display the properties of the object. If we now examine the properties of the returned object, we see that it now has a foo property with the value bar. We have thus successfully found a source of prototype contamination.

Identify a gadget

In DevTools, we now switch to the Sources tab and look for JavaScript files that are loaded by the application and may contain DOM XSS sinks. In the JavaScript file searchLogger.js, the object config has the property transport_url. This property is used to attach a script to the DOM. The code concerned is shown in the following code snippet.

// If the query string contains a `transport_url` parameter
    if(config.transport_url) {
        // Dynamically create a new <script> element
        let script = document.createElement('script');
        // Set the source of the script to the provided transport_url
        script.src = config.transport_url;

        // Append the script to the page, triggering its execution
        document.body.appendChild(script);
    }

Note that no transport_url property is defined for the config object. This is a possible function for controlling src of the <script> element.

Craft an Exploit

We now use our identified property transport_url as the prototype pollution source. To do this, we append /?__proto__[transport_url]=foo back to our query string in the address bar of our browser and press ENTER.

If we now switch to the Elements tab in the DevTools, we can see that the DOM contains a new tag.

Change the payload in the URL to inject an XSS proof-of-concept. For example, you can use a data: URL as follows: /?__proto__[transport_url]=data:,alert(1);

We now paste this payload into the address bar of our browser and press ENTER.

We receive the following window and have solved the exercise.

DOM Invader solution

When solving the exercise with the DOM Invader it is necessary that you use the Built-In Browser of the Burp Suite. After starting the exercise, the blog should look like the following image.

We now need to activate the DOM Invader in the browser. To do this, we click on the Burp Suite icon in the browser extensions.

A window should open in which we can activate the DOM Invader. To do this, we move the DOM Invader is on slider to the right.

In the Attack Types section, we also move the slider for Prototype Pollution is on to the right.

Now we click on the Reload button. In the upper area of the browser, we see a status display that informs us how far the DOM Invader has come with its analysis of the web application.

Now we switch to the DevTools of the browser, there are different ways to get there. The easiest way is to use the key combination CTRL + Shift + I. In the DevTools we switch to the DOM Invader tab.

In the DOM Invader tab, you can see that a sink (script.src) has been found. An update of the DOM Invader automatically searches for gadgets. There is a deviation from the sample solution here.

If we click on the link in the Stack Trace column. The stack trace is displayed in the console.

In the Console we see the JavaScript file in which Prototype Pollution occurs. If we click on the link, the file opens in the Source code tab.

The source code looks as follows. The problematic part of the code can be found in lines 12 to 15.

async function logQuery(url, params) {
    try {
        await fetch(url, {method: "post", keepalive: true, body: JSON.stringify(params)});
    } catch(e) {
        console.error("Failed storing query");
    }
}

async function searchLogger() {
    let config = {params: deparam(new URL(location).searchParams.toString())};

    if(config.transport_url) {
        let script = document.createElement('script');
        script.src = config.transport_url;
        document.body.appendChild(script);
    }

    if(config.params && config.params.search) {
        await logQuery('/logger', config.params);
    }
}

window.addEventListener("load", searchLogger);

We now return to the DOM Inavder tab and click on the Exploit button.

Wir erhalten folgende Meldung im Browser.

We have now successfully completed this exercise.

Video Solution

Last updated