Dusty Alleys
hackthebox
Task: Discover a hidden nginx vhost and exploit SSRF to exfiltrate the flag. Solution: Send an HTTP/1.0 request without Host header to /think, causing nginx to fall back to server_name as $host variable and leak the secret vhost domain, then use the /guardian SSRF endpoint to fetch /think with the flag injected in the Key header.
$ ls tags/ techniques/
$ cat /etc/rate-limit
Rate limit reached (20 reads/hour per IP). Showing preview only — full content returns at the next hour roll-over.
Dusty Alleys — HackTheBox
Description
"In the dark, dusty underground labyrinth, the survivors feel lost and their resolve weakens. Just as despair sets in, they notice a faint light: a dilapidated, rusty robot emitting feeble sparks. Hoping for answers, they decide to engage with it."
Target: http://154.57.164.81:32496
Architecture
Two-layer setup:
- nginx (port 80) — reverse proxy with two virtual host server blocks:
alley.$SECRET_ALLEY(default_server) — serves static files at/, proxies/alleyand/thinkto Node.jsguardian.$SECRET_ALLEY— proxies/guardianto Node.js
- Node.js Express (port 1337) — backend with three routes:
GET /alley— renders index pageGET /think— returns all received request headers as JSON (header reflection)GET /guardian— SSRF endpoint: takesquoteURL parameter, validates hostname ends with "localhost", fetches URL with FLAG inKeyheader
Key Source: routes/guardian.js
router.get("/guardian", async (req, res) => { const quote = req.query.quote; if (!quote) return res.render("guardian"); try { const location = new URL(quote); const direction = location.hostname; if (!direction.endsWith("localhost") && direction !== "localhost") return res.send("guardian", { error: "You are forbidden from talking with me." }); } catch (error) { return res.render("guardian", { error: "My brain circuits are mad." }); } try { let result = await node_fetch(quote, { method: "GET", headers: { Key: process.env.FLAG || "HTB{REDACTED}" }, }).then((res) => res.text()); res.set("Content-Type", "text/plain"); res.send(result); } catch (e) { return res.render("guardian", { error: "The words are lost in my circuits" }); } });
Key Source: nginx default.conf
...
$ grep --similar
Similar writeups
- [web][free]Proxy— hackthebox
- [web][Pro]Commentary— scarlet
- [web][Pro]Lab 160 — WikiForge — Nginx Alias Path Traversal— hackadvisor
- [web][Pro]Lab 209 — BuildForge — Path Traversal in Static File Serving— hackadvisor
- [web][free]Prison Pipeline— hackthebox_business_ctf_2024