Challenge: DEAD VAULT · CTF: Zer0d4yh31st CTF · Category: Web · Difficulty: Medium
Summary
A Money Heist–themed Flask app hides a flag split into three fragments behind a server-side URL fetcher. The fetcher blacklists localhost and 127.0.0.1 by string match, so a DNS-based bypass (127.0.0.1.nip.io) reaches the internal API and a privileged file-read endpoint to collect all three fragments.
Solution
Step 1: Recon & guest login
The login page leaks credentials in a visible HTML comment: guest / guest123.
The /hints page (no auth required) reveals the attack map:
| Soul | Clue | Mechanism |
|---|---|---|
| Tokyo | “address begins with 127… path hidden inside itself” | SSRF to internal API |
| El Profesor | “machine confesses when you find its config” | /internal-api/config |
| Berlin | “token is the key, path is where stories end” | file read /flag.txt |
Step 2: SSRF blacklist bypass
/fetch blocks the strings localhost and 127.0.0.1. The service uses Python requests, which resolves DNS before connecting. 127.0.0.1.nip.io is not in the blocklist but resolves to 127.0.0.1, so the filter never fires.
| |
The internal Flask server runs on port 5000 (confirmed via PORT=5000 in /proc/self/environ).
Step 3: Collect all three fragments
| |
The .py extension is blocked by the file reader, but /flag.txt at the filesystem root is not. “Where stories end” = /flag.txt.
Combine: Zer0d4yh31st{d34d_ + m3n_t3ll_ + n0_t4l3s} = the flag.
Flag
| |
“Dead men tell no tales.”