Cross-site Scripting (XSS)
Cross-site Scripting (XSS)
<script>
Cross-Site Scripting, or XSS, is a vulnerability that would allow attackers to exploit the
interactions that other users have with an application. In short, it can allow us to impersonate
and perform actions as another user, steal information and in some cases, gain RCE.
The most common way of testing if XSS is present on a website is to call the Javascript alert
function. For example, the script tags of HTML can be used :<script>alert(1)</script>. The image
below shows an example of what would pop out.
How it Works
Browsers and websites allow users to interact with them and perform actions through
Javascript. XSS would work via injecting malicious Javascript code to execute on a user's
browser. Basically, scripting across the website.
There are 3 types of XSS:
1. 1.
Reflected XSS
2. 2.
Stored XSS
3. 3.
DOM Based XSS
Reflected XSS
Reflected XSS is the simplest form of the exploit. This occurs when a malicious script is reflected
off a web application and onto the victim's browser. This script is normally activated through a
link or action on the website and would be redirected to the next user.
Stored XSS is much more dangerous because it stores the script on the page itself and exploiting
every user that visits it. In the above example, XSS was used to steal information about a
directory that only the user could visit. In other cases, stuff like authorisation cookies or
passwords can be stolen by attackers.
DOM-Based XSS
DOM XSS arises when Javascript takes some input from a user-controlled source and processes
it insecurely.
Document Object Model (DOM) is a programming interface for web pages, defining the
structure of a document and how the document is accessed and manipulated. A website can
use Javascript to do something, but uses DOM to access the document and the relevant
elements. DOM is structured like a hiearchy tree, with a root element and other elements that
are children of the root node.
More can be read here:
https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Introduction
DOM XSS arises when data is passed to something called a sink, which is basically a function
that supports dynamic code execution. This can be a function like eval, for example. Malicious
Javascript code can be passed to this sink and allow for the execution of Javascript used to
hijack other accounts.
Here are some sinks that can be used for DOM XSS:
document.write()
document.writeln()
document.domain
element.innerHTML
element.outerHTML
element.insertAdjacentHTML
element.onevent
add()
after()
append()
animate()
insertAfter()
insertBefore()
before()
html()
prepend()
replaceAll()
replaceWith()
wrap()
wrapInner()
wrapAll()
has()
constructor()
init()
index()
jQuery.parseHTML()
$.parseHTML()
These functions are not limited to only XSS, but can also be used for other DOM exploits, such
as open redirection, through exploiting taint flow vulnerabilities.
There are methods to test the HTML and Javascript sinks that are within a website that require
the use of browser inspector tools, which would involve looking at how data is parsed by the
function. First, we would need to identify a potential source (input location) whereby our input
is processed via the sink. Then we can test them as follows:
• HTML Sinks
o Input HTML strings within a potentially vulnerable sink.
o Check the page source and try to find out string.
o Attempt ot break out of the HTML tags to execute our code.
• Javascript execution sinks
o Sometimes, we cannot see our input anywhere within the DOM, so we can't
search for it.
o Use the Javascript Debugger to determine whether and how our input is sent to
a sink.
o Add a break point and follow how the source's value is read, then track the
variables to see if they are passed to a sink.
o Once we have found the sink, attempt to execute malicious Javascript by
tweaking our payload.
Here's an example of exploiting DOM-based XSS:
Suppose we have this website that has a dashboard customised based on the username. The
username is encoded in the URL and used directly on the page.
<html>
<head>
<title>Custom Dashboard </title>
...
</head>
Main Dashboard for
<script>
var pos=document.URL.indexOf("context=")+8;
document.write(document.URL.substring(pos,document.URL.length));
</script>
...
</html>
We can see that the vulnerable sink used is document.write( ), and the source would be a
context parameter we pass to the website. We can then embed a malicious script in the URL like
this: http://example.com/dashboard.html#context=<script>alert(1)</script>.
A victim would then need to click this link. When the link is clicked and the browser starts
building the DOM of the page, the browser would use the URL provided (in this case, the
malcious link above) and run it. The malicious context parameter would then be extracted and
the HTML is updated to have our code. The browser then runs this code and calls the alert
function, thus making the XSS possible.
Payloads
XSS is a common vulnerablity and there are often measures to prevent it's execution. For
example, a website could restrict the usage of events or <script> tags to prevent users from
exploiting it. However, there are always ways to bypass this.
In basic cases, websites can allow for <script> tags to be used as input and allow for the
embedding of HTML directly on the page. However, if the website has a WAF that does not
allow this, we can brute force the possible tags possible.
Event attributes can be used in conjunction with tags to deliver the payload, such as onerror.
Again, this can be brute forced. A lot of XSS payloads out there are built to bypass WAF
detection and execute our payload. I normally use Portswigger's cheat sheet to find all the
possible tags and events for each browser.
HTML Event attributes allow events to trigger actions on a browser, like starting Javascript whne
a user clicks on an element. For example, using the <img src="x" onerror=alert(1)> payload
would attempt to render an image, which would always result in an error in this case. This
would trigger the alert(1) to happen.
https://portswigger.net/web-security/cross-site-scripting/cheat-sheet
There are loads of payload repositories out there, so I'm not going to make one here.
https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XSS%20Injection