portswigger-all-labs

Complete PortSwigger Web Security Academy Lab Writeups Detailed, categorized solutions for every lab — from APPRENTICE to EXPERT — covering all 30 vulnerability types.

View on GitHub

Labs Covered

This write-up focuses on the following PRACTITIONER-level labs from the PortSwigger Web Security Academy related to DOM-based vulnerabilities:

1 DOM XSS using web messages

This lab demonstrates how attackers can exploit insecure handling of `postMessage` web messages to achieve DOM-based XSS.

2 DOM XSS using web messages and a JavaScript URL

This lab extends the previous concept by leveraging JavaScript URLs to achieve DOM-based XSS through web messages.

3 DOM XSS using web messages and JSON.parse

This lab explores how insecure parsing of untrusted messages using `JSON.parse` can lead to DOM XSS.

4 DOM-based open redirection

This lab demonstrates how insecure handling of user input in redirects can allow DOM-based open redirection attacks.

5 DOM-based cookie manipulation

This lab shows how attackers can exploit DOM vulnerabilities to manipulate cookies directly within the browser.

LAB 1 - DOM XSS using web messages

Lab Description

image

Solution

As usual, the first step is to analyze the functionality of the lab application, in this case, a shop website. What immediately jumps at me is a weird [object Object] string above the product listing:

image

With the help of the browser inspector, I review the corresponding part of the HTML:

image

Whenever a message is sent to the window, an element of the DOM is changed. What is good news is that there are no forms of sanitization going on here, the raw message data is taken and put straight into the DOM.

The theory;

If I can load the page in an iframe within a page I control, I can send arbitrary data to the application. A quick google search brought me to the mozilla documentation for iframe . Interesting for the lab is the scripting information:

image

So I can access the window object of the lab application to send the message. I cannot inject a

To have the browser run my script I need to include it in a way that it runs while it tries to render the page, for example, in the onerror property of an tag.

The Mozilla documentation also shows the correct syntax for sending a message to the window object of the iframe:


postMessage(message, targetOrigin)
postMessage(message, targetOrigin, transfer)

My payload will be transported in the message, while the targetOrigin is the target domain or a * as a synonym for the full world.

The malicious page

Now I have all the information I require to craft a malicious page on the exploit server. As I care about the security of my exploit page, I use the full URL of my victim as targetOrigin:

image

Storing the exploit and viewing it opens the print dialog as expected. Directly after sending the exploit to the victim, the lab updates to solve

image


LAB 2 - DOM XSS using web messages and a JavaScript URL

Lab Description

image

Solution

As usual, the first step is to analyze the functionality of the lab application, in this case, a blog website. From plain browsing of the site, nothing is immediately obvious. So I turn to the source of the page and find an interesting script:

image

When a message is received by the window, a check is performed whether it contains an http: or https:. If found to be so, the current location will redirect to the data value of the message.

The theory

If I can load the page in an iframe within a page I control, I can send arbitrary data to the application. A google search brings me to the mozilla documentation for iframe. Interesting for the lab is the scripting information:

image

So I can access the window object of the lab application to send the message. The Mozilla documentation also shows the correct syntax for sending a message to the window object of the iframe:


postMessage(message, targetOrigin)
postMessage(message, targetOrigin, transfer)

My payload will be transported in the message, while the targetOrigin is the target domain or a * as a synonym for the full world.

I need a payload that contains an http: or https:, it does not require it at the beginning of the string. No other validation is done on the content. As long as I ensure one of these strings is anywhere in my code, for example in a JavaScript comment, it will pass the validation.

In most browsers, using javascript:alert("Hello World"); as URL will execute the code. As the code in the lab application puts whatever string I send straight into the URL.

The malicious page:

If the payload contains “http:” or “https:”, it will redirect to that page. Our payload in the exploit server:

<iframe src="https://0a0300fb03ec541d83b0e1af005a0096.web-security-academy.net/" onload="this.contentWindow.postMessage('https://as.com','*')" style="width:100%;height:100%">

When we click “View”, it redirects to as.com:

image

We can execute Javascript code with javascript:alert(1). As there are already nested quotes and double quotes we can use the character “`” to create an alert message with the previous url, so the payload wil still have “https:”:

<iframe src="https://0a0300fb03ec541d83b0e1af005a0096.web-security-academy.net/" onload="this.contentWindow.postMessage('javascript:alert`https://as.com`','*')" style="width:100%;height:100%">


image

If we change the payload to print the page:


<iframe src="https://0a0300fb03ec541d83b0e1af005a0096.web-security-academy.net/" onload="this.contentWindow.postMessage('javascript:print`https://as.com`','*')" style="width:100%;height:100%">

image


LAB 3 - DOM XSS using web messages and JSON.parse

Lab Description

image

Solution

As usual, the first step is to analyze the functionality of the lab application, in this case, a shop website. After browsing the public pages I move on to the HTML source of the page. On the main page an interesting script can be found:

