badcat
Challenge
you've seen batcat, are you ready for badcat?
Login: badcat:b4788c115ea4eb42
Service: ssh -o "ProxyCommand=ncat --ssl %h %p" <instance>.play.gaslightctf.cooking -p 31337
The flag lives at /flag (mode -r-------- root:root). /bin/badcat is SUID root.
Reverse engineering
badcat (not stripped, full RELRO/canary/NX/PIE/FORTIFY) works like a cat:
- On startup it drops privileges:
seteuid(getuid()),setegid(getgid()). - Loops over arguments:
-→slurp(0): read up to 0xfff bytes from stdin, print them,close(fd 0).- arg ==
"/flag"(rodata0x2004): re-raise euid/egid to root,open("/flag", O_RDONLY|O_NOFOLLOW),read(fd, buf, 8), printpsst, here's a sneak peek: %s, then drop privileges again — the fd is never closed. - any other arg:
__realpath_chk()it, refuse paths resolving to/proc...or/dev..., thenopen()as the unprivileged user andslurp()the whole file.
So the root-privileged read is limited to the first 8 bytes of /flag.
Exploit: fd reuse via closed stdin
slurp(0) closes fd 0. The subsequent root-branch open("/flag") therefore
reuses the lowest free descriptor — fd 0 — pointing at /flag, offset 8
after the peek. A second - makes slurp(0) read from that root-open fd,
dumping the rest of the flag.
badcat - /flag - </dev/nullOutput:
psst, here's a sneak peek: gaslight
CTF{f3l1n3_d3scr1pt0r_m30www_ee8a0066610c}Flag
gaslightCTF{f3l1n3_d3scr1pt0r_m30www_ee8a0066610c}