Knowledge about DOM-based and sinks
Knowledge about DOM-based and sinks: In our demonstration page, we have the following source code: • Knowledge • knowledge, sinks
In our demonstration page, we have the following source code:
Hello, guest!
var currentSearch = document.location.search; var searchParams = new URLSearchParams(currentSearch); /*** Document Sink ***/ var username = searchParams.get('name'); if (username !== null) { document.getElementById('p1').innerHTML = 'Hello, ' + username + '!'; } /*** Location Sink ***/ var redir = searchParams.get('redir'); if (redir !== null) { document.location = redir; } /*** Execution Sink ***/ var nasdaq = 'AAAA'; var dowjones = 'BBBB'; var sp500 = 'CCCC'; var market = []; var index = searchParams.get('index').toString(); eval('market.index=' + index); document.getElementById('p1').innerHTML = 'Current market index is ' + market.index + '.'; It has only one element, p1 a paragraph which is dynamically updated by the native JavaScript code in the only script block of the page.
There are no imports, no libraries.
All 3 cases are highlighted by means of 3 lines of comments to define where the snippet of code responsible for each one of them starts.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.
var currentSearch = document.location.search; var searchParams = new URLSearchParams(currentSearch);
In the Document Sink, the native JavaScript code updates the current document with data controlled or provided by attacker. It makes possible the insertion in the DOM of a whole new HTML tag with javascript code or a new attribute which might be an event handler with JS code.
/*** Document Sink ***/ var username = searchParams.get('name'); if (username !== null) { document.getElementById('p1').innerHTML = 'Hello, ' + username + '!'; }
```sql
```sql
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 Helloplus the content provided in the URL via name parameter.
That makes possible for an attacker to insert HTML code with:https://baddomain.xyz/tests/sinks.html?name=Important to note here is the fact that classic alert(1)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
Document Sink can appear in many ways: with innerHTML and outerHTML element properties, with document.write(), document.writeln() functions and any other way provided by JavaScript libraries to update an element or the document.Location Sink
In the Location Sink, the native JavaScript code updates the location of the document with data controlled or provided by attacker. In this way, it’s possible to use an interesting feature of modern browsers: the JavaScript pseudo-protocol.
/*** Location Sink ***/ var redir = searchParams.get('redir'); if (redir !== null) { document.location = redir; }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.
But by using the JavaScript pseudo-protocol, which is a way to run JavaScript code directly into the address bar of browsers, it’s possible to run code over the current document and its context.
https://baddomain.xyz/tests/sinks.html?redir=javascript:alert(1)In the past, data URI was used to replace that trick when “javascript” keyword was flagged by application filters and WAFs (Web Application Firewall). But now modern browsers provide a blank context for JS execution or don’t even allow the navigation anymore as a security measure.
In the Execution Sink, the native JavaScript code updates its own code flow with data controlled or provided by attacker.
/*** Execution Sink ***/ var nasdaq = 'AAAA'; var dowjones = 'BBBB'; var sp500 = 'CCCC'; var market = []; var index = searchParams.get('index').toString(); eval('market.index=' + index); document.getElementById('p1').innerHTML = 'Current market index is ' + market.index + '.';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.
```sql
```sql
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:
https://baddomain.xyz/tests/sinks.html?index=alert(1)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.