March 2023 - Intigriti's XSS Challenge - Author Writeup

GodsonGodson
2 min read

Due to time constrains, I was not able to deliver the write-up for my challenge when it ended, but plenty of people decided to share how they shared it. So, I highly recommend checking their write-ups for more detailed write up!

AI Generated Summary

Goal: Steal the admin’s flag (stored in a note) in spite of strict CSP and sanitization.

Recon & Source-Code Review

• You can create notes via the /note/:id?id=<id> endpoint; content is sanitized with DOMPurify.

• A special /debug/<author‑ID>/<note‑ID> endpoint returns raw note content in text/html only when the custom header mode: read is set—otherwise returns 404.

Client-Side Path Traversal to Access Debug Endpoint

• The frontend fetches /note/<id>, with id coming from URL parameters—and always includes the header mode: read.

• By using directory-traversal (e.g. ?id=../debug/<author‑ID>/<note‑ID>), you can force the browser to request the debug path with correct header even though the UI makes it impossible normally.

CSP Bypass via 404-based Script Injection

• A strict CSP prevents inline scripts and external untrusted sources.

• But the custom 404 page reflects paths unsanitized—with ability to inject <script src=...> tags into error message via path encoding tricks.

• By inserting a crafted path containing JavaScript in the error message (e.g. ending in /...;alert(...)), you can bypass CSP and cause script execution.

Exploitation via Browser Cache (bfcache / disk cache) — (Author Note: This part was inspired by ArkArk’s writeup)

• The debug response is fetched with text/html, which can be stored in browser cache (e.g. disk cache).

• By navigating (e.g. using window.open) to the path‐traversal note endpoint, then using history.back(), the previously fetched debug response is loaded without sanitization and exec context persists—triggering the injected script.

Final Attack Chain Overview

1. Submit a note with payload or trigger stored content indirectly via path traversal.

2. Trigger fetch to /debug/... through traversal path (with forward history), which stores the raw HTML response in cache.

3. Navigate back to cached view, where CSP bypass path injection executes JS—revealing the flag.


0
Subscribe to my newsletter

Read articles from Godson directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Godson
Godson

Hey there 👋 , I'm Godson - a 19-year-old dude who loves doing source-code reviews and web security 👨‍💻. I'm passionate about ensuring that web applications are secure 🔒 uncovering vulnerabilities 🐞 and keeping applications safe 🔐.