Almost 50% of web pages have this bug. Learn How it is exploited in the wild
What we are up against.
Have you ever wondered how hackers find bugs on websites? What does it take to hunt for bugs and responsibly disclose them? In this article, we will be focusing mainly on a single bug called DOM-based XSS (cross-site scripting), which is found very often on web pages.
This XSS bug alone has paid out 4.2 million dollars to hackers on the HackerOne platform, according to 2020 statistics.
After reading this article, you will be able to find this bug faster. You will understand how to attack it in a real-world scenario and what tools to use.
Security measures by browser
SOP stands for same-origin policy. This is a security measure taken by the browser. According to it, one web page cannot access data from another webpage. It's possible only if both pages have the same origin.
An origin consists of a URI scheme, domain, and port number. These measures block the malicious script from one page accessing sensitive data on another page from the DOM. XSS poses a serious threat to this security mechanism.
A DOM-based attack Vector
Let's learn DOM first.
Imagine a blueprint or map for a house. The HTML we see on websites is like this blueprint. The DOM is like a dynamic, interactive version of the blueprint.
We can make changes like rearranging furniture in the house or adding new items without altering the original blueprint.
Likewise, the DOM (Document Object Model) allows you to manipulate and interact with the structure of the webpage. It does not modify the underlying HTML code. The following diagram explains how DOM is structured like a tree.
Example of DOM manipulation: We can change the content of an element using its id.
// HTML: <p id="demo">Hello, World!</p> document.getElementById("demo").innerHTML = "Welcome to the DOM!";
We can even change the style of elements
// HTML: <div id="myDiv">Content</div> document.getElementById("myDiv").style.color = "blue";
This is how DOM works. We can change element properties, add new elements, and do all kinds of modifications to the HTML using DOM manipulation.
The DOM represents a document with a logical tree. Each branch of the tree ends in a node, and each node contains objects. DOM methods allow programmatic access to the tree. With them, you can change the document's structure, style, or content.
When the DOM manipulation is done by the JS in an unsafe way, it's prone to DOM-based attacks. In attacks, hackers make use of the weak JS data handling to their advantage and try to modify the DOM, steal user data, etc.
There are many kinds of Dom-based attacks:
All about XSS you need to know
Let's first understand what XSS is. XSS stands for cross-site scripting which allows an attacker to inject malicious code into a website. This code is executed by the victims and lets the attackers bypass access controls and impersonate users.
Attack succeeds if the Web app does not employ enough validation or encoding.
Sinks are used to change the DOM. DOM-based XSS attacks happen when a user is able to write arbitrary JavaScript code and have it executed by one of these functions.
Functions that insert HTML into the document, such as Element.innerHTML
, Element.outerHTML
, or Document.write
.
Functions that execute code such as Global_Objects/eval
A source function is any JS property or function that accepts user input from somewhere on the page. An example of a source is the location.search property because it reads input from the query string.
Example:
location.search()
document.URL
document.documentURI
document.URLUnencoded
document.baseURI
location.search
* document.cookie
There are mainly three kinds of XSS
- Reflected XSS
- Stored XSS
- DOM-Based XSS
A DOM-based XSS attack is possible if the web application writes data to the Document Object Model without proper sanitization. The attacker can manipulate this data to include harmful XSS Scripts.
Typically, attacks happen when data controlled by a user (such as that input into a form field) reaches a function that can execute that data. These functions are known as injection sinks, as discussed above.
Let's see a quick example to get a good understanding.
The http://www.example.com/userdashboard.html
page is customized based on the user name. The user name is encoded in the URL and used directly on the resulting page:
<html> <head> <title>Custom Dashboard </title> ... </head> Main Dashboard for <script> var pos=document.URL.indexOf("context=")+8; document.write(document.URL.substring(pos,document.URL.length)); </script> ... </html>
http://www.example.com/userdashboard.html?context=Mary
is a dashboard customized for Mary. It contains the string Main Dashboard for Mary at the top.
Here is how a DOM-based XSS attack can be performed for this web application:
- The attacker embeds a malicious script in the URL:
http://www.example.com/userdashboard.html#context=<script>DangerousFunction(data)</script>
. - The victim’s browser receives this URL, sends an HTTP request to
http://www.example.com
, and receives the static HTML page. - The browser starts building the DOM of the page and populates the
document.URL
property with the URL from step 1. - The browser parses the HTML page, reaches the script, and runs it, extracting the malicious content from the
document.URL
property. - The browser updates the raw HTML body of the page to contain: Main Dashboard for
<script>DangerousFunction(data)</script>.
The browser finds the JavaScript code in the HTML body and executes it.
Statistics on the Prevalence in Web Pages
Almost 50% of the web pages are already affected by this DOM-based XSS. We either use PHP or JS for DOM manipulation. Anywhere we use them is potentially vulnerable if we are not careful.
Even big tech giants like Google, Yahoo, and Amazon had a lot of DOM-based XSS issues reported. Whenever anything is sent to the server from the browser, we need proper validation. Input should be properly sanitized before being sent to the server.
To defend against DOM XSS, you can: 1. Avoid using data received from the client for client-side sensitive actions such as rewriting or redirection. 2. Sanitize client-side code by inspecting references to DOM objects that pose a threat, for example, URL, location, and referrer. This is especially important if DOM may be modified. 3. Use intrusion prevention systems that can inspect inbound URL parameters and prevent inappropriate pages from being served.
Get your hands dirty
Let's try to solve a practical lab from the Portswigger Academy to get our knowledge asserted. We will be trying out this lab, Dom-based XSS lab.
We will be trying to exploit the search functionality of the blog with DOM based XSS.
On starting the lab, we get a blog page.
The first step is to try the search functionality where the bug is present according to the description. Let's try searching for football:
We can see that the URL changed to /?search=Football
Let's do an inspection to see what’s happening.
In trackSearch, they use document.write
to dynamically generate a <img>
tag with a source attribute pointing to a tracker image (/resources/images/tracker.gif) and include the search query as a parameter (searchTerms).
new URLSearchParams(window.location.search)
is used to create a new URLSearchParams object from the query string of the current URL (window.location.search).get('search')
is then called to retrieve the value of the 'search' parameter from the query string. The result is stored in the variable query.
When we do a location.search
it returns the values after “?”
in the URL. Here, location.search is our source. We can inject some malicious code using it from the browser.
Next, we have the operation document.write()
which is a sink. We can run this sink to execute arbitrary JS code. We can create a simple script to bypass the image tag and pop an alert.
This will execute a DOM-based XSS on the site. You can also try any other payload. You can find a collection of payloads here%3E-,DOM%20based%20XSS,-Based%20on%20a).
More Detection Techniques and Tools
For detecting these kinds of vulnerabilities, you should look into the HTML source code. Find script tags and see what is happening. Lookout for sources where you can input data. Then look for sinks that you can use to your advantage.
One of the tools is a browser DOM invader. DOM Invader is a browser-based tool that helps you test for DOM XSS vulnerabilities using a variety of sources and sinks, including both web message and prototype pollution vectors.
DOM Invader is a browser tool installed in Burp's in-built browser. It assists in detecting DOM XSS vulnerabilities using various sources and sinks, including web messages and prototype pollution. The tool is preinstalled as an extension.
DOM Invader integrates a tab within the browser's DevTools panel, enabling the following:
1. Identification of controllable sinks on a webpage for DOM XSS testing, providing context and sanitization details.
2. Logging, editing, and resending web messages sent via the postMessage()
method for DOM XSS testing. DOM Invader can also auto-detect vulnerabilities using specially crafted web messages.
3. Detection of client-side prototype pollution sources and scanning of controllable gadgets sent to risky sinks.
4. Identification of DOM clobbering vulnerabilitie
How to Train Your Skills
Here are some labs you can try to gain skills in the XSS area:
- Google XSS game
- alert(1)towin
- PortswiggerLabs You can refer to the DOMXSS wiki for an advanced knowledge base. Here is the initial study published on this vulnerability by Amit Klein: DOM-Based Cross-Site Scripting or XSS of the Third Kind .A look at an overlooked flavor of XSS
conclusion
So far, we have understood a lot about XSS and other web principles. It is time to use this understanding and hunt down such bugs on websites and follow responsible disclosure. I hope this article gave you a good idea of the workings of DOM-based XSS. Thank you for your time.