From 4 sources to 3 sinks in DOM XSS - DomGoat level 1-10 (all levels) writeup
Feb 24, 2019 •
ctf
DomGoat is a DOM Security learning platform written by Lava Kumar Kupan (from Ironwasp security) with different levels, each level targetting on different sources and sinks.
Introduction
According to OWASP, DOM Based XSS is an XSS attack wherein the attack payload is executed as a result of modifying the DOM “environment” in the victim’s browser used by the original client side script, so that the client side code runs in an “unexpected” manner.
Now what does it mean? Before diving into an example, let’s look at what “sink” and “source” means:
Source:
Source is the location from which untrusted data is taken by the application (which can be controlled by user input) and passed on to the sink. There are 4 different categories of sources:
URL-based Sources |
Navigation-based Sources |
Communication Sources |
Storage Sources |
location |
window.name |
Ajax |
Cookies |
location.href |
document.referrer |
Web Sockets |
localStorage |
location.search |
|
Window Messaging |
SessionStorage |
location.pathname |
|
|
|
See an example for all the sources at DomGoat.
Sink:
Sinks are the places where untrusted data coming from the sources is actually getting executed resulting in DOM XSS. There are 3 different categories of sinks:
javaScript Execution Sinks |
HTML Execution Sinks |
javaScript URI Sinks |
eval() |
innerHTML() |
location |
setTimeout() |
outerHTML() |
location.href |
setInterval() |
document.write() |
location.replace() |
Function() |
|
location.assign() |
See an example for all the sinks at DomGoat.
Confused ? let’s take an example to illustrate:
In the above example, you can see that the javaScript is searching a GET parameter called “name” and it’s writing its value dynamically into the DOM using innerHTML. So its vulnerable to DOM xss: name=<svg/onload=alert(1)>
So here, location.href is the source (where the untrusted data is coming from) while innerHTML is the sink (where the payload actually executed).
DomGoat
DomGoat is a DOM Security learning platform written by Lava Kumar Kupan (from Ironwasp security) with different levels, each level targetting on different sources and sinks.
Level 1:
Sink: innerHTML
Source: location.hash
Solution: <svg/onload=alert(1)>
As always, level 1 starts with the easiest challenge. Here the location.hash
is read and specifically unescaped (since modern browsers by default will urlencode the location.hash to avoid DOM XSS) and inserted into the div using innerHTML.
Level 2:
If you look at the HTML source code, you can see the getPayloadParamValueFromUrl()
defined which extracts the value of the GET parameter named payload if any:
Sink: innerHTML
Source: document.referrer
Solution: https://domgo.at/cxss/example/1?payload=%3Csvg/onload=alert(1)%3E&sp=x#12345
Here, the payload from the document.referrer
is extracted and is written to the DOM using innerHTML. So you can visit the above URL first and then navigate to Example 2 link (payload param is set to actual XSS payload.)
Level 3:
Sink: innerHTML
Source: Ajax
Solution: <img src=xx onerror=alert(1)>
The response from the Ajax request (emulated with the user input) is parsed on the client side and is written directly to DOM with innerHTML.
Level 4:
Sink: innerHTML
Source: Web Sockets
Solution: <img src=xx onerror=alert(1)>
The web socket response (emulated with the user input) is parsed on the client side and is written directly to DOM with innerHTML.
Level 5:
Sink: innerHTML
Source: Post message
Solution: <img src=xx onerror=alert(1)>
The HTML5 post message data (emulated with the user input) is parsed and written directly to DOM with innerHTML.
Level 6:
Sink: innerHTML
Source: localStorage
Solution: <img src=xx onerror=alert(1)>
The localStorage data (emulated with the user input) is parsed and written directly to DOM with innerHTML.
Level 7:
Sink: innerHTML
Source: location.hash
Solution: #'%20onmouseover=alert(1)//
The location.hash is written directly into href
tag without sanitization and hence we can inject a single quote and break out of the attribtue context to inject our own event handlers.
Level 8:
Sink: innerHTML
Source: location.hash
Solution: #='%20onmouseover=alert(1)//
A small difference between this and level 7 is that what ever comes after the first =
character is written into the DOM as a part of href tag. Since we can’t inject new tags, we can use event handlers to solve the challenge.
Level 9:
Sink: innerHTML
Source: window.name + location.hash
Solution:
In this challenge, 2 values namely window.name and location.hash are combined (both can be attacker controlled) and is written to the DOM using innerHTML. In order to exploit this, we can host a custom HTML page with the above solution and visit it (which can control the window.name property and location.hash property together).
Level 10:
Sink: innerHTML
Source: window.name + user (GET parameter)
Solution:
Here, the value of GET parameter user
is extracted and written into the DOM along with the window.name property inside an href tag. Since we are dealing with URL context, we can inject javascript:
URI just like the last challenge.
Note
If you have a better way of solving the challenge (may be without any user interaction ?), do comment below, let’s share and learn :)
Anirudh Anand
Product Security ♥ | CTF - @teambi0s | Security Trainer - @7asecurity | certs - eWDP, OSCP, OSWE