DOM-based XSS also has reflected and stored sub-types, pretty much like it’s counterpart, the source-based XSS. They are exactly the same, with reflected/stored being provided by browser itself via its JS engine and client side storage.
However, unlike in the simple request/response model, DOM-based XSS might involve a lot of analysis of code flow in order to catch it. It’s hard to spot this flaw for static and even dynamic analysis tools.
Sources and Sinks
We have almost the same XSS logic in client side as we have in server side: we need something responsible for the input and another for the output. In server side we have things like $_GET[“var”] or $_POST[“var”] for the input and echo or print commands for the output in PHP language to make our XSS situation arise.
So in order to get our study of DOM-based XSS easier let’s look first at the sinks because there are only 3 main cases. Below is a page to demonstrate them. If you are experienced enough with XSS or just want to train yourself, stop this reading right now and XSS them following our #hack2learn principle.
The 3 Sinks
In our demonstration page, we have the following source code:
Before the first case, Document Sink, our code starts with the API to make possible to handle the value of URL parameters: after taking the search property of document’s location (which itself is property of document) we then create a new object implementing URLSearchParams.
The value of URL parameter “name” gets stored in “username” variable for later use in an update of the document. If that variable is not null, the paragraph element is updated with the content “Hello” plus the content provided in the URL via “name” parameter. That makes possible for an attacker to insert HTML code with:
Important to note here is the fact that classic “<script>alert(1)</script>” won’t work. Also several other XSS vectors because it’s a DOM insertion not a simple source reflection. Just a few will work like the one provided above.
By taking the value of “redir” parameter the code above makes possible to redirect the browser to another address, loading another document. If we use a site we control, it would be of no use to attack a target application, since we would be out of context.
Usually evaluation sinks make part of big and complex code so above we will see a very simple one: there are 3 variables, one for each major stock index: Nasdaq, Dow Jones and S&P 500. Let’s not consider that their values would come from a database in a real application, so they are not constantly changing.
The “market” object is created. After getting from URL the value of “index” parameter (to know which index to look for) we try to ensure it’s a string with toString() conversion (just a silly way to try to avoid the outcome). Then our code creates in the object “market” the property “index”, dynamically, with “eval” function. Finally, the current value of the queried index is displayed in the paragraph.
An attacker can simply XSS this by providing the JS code he/she wants to run:
Because that code will go straight to evaluation, it’s simple like that. In real world applications, most probably it will require passing some test or assignment according to code flow in order to reach the flawed point.
Other execution sinks besides “eval” are “setInterval” and “setTimeout” functions and template literals.
Those were the 3 sinks we should be aware of when looking for DOM-based XSS.