Why GOT is not printed clearly when using printf

TL;DR

32bit 워게임 프로그램에서 GOT를 출력하고자 했을 때 4바이트가 출력되지 않고 그 이상의 값이 출력되었다. 그 이유는 leak할 때 사용한 printf 함수는 null byte를 만나기 전까지 출력하기 때문이다.

Why GOT is not printed clearly when using printf

printf를 사용하여 GOT를 print(leak)할 때 명확하게 되지 않는 이유

1
2
3
4
5
payload = b''
payload += b'A' * (0x2c+0x4)
payload += p32(e.plt['printf'])
payload += p32(e.sym['main'])
payload += p32(e.got['printf'])

32bit 워게임 문제를 풀다가 rop를 해야하는 상황이 있었다. libc system 함수 실제 주소를 구하기 위해 printf@got를 leak하려고 했는데 4바이트 이상의 바이트가 아래와 같이 출력되었다.

1
0\x0f\xf7М\xc7\xf7\x96\x8`\xf1\xc1\xf7\x908\xc7\xf7\xc0p\xc3\xf7

atoi@got는 깔끔하게 4바이트가 출력되었는데 printf@got는 4바이트 이상의 문자열이 출력되는 것이 이상하다고 생각되어서 디버깅을 해보았다.

1
2
3
4
5
6
7
8
9
10
11
gef> der $_got()
0x8049ffc│+0x0000: add BYTE PTR [eax], al
0x804a000│+0x0004: 0x8049f14 → <_DYNAMIC+0> add DWORD PTR [eax], eax
0x804a004│+0x0008: 0xf7f0ea20 → 0x00000000
0x804a008│+0x000c: 0xf7eebc00 → endbr32
0x804a00c│+0x0010: 0xf7c50f30 → <printf+0> endbr32
0x804a010│+0x0014: 0xf7c79cd0 → <getchar+0> endbr32
0x804a014│+0x0018: 0x8048396 → <__gmon_start__@plt+6> push 0x10
0x804a018│+0x001c: 0xf7c1f160 → <__libc_start_main+0> endbr32
0x804a01c│+0x0020: 0xf7c73890 → <setvbuf+0> endbr32
0x804a020│+0x0024: 0xf7c370c0 → <atoi+0> endbr32

0x804a00c 주소를 출력하면 0xf7c50f30가 깔끔하게 print(leak) 될 줄 알았다.

1
2
gef> print-format -l 40 --bitlen 8 --lang py 0x804a00c
buf = [0x30, 0xf, 0xc5, 0xf7, 0xd0, 0x9c, 0xc7, 0xf7, 0x96, 0x83, 0x4, 0x8, 0x60, 0xf1, 0xc1, 0xf7, 0x90, 0x38, 0xc7, 0xf7, 0xc0, 0x70, 0xc3, 0xf7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]
1
2
3
>>> buf = [0x30, 0xf, 0xc5, 0xf7, 0xd0, 0x9c, 0xc7, 0xf7, 0x96, 0x83, 0x4, 0x8, 0x60, 0xf1, 0xc1, 0xf7, 0x90, 0x38, 0xc7, 0xf7, 0xc0, 0x70, 0xc3, 0xf7]
>>> bytes(buf)
b'0\x0f\xc5\xf7\xd0\x9c\xc7\xf7\x96\x83\x04\x08`\xf1\xc1\xf7\x908\xc7\xf7\xc0p\xc3\xf7'

하지만 내가 함수 주소 leak하는 코드를 printf 함수를 이용했기 때문에 null byte까지 출력하는 printf 함수 특성에 의해 4바이트 이상이 출력이 된다.

atoi@got 같은 경우에는 바로 뒤가 null byte였기 때문에 4바이트가 깔끔하게 출력된 것이었다.