demo ctf 2026 — baby steps
event: Demo CTF 2026 · web · easy · 100 pts
Training fixture. Demo CTF 2026 is an invented event I host against myself. The challenge, the box, and the flag are mine; this writeup exists to keep the format — including the failed attempts — honest.
Description
baby steps — web, 100 pts
“Our new site is so secure even the crawlers behave.”
http://demo-ctf.local:9000/
A single static-looking page reading “nothing to see here.” No files attached, no parameters, no forms. Easy tier: the challenge is about looking where the site tells you not to look.
Thought process
Failed attempt 1 — brute force before reading
I pointed feroxbuster at the root with a common wordlist before doing
any manual enumeration. Ten minutes, a few thousand requests, one hit:
/robots.txt — which I had not read yet. Classic own goal: the scanner
found the map and I ignored it.
$ feroxbuster -u http://demo-ctf.local:9000/ -w common.txt -q
200 GET 21l 45w 402c http://demo-ctf.local:9000/robots.txt
# ... nothing else
Failed attempt 2 — taking the page at face value
After finally reading robots.txt (below) I fetched the disallowed path,
saw a page that said “flag is not here”, and briefly went back to
fuzzing for other paths. Cost: another few minutes. The page was lying by
omission — I had read the rendered text but not the source. On a static
challenge, view-source is not optional.
Solution
Two requests. First, the map the site hands you for free:
$ curl -s http://demo-ctf.local:9000/robots.txt
User-agent: *
Disallow: /s3cr3t-adm1n/
Disallow is an instruction to polite crawlers, not an access control —
the path serves 200 to anyone who asks. Asking, and reading the source
this time:
$ curl -s http://demo-ctf.local:9000/s3cr3t-adm1n/ | grep -io 'flag{[^}]*}'
flag{robots_txt_is_a_map_not_a_fence}
The rendered page says “flag is not here”; the HTML source carries the flag in a comment immediately under it.
Flag
Lessons
- Read
robots.txt(andsitemap.xml, and.well-known/) before reaching for a wordlist. The scanner is a supplement, not a substitute. - Rendered text is a suggestion; source is the truth. Grep every response
for the flag format early:
grep -io 'flag{[^}]*}'costs nothing. - For defenders:
Disallowdoes not protect anything. If a path must not be public, authenticate it — or better, don’t deploy it. - Next practice: same shape, harder tier — a disallowed path behind a referer/header check, to drill request malleation instead of plain curl.