Cross-Site Scripting (XSS)

In this chapter, we are going to learn about cross-site scripting (or also called XSS).

Type of vulnerability: Client-Side

Chances to find: Very high; XSS is ranked #3 in the “OWASP Top-10 Vulnerabilities

TL;DR: An XSS vulnerability allows an attacker to execute Javascript code in the browser of a victim. This enables an adversary to fully compromise the victim’s account by e.g. performing any action on the website that the user could perform as well.

What is cross-site scripting?

Cross-Site Scripting (XSS) attacks are a type of injection, in which malicious scripts are injected into otherwise benign and trusted websites. XSS attacks occur when an attacker uses a web application to send malicious code, generally in the form of a browser side script, to a different end-user. (src: OWASP)

Before we are diving deeper into the variations of XSS, let’s have a quick look at an example, how an XSS exploit looks like:

Example of an XSS payload triggering an XSS vulnerability

High-level overview of different XSS classes

Click on the links below to receive in-depth knowledge about every category.

Reflected cross-site scripting

Reflected XSS is occurring if user input is sent to the server within an HTTP request, which is then immediately printed out on the website in an insecure fashion.

A classic example would be a URL, which contains a parameter that can be altered by a user, where the input is mirrored and made visible.

Example URL: https://example.com/?user=Intigriti

Example output:

<span id="user">
  <b>Hi Intigriti</b>
</span>

If the underlying code responsible for creating the server response is not performing any type of sanitization and if the output is not properly encoded, an attacker could try to send a malicious request.

Malicious example URL: https://example.com/?user=%3Cscript%3Ealert(document.domain)%3C/script%3E

This would result in the following output:

<span id="user">
  <b>Hi <script>alert(document.domain)</script></b>
</span>

If an attacker would craft such a malicious example and send it to his victim, the victim would see an alert box popping up displaying the website’s domain. The attacker would need an additional trick to make the victim click on the URL (such as a phishing email).

Recommended Write-Ups:

Stored cross-site scripting

Stored XSS is occurring if a malicious Javascript payload, that has been previously stored on a system, is requested and delivered in an HTTP response by a victim at a later point in time.

Web applications offer a very diverse set of functionalities these days. A lot of them enable a user to store information that they would want to share with somebody else (e.g. think of social media platforms, the comment section on news websites, a forum, and many more).

Whenever a user sends in information for later use, the application needs to store that data somewhere (typically in a database). If stored information is then displayed to a victim in an insecure fashion, an attacker can make us of that.

Example URL: https://example.com/forum/thread/1?content=this%20is%20a%20test

Example output:

<span id="content">
  <b>This is a test</b>
</span>

If the underlying code responsible for creating the server response is not performing any type of sanitization and if the output is not properly encoded, an attacker could try to send a malicious request.

Malicious example URL: https://example.com/forum/thread/1?content=%3Cscript%3Eprint()%3C/script%3E

This would result in the following output:

<span id="content">
  <b><script>print()</script></b>
</span>

If an attacker would craft such a malicious example and send it to his victim, the victim would see a print window popping up within the browser. The attacker would need an additional trick to make the victim click on the URL (such as a phishing email).

Recommended Write-Ups:

DOM-based cross-site scripting

DOM-based XSS is occurring when client-side Javascript (running in the browser) is processing data coming from various sources in an insecure fashion, writing the malicious output in the DOM (document object model).

Example URL: https://example.com/?username=Intigriti

Example script running on the website (where a script reads the username provided within the URL):

<script>
  let username=document.URL.indexOf("username=")+9;
  let usernamePlaceholder=document.getElementById('usernamePlaceholder');
  usernamePlaceholder='Hi there,  '+username;
</script>

This would result in the following output:

<span id="username">
  <b>Hi there, Intigriti</b>
</span>

If the script running inside the browser is not performing any type of sanitization and if the output is not properly encoded, an attacker could try to send a malicious request.

Malicious example URL: https://example.com/?username=%3Cscript%3Edocument.write(%22test%22)%3C/script%3E

This would result in the following output:

<span id="username">
  <b>Hi there, <script>document.write("test")</script></b>
</span>

If an attacker would craft such a malicious example and send it to his victim, the victim would see a an empty blank page containing the string “test”. The attacker would need an additional trick to make the victim click on the URL (such as a phishing email).

Recommended Write-Ups:

Impact

Until now, we have only seen XSS payloads that are rather benign if a victim falls for them. What could an attacker potentially achieve by maliciously misusing an XSS vulnerability:

  • Install a key-logger to read every single button press on a given domain (e.g. to spy on a user’s password)

  • Act on the behalf of the victim on the website (e.g. post messages, update information)

  • Retrieve confidential data that is supposed to be only visible to the victim (e.g. PII data)

  • Change the website’s appearance in order to trick the victim into performing further unwanted actions

  • etc.

Further variants of cross-site scripting

Blind cross-site scripting

Blind XSS occurs when user input is stored in a in place that cannot be visited by an attacker. Given that situation, it’s hard to confirm that a vulnerability exists since the attacker doesn’t have access to the page where the payload might trigger (hence the word “blind”). A basic example would be a contact form, where you are able to send a message to employees of a company. While you can send payloads, you don’t know how the malicious input is going to be processed on the backend.

In order to help to get feedback for blind XSS attacks, you can use tools such as XSSHunter, which send a callback to a domain of your choice. Watch this video to learn how to set up XSSHunter.

Recommended write-ups:

Self-XSS

Self-XSS occurs when user input gets printed out to the web app in an insecure way, while you can only exploit the XSS vulnerability against yourself, or if you convince the victim to paste Javascript code in the browser’s console (which is considered phishing). As self-XSS findings are typically not in the scope of bug bounty programs, it is better to try chaining the vulnerability with an additional attack vector.

Recommended write-ups:

Time to practice!

Intigriti is continuously releasing new XSS challenges on our Twitter account. Make sure to participate in order to win swag and to show the world your skills!

Example of a previous XSS challenge:

Additional external challenges:

How to prevent cross-site scripting?

A short summary of the XSS prevention cheat sheet by OWASP:

  1. Never Insert Untrusted Data Except in Allowed Locations

  2. HTML Escape Before Inserting Untrusted Data into HTML Element Content

  3. Attribute Escape Before Inserting Untrusted Data into HTML Common Attributes

  4. JavaScript Escape Before Inserting Untrusted Data into JavaScript Data Values

  5. CSS Escape And Strictly Validate Before Inserting Untrusted Data into HTML Style Property Values

  6. URL Escape Before Inserting Untrusted Data into HTML URL Parameter Values

  7. Sanitize HTML Markup with a Library Designed for the Job

  8. Avoid JavaScript URL’s

Additional resources