Reflected XSS: Advanced Exploitation Guide

Reflected XSS: Advanced Exploitation Guide

Cross-site scripting vulnerabilities are, by no doubt, one of the vulnerability types that’ll keep haunting applications for a long time. This seamless injection bug can often be further escalated to allow attackers to perform malicious actions on behalf of the victim, or even worse, on behalf of a vulnerable server-side component, from reading and changing account information, such as passwords or emails, to reaching internal-only resources and even reading local files.

In this article, we’ll look at a proven methodology to identify reflective XSS vulnerabilities while also diving deeper into some advanced exploitation methods.

Let’s dive in!

Cross-site scripting (XSS) is an injection vulnerability that allows attackers to inject malicious scripts into web pages viewed by other users. It works by exploiting insufficient input validation and a lack of encoding of any reflection of this user input, enabling attackers to insert HTML or JavaScript code that runs in the victims’ browsers upon visiting the compromised page.

Depending on the vulnerable component, XSS can occur on both the client-side and server-side. Client-side XSS happens solely in the victim’s web browser, and it allows attackers to take over the victim’s session.

Server-side XSS (or also referred to as blind XSS) occurs when the vulnerable component uses your unsanitized input and evaluates it within the DOM on the server-side, for instance, via a headless web browser. This enables attackers to use arbitrary JavaScript code to initiate outgoing requests on behalf of the server, and in severe cases, even read local files (depending on the headless web browser’s deployment configuration).

Now let’s take a look at the different types of XSS vulnerabilities.

Reflected XSS

Reflected XSS (or sometimes referred to as reflective XSS) occurs when malicious user input is injected through a request property (such as the URL path, fragment, query/body parameter, or HTTP header) and immediately reflected back to the user without proper sanitization.

The server processes the user input and includes it in the HTTP response without any encoding, causing the victim’s browser to execute the attacker’s script when they click a specially crafted link.

Stored XSS

Stored XSS (or sometimes referred to as persistent XSS) happens when an attacker’s malicious script gets saved in the target’s database, file system, or any other type of storage service (such as AWS S3). When other users later retrieve this stored data (for instance, viewing a comment section, public profile, or forum post), the malicious script executes in their browser.

Stored XSS is particularly dangerous as it can affect multiple victims without requiring them to click a specific link, unlike reflected XSS.

DOM-based XSS

DOM-based XSS occurs when unsafe JavaScript code processes user-controllable data (from a DOM source) and passes it to a DOM sink. This allows attackers to craft JavaScript payloads that would be evaluated by the vulnerable application.

DOM-based XSS is harder to spot as malicious user input is not immediately reflected into the HTTP response but rather passed to a DOM sink. The identification and exploitation of DOM-based XSS vulnerabilities will be discussed in an upcoming article.

Throughout this article, we will solely cover reflected (or reflective) and stored (persistent) XSS, as both of these types share the same characteristics.

What is self-XSS?

Self-XSS occurs when an attacker tricks a victim into executing malicious JavaScript in their own browser, typically by convincing them to paste code into the browser’s developer console or a text field on a legitimate website that’s only accessible to them (for instance, the address field on your profile).

While this technically causes script execution, most bug bounty programs and security researchers don’t consider self-XSS to pose a security risk because it requires the victim to actively perform the attack against themselves, which breaks the fundamental security principle that vulnerabilities should be exploitable without extensive social engineering.

Do note that there are cases where self-XSS vulnerabilities can be chained and further escalated, but this is a topic that we will cover more extensively in an upcoming article.

If you’re a beginner, this part is essential. It can help you save hours in determining whether you’ve found an XSS vulnerability or are dealing with a simple content injection. Let’s go through this 3-step methodology to help us identify a reflected or stored XSS vulnerability.

Step 1: Reflection

The first step is identifying where your input gets reflected in the application’s response. Insert a unique string (such as intigriti1337test) into various input fields, URL parameters, headers, or any other user-controllable data points.

Next, search for this string in the HTTP response. This helps you map out all reflection points and understand where your input ends up, which is crucial for determining whether exploitation is possible and what type of injection you’re dealing with.

Searching for cross-site scripting (XSS) reflection point

Finding hidden input parameters

Enumerating (hidden) parameters can help you discover all types of injection vulnerabilities, including XSS! In our detailed guide, we outlined 5 ways to discover hidden parameters. Read the article today.

https://www.intigriti.com/researchers/blog/hacking-tools/finding-hidden-input-parameters

Step 2: Injection

Once you’ve found a reflection point, test whether you can break out of the current context by injecting a simple HTML tag like intigriti1337test and observe how the application handles it.

For reflections in JavaScript context (anywhere inside the

Or:

Reflected XSS: Advanced Exploitation Guide

Both aforementioned payloads will work without needing to break out of any tag. This is the easiest scenario for beginners, as you can use virtually any HTML tag that supports JavaScript execution, including , , , or event handler attributes on self-closing tags.

Cross-site scripting (XSS) in HTML page (generic)

HTML attribute (inline HTML)

When your reflection appears inside an HTML attribute (like or ), you’ll need to break out of the attribute context first before injecting your payload.

You can either close the attribute with a quote, close the entire tag with >, and then inject a new malicious tag like ">, or stay within the same tag by adding an event handler like " onload=alert(1) x=".

The key is understanding which quote type (single or double) is used to wrap the attribute and whether the application filters any other characters that could block us from escaping the context.

Cross-site scripting (XSS) in an HTML attribute (inline HTML)

JavaScript block

When your input gets reflected inside