DOM based vulnerabilities
DOM is the web browser's hierarchical representation of the elements on the page. Javascript is used to manipulate the nodes and objects of the DOM as well as their properties. DOM manipulation in itself is not a problem in fact it is an integral part of how modern web browsers work but problem arises when javascript takes attacker controlled data known as source and passes it to dangerous functions known as sinks.
Source
A source is javascript property that accepts data that is potentially attacker controlled. eg: location.search
that reads input from query string, document.referrer
, document.cookie
and web messages.
Sinks
A sink is potentially dangerous javascript function or DOM object that can case undesirable effects if attacker controlled data is passed to it.eg: eval()
function is a sink because if processes argument that is passed to it as javascript. An example of HTML sink is document.body.innerHTML
because it potentially allows an attacker to inject malicious HTML and execute arbitary javascript.
DOM Based open redirection example
FUndamentally DOM based vulnerabilities arise when a website passes data from source to sink which processes the data in unsafe way. for example:
This is vulnerable to DOM based open redirection because location.hash.slice(1) extracts the fragment after the # in url and it that fragment starts with https it redirects the user to that url here we can simply do https://vulnerable-site.com#https://evil-user.net
to cause redirection.
DOM Based Open Redirection
Here, the regex between / /
matches anything starting with http as well as s? optionally allowing to match https as well, it also matches ://
escaping the forward slashes with backslashes and .+ matches one or more of any character the exec() method tests for a match in string after hash fragment in the url. It url exists it redirects to that website.
https://normal-site.com#https://evil-user.net
Here clicking to < Back
page the regex matches the location for occurence of url=https://anything/
and if exists sets the location.href to that url if condition ?
is true it sets return url to that page else :
it sets return url to /
.
https://normal-site.com/#url=https://evil-website.com
The following are main sinks which can lead to DOM based open redirection vulnerabilities
DOM XSS via web messages(eventlisteners and postMessage)
If a page handles incoming web messages in an unsafe way for example: by not verifying the origin of the incoming messages correctly in the event listener properties and functions that are called by the event listeners can potentially become sinks. An attacker can host a malicious iframe and use postMessage()
method to pass web messages data to the vulnerable event listeners. Here this event is listening for incoming messages and passing the data to eval()
funtion. The vulnerability here is that the event listener does not verify the origin of the message so during attack postMessage() method can specify target *
.
Above an attacker can simply host an iframe in his own site and use postMessage()
method to pass dangerous javascript function. <iframe src="//vulnerable-website" onload="this.contentWindow.postMessage('print()','*')">
Below a div container is set with id as ads
this page is accepting a postMessage
by setting event listener and the data which is sent using postMessage
is set as innerHTML within the div tag. Here the eventlistener is not verifying the origin meaning an attacker can host a malicious iframe in his own server pointing to this site when the iframe loads a postMessage()
function is set to pass a malicious javascript.
Now, when the victim visits the attacker's site the iframe will load and set the innerHTML to the malicious payload. If the victim is authenticated to the vulnerable application we can do anything on his account via javascript.
Second case
Here is another javascript code found within source of a web application.
To exploit this we can pass javascript url within the postMessage as <iframe src="https://0a3300a304d51442826115d700c100a5.web-security-academy.net/" onload="this.contentWindow.postMessage('javascript:print()//http:','*')">
Third Case
Here, an event listener is added to DOM of website. The event listener is listening for postMessage. An iframe element is created and assigned into iframe variable and ACMEplayer object is created with property element pointing to iframe created earlier a variable d is just initialized. The iframe element is appended into html body. The data received from postMessage() is parsed and set into variable d. Now the type of data received is checked if the type is page-load it scrolls the iframe into view using ACMEplayer.element.scrollIntoView(), if the data received is load-channel it sets the source attribute of the iframe to URL specified in d.url and if the data received is player-height-changed it adjusts the width and height of the iframe.
Since again above the origin is not chekced we can load an iframe pointing to this vulnerable site and send postMessage with type load-channel and url as javascript:print()
Last updated