$ cat writeup.md…
$ cat writeup.md…
broncoctf2026
Task: tutorial pwn with 4 stages, each reading via unbounded gets() into a stack buffer guarded by volatile sentinels. Solution: overwrite adjacent local sentinels to pass gates 1-3 (preserving a second sentinel at exactly 41), then classic ret2win in the treasure room using disassembly-derived physical offsets rather than source declaration order.
$ cat /etc/rate-limit
Rate limit reached (20 reads/hour per IP). Showing preview only — full content returns at the next hour roll-over.
Have you read the Pwntorial? Ready to graduate from baby pwns? This should do it. Three gates and a treasure room await your input.
A tutorial-style stack overflow chain. main() calls four functions in sequence:
gate1 -> gate2 -> gate3 -> treasure_room. Each reads input with unbounded
gets() into a stack buffer, and each gate checks one or two "sentinel" local
variables that we must corrupt to specific values. The final treasure_room is
a straightforward ret2win.
Remote: nc 0.cloud.chals.io 21543
ELF 64-bit x86-64, dynamically linked, not stripped
No PIE (base 0x400000)
No stack canary
Executable stack (-z execstack), NX off, RWX segments
Partial RELRO
Ubuntu 22.04, glibc 2.34
gcc proper.c -o proper -fno-stack-protector -z execstack -no-pie
win() at 0x40123b prints a message, runs system("/bin/cat flag.txt"), then
exit(0). No PIE and no canary make this pure offset arithmetic.
The source declaration order of locals is not the physical stack layout. GCC
reorders locals, so the offset from the buffer to each sentinel must be read from
the disassembly (objdump -d / gdb), not guessed from the C source. Every
gate offset below was derived from the actual rbp-0x... references.
int buffer[64]; volatile int gate = CLOSED; // 0 gets(buffer); // require gate != 0
Disassembly: buffer at rbp-0x110, gate at rbp-0x4.
Offset to gate = 0x110 - 0x4 = 0x10c = 268.
Payload: b"A"*268 + p32(1)
long buffer[64]; volatile int gate = CLOSED; // 0 volatile int baby_chicken = ALIVE; // 41 gets(buffer); // require baby_chicken == 41 AND gate != 0
...