"Cross-site scripting (XSS) is a type of computer security vulnerability typically found in web applications. XSS enables attackers to inject client-side scripts into web pages viewed by other users. A cross-site scripting vulnerability may be used by attackers to bypass access controls such as the same-origin policy. Cross-site scripting carried out on websites accounted for roughly 84% of all security vulnerabilities documented by Symantec as of 2007. Their effect may range from a petty nuisance to a significant security risk, depending on the sensitivity of the data handled by the vulnerable site and the nature of any security mitigation implemented by the site's owner." - Wikipedia article: Cross-Site Scripting
XSS is a problem that has been around for a very long time, and it’s still around. If you take a look at the 2017 OWASP Top 10 you’ll find that XSS is number 3. Clearly it isn’t going away any time soon, so lets talk about it! You’d be surprised how many popular web applications can have XSS vulnerabilities. *cough**cough*. They can be found by anyone *wink*. I mean anyone *nudge*…..*wink**wink**nudge**nudge*.
A quick note I’d like to add, there are a number of web application frameworks that will do their best to have XSS protection by default. For example, while developing this article I wrote a small Flask app to use as an example. By default, Flask will do it’s best to prevent XSS from executing. That’s awesome! There is one thing I’d like to point out however, do not rely on this to protect you from a whole range of attacks.
Just because your framework will try to prevent it, it doesn’t mean it will always work. By using the Markup feature of Flask, I was able to execute XSS again. In addition due to the logical configuration of your app, you can still cause this attack to work. See below.
With that out of the way, lets take a look at how XSS works. At it’s very core, XSS is about injecting code directly into a web page. This can occur anywhere that user input is taken. A search bar, comment box, etc. In our example, we have a web application called 'Name Taker' which will give you your name if you tell it.
So lets give it the name 'Nick' and see what happens?
Uh oh. That was unintended. This is the heart of what XSS is. Now lets focus on the two main types of XSS, Reflected vs. Persistent.
This is the least dangerous of the two, that being said, it can still be used to do bad things. The important thing to remember is that the injected script is not stored by the system. An example of this would be a search bar. After you have searched something, what you searched typically is forgotten (unless you’re Google in which it stays around forever). With this type of XSS attack, you can load the attack code directly into the link. For example, the following link will trigger XSS in our example web app.
How is it dangerous? Because you can still get a victim to fall for it, but it requires some social engineering. This is one of the reasons people tell you not to click suspicious links (don’t click suspicious links). Examples of attack vectors for this type of XSS would be through emails or websites that allow for links.
It is important to remember that this does not lift all of the blame off the owner of the vulnerability. If you could send someone a legitimate link to YouTube with this vulnerability, it is partially (And some would say entirely) YouTube’s fault. These links would have the legitimate domain name. Remember, the victim would still be going to the real website. Due to the lack of training many people have experienced they may think that just because it really is YouTube, they're safe.
This is the more dangerous type of XSS. This type is stored by the vulnerable system. A great example of this would be a comment box or a username. The reason it is more dangerous is because in some cases there is no need to social engineer a victim to click on a link. They may accidentally stumble across the attack code without even realizing it. And in some cases, the web app may broadcast your attack for you.
Let me give you an example. Let’s say you go to a social media site and insert some XSS attack code. From that point on, any user who (has JS running) goes to your site or views your post will fall victim to the attack.
One thing to consider if you are defending yourself from XSS is that an attacker may not want to leverage it right away. In my Name Taker example, the system will automatically run the code. With Persistent XSS we can wait for a later chance to exploit. There may be a location that nobody thought of that could fall victim to the attack.
The damage caused by XSS depends entirely on the web application and how it is configured. Depending on these factors you could steal a users cookie. Simply make a get request to a server you control with the cookie found by calling “document.cookie”. Keep in mind there are flags that can prevent this.
Hopefully you can see just how dangerous this attack can be. Of course, it can also be mitigated highly. The big difficulty is that it’s like playing wakamole. Every time you create a new way for your web app to show data, you are possibly opening an attack vector.
“Well Nick”, you may be saying to yourself, “I know what I’m going to do. My web app isn’t catering to aspiring film authors! I’ll just put a regex on my input that will filter out the script tag!”. That’s brilliant!! Let’s try that with our name taker example. If it sees the word “script” it will present a pop-up that says “Buzz Off Hacker”.
Well look at that! You did it! You saved the world from every Cross-Site Scripting attack! YAAAY!! Wait, what was that noise? Oh no!
So unfortunately things aren’t that easy. We managed to bypass that my filter by using a different tag. The code I used was the following.
Are there more ways to bypass XSS filters? Yes! In fact there are a ton and ever increasing due to the prevalence of HTML5. A great resource for these bypass’s is the OWASP page on XSS Filter Evasion
Now, sometimes it may not be as easy as copy and pasting. You will need to figure out if there is a filter and what the rules are. For example while working on this article I noticed that my example web app had trouble with XSS attack code that contained spaces (this is something I’ve run into multiple times now). A cute way to bypass this is to store a space from the screen itself. Notice the space between “Name” and “Taker”.
To truly mitigate the threat of XSS you will need to apply a list of filter rules that try to detect XSS.
Remember, XSS is a very common vulnerability. Anybody could find it in a big name application. *wink*