Turncoat's Treasure
umasscybersec
Task: a forum app exposed stored XSS, a wildcard Host-based proxy, and captain-only endpoints hidden behind nginx path filters. Solution: bypass the lowercase proxy block with uppercase Express routes, make the bot visit the XSS page, and leak the localhost-only treasure through CSS selector injection.
$ ls tags/ techniques/
Turncoat's Treasure — UMass Cybersecurity CTF
Description
Organizer description was not preserved in the local task files.
English summary: the challenge provided a forum-style web app plus hidden captain functionality. The goal was to pivot from a stored XSS in user profiles to an internal service, then exfiltrate a localhost-only flag despite same-origin and CORS restrictions.
Analysis
After downloading the assets and reviewing the source, the first useful bug appeared in the profile page template:
{{ p.content | safe }}
That made /user/:username a stored XSS sink. Any JavaScript placed in a forum post or profile content would execute when that profile page was rendered.
The next interesting components were the captain endpoints:
/call-captain/treasure
At first glance they looked unreachable because nginx explicitly blocked those lowercase paths. However, the deployment also used a wildcard subdomain proxy that routed requests by Host. By sending a host like 10.128.6.2.<instancehost>, traffic could be forwarded to the internal captain service.
The key bypass was a mismatch between the reverse proxy and the backend:
- nginx location matching was case-sensitive for the blocking rule.
- Express routing was case-insensitive by default.
That meant /CALL-CAPTAIN was not caught by nginx's lowercase deny rule, but Express still treated it as /call-captain and served the captain logic. The same applied to /TREASURE, but the captain service itself still limited /treasure to localhost, so an extra pivot was required.
This naturally suggested using the bot. By requesting:
GET /CALL-CAPTAIN?endpoint=/user/<attacker_username> Host: 10.128.6.2.<instancehost>
the captain bot was convinced to visit our stored-XSS profile page from inside the internal network context.
...
Permission denied (requires auth)
Sign in to read this free writeup
This writeup is free — just sign in with GitHub to read it.
$ssh [email protected]