A DOM-based XSS primer
Note: this post is a very simple primer aimed to help those who I know personally that have trouble chasing up DOM-based XSS findings in Burp Suite or similar due to the daunting nature of this vulnerability class.
Cross-site scripting comes in many different flavours. Persistent, reflected and DOM-based. This blog post acts as a primer to DOM-based cross-site scripting and how to effectively locate and exploit such vulnerabilities.
The "DOM" (Document Object Model), defined by W3 is:
an application programming interface (API) for valid HTML and well-formed XML documents. It defines the logical structure of documents and the way a document is accessed and manipulated.1
The above may not make much sense at first, but maybe a classic yet widely-found example may help:
<html> <div id="myname"> Welcome back, <span id="dynamicName"></span>. </div> <script> dynamicNameElement = document.getElementById("dynamicName"); dynamicNameElement.innerHTML = location.hash.split('#'); </script> </html>
Let's suppose that the above was a snippet of code from an application that shows a welcome message with your name every time you login. Let's suppose that the developers thought that it would be a good idea to do this client side instead of process is on the server side and reflect the name in the response HTML.
An innocent URL for this could look like
<html><head></head><body><div id="myname"> Welcome back, <span id="dynamicName">shubs</span>. </div> <script> dynamicNameElement = document.getElementById("dynamicName"); dynamicNameElement.innerHTML = location.hash.split('#'); </script> </body></html>
The extra tags such as
<body></body> are automatically inserted by the browser for parsing reasons, however what we are interested in is the
<span> element with the ID
dynamicName. It now has the contents
shubs within it.
dynamicNameElement.innerHTML = location.hash.split('#'); obtains the value after the
# in the URL. This value is then written to the property
dynamicNameElement.innerHTML. This property refers to the
span element in the code with the id
innerHTML property of an element. This is dangerous as innerHTML allows for the insertion of arbitrary HTML including scripts. Therefore, if I were to be malicious (for example), I would be able to insert arbitrary script through a URL such as
http://example.com/welcome"#<img src=x onerror="prompt(document.location)"/>".
The above URL would result in the following HTML being loaded in the DOM:
<html><head></head><body><div id="myname"> Welcome back, <span id="dynamicName"><img src="x" onerror="prompt(document.location)"></span>. </div> <script> dynamicNameElement = document.getElementById("dynamicName"); dynamicNameElement.innerHTML = location.hash.split('#'); </script> </body></html>
There you go. That's a primer in DOM based XSS. However, I have only covered a single method of acheiving DOM based XSS - through the innerHTML property.
There are quite a few more ways that this type of XSS is possible and for that I would highly recommend studying the following resources:
Good luck and contact me if you have a tricky potential DOM-based XSS somewhere that looks worthwhile checking out.