image

Whenever a message is received, the script creates an iframe and appends it to the current page. The message is then parsed as JSON and, depending on the message content, an action may be performed. One of the possible actions is loading an URL contained in the message within the iframe.

The theory

If I can load the page in an iframe within a page I control, I can send arbitrary data to the application. A google search brings me to the mozilla documentation for iframe. Interesting for the lab is the scripting information:

image

So I can access the window object of the lab application to send the message. The Mozilla documentation also shows the correct syntax for sending a message to the window object of the iframe:

postMessage(message, targetOrigin)
postMessage(message, targetOrigin, transfer)

My payload will be transported in the message, while the targetOrigin is the target domain or a * as a synonym for the full world. The vulnerable script requires a valid JSON string in the message. It always contains a key type which can be one of page-load, load-channel or player-height-changed. In case the type is load-channel, an additional key url is assumed to be present in the message which is then loaded into the iframe. No further checks are done on the content of the message, so I can inject a JavaScript URL in there:


{
    "type": "load-channel", 
    "url": "javascript:print()"}

The malicious page

One question that always comes to mind when using strings is: Which types of quotes to use, single or double?

For this lab, I need three nested layers of quotations • the content of onload • the argument for postMessage • the strings within the JSON

The JSON RFC 7159 requires strings within JSON to use double quotes, so I need to use them there. I already need both types of quotes for the iframe onload content and its argument, so I need to escape the double quotes within the JSON string:


<iframesrc="https://0a21004a048f2b53c0c70b7c004c0002.web-security-academy.net/" 
    onload='contentWindow.postMessage("{\"type\": \"load-channel\", \"url\": \"javascript:print()\"}","*");'
></iframe>

This results in my malicious HTML page:

image

After storing I test the exploit by viewing it. As expected, the print window opens. All that is left now is to deliver the exploit to the victim and the lab updates to solved

image


LAB 4 - DOM-based open redirection

Lab Description

image

Solution

As usual, the first step is to analyze the functionality of the lab application, in this case, a blog website. After I browse through the page, I go check the HTML sources. One interesting piece of HTML can be found:

image

This link is found under every blog article and is used to determine the target of the link dynamically. If there is no parameter url in the URL of the page, then it redirects to the local base /. However, if the url parameter exists and starts with either http:// or https://, it will be used as the destination of the link. No further validation is performed on the destination target.

Now I know how to craft a URL that redirects to any target of my choice.

https://0aa4001903e8eff4c0973a9a00d3008e.web-security-academy.net/post?postId=5&url=https://exploit-0a610014032cefa6c0983abd01bd00c8.web-security-academy.net/exploit

As soon as I load that URL, the lab updates to solved

image


Lab Description

image

Solution

As usual, the first step is to analyze the functionality of the lab application, in this case, a shop website. After I browse through the page, I go check the HTML sources. One interesting piece of HTML can be found on the product pages:

image

This script stores the current page by URL in the cookie.

image

From this moment onwards, the requests are sent with that cookie and the page contains a Last viewed product link at the top:

image

image

First I test whether the application verifies that the target is within its own domain:

image

Next, I check if I can break out of the link and inject arbitrary HTML and JavaScript:

image

Sure enough, the cookie value can be used to execute arbitrary JavaScript in the scope of the page. The theory

The vulnerable script takes the raw input from window.location without any validation. Above, I verified that I can break out of the link context. So I need to take a valid product URL and attach my payload in a way that the URL stays valid and produces a product page. For example, with an additional and completely fictional parameter:

https://0ae5007c0406e52ec028374700af0043.web-security-academy.net/product?productId=1&evil='><script>alert(document.domain)</script>

I test this URL in the browser and, sure enough, the alert() box shows up.

If I load that crafted URL in an iframe within a page I control, I can inject arbitrary JavaScript into the cookie. However, the initial display of the page just writes the cookie. It requires a reload to send the cookie to the server and include the JavaScript into the page.

It is unlikely that my victim is inclined to help me with this, therefore I need a way to automate this.

My initial thought was to use a script within my malicious page that sleeps for some milliseconds and then reloads the iframe. However, after searching a bit I found that sleep is not as trivial in JavaScript as it is in other languages I know.

But I found the documentation of setTimeout which does what I want, albeit in an asynchronous way:

image

The malicious page

My malicious page loads the vulnerable product details page within an iframe, with my payload added as a URL parameter. After a few milliseconds, the frame content gets redirected to the base URL of the shop, thus triggering the script.


<iframename="victim" id="victim"
    src="https://0ae5007c0406e52ec028374700af0043.web-security-academy.net/product?productId=1&'><script>print()</script>" 
></iframe><script>setTimeout(()=>{document.getElementsByName('victim')[0].src="https://0ae5007c0406e52ec028374700af0043.web-security-academy.net"},500);</script>

image

After delivering the exploit to the victim, the lab updates to solved

image