Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1395454
  • 博文数量: 343
  • 博客积分: 13098
  • 博客等级: 上将
  • 技术积分: 2862
  • 用 户 组: 普通用户
  • 注册时间: 2005-07-06 00:35
文章存档

2012年(131)

2011年(31)

2010年(53)

2009年(23)

2008年(62)

2007年(2)

2006年(36)

2005年(5)

分类: LINUX

2008-06-01 13:22:18

堆溢出的研究

根据我的下面文章的总结,其实堆溢出与格式串溢出特像,就是“一个format strings 
的bug可以使往任何数据写到任何地方。作者把它称为write-anything-anywhere权限”。 
  现在堆溢出的研究有点升温,暴露出来的堆溢出漏洞也越来越多,所以就有必要研 
究有效的堆溢出攻击方法了。由于堆溢出只是溢出的一种形式,原理已经介绍得比较 
多,也比较简单,所以就不再做这方面的介绍。 
  一、堆溢出后的后果; 
  现在的系统管理堆,为了查询的高效快速,一般都使用的双向链表结构。我们来看 
双向链表管理的时候的删除操作。*a,*b,*p1,*p2,*c,*d都是指针,考虑双向链表, 
a,b--->p1,p2--->c,d,其中由双向链表有*b=p1,*p1=a,*p2=c。如果是空闲内存链表, 
那么申请使用p1、p2指向的内存,或者如果是使用内存链表,释放p1、p2指向的内存, 
都会从这个链表中删除p1,p2。删除后的链表是a,b--->c,d,应该有内存改写操作: 
*b=c,*c=a。这时代码是经过链表检索从a,b得到的p1,p2,一般为了高效等就不会记忆 
a,b,因为双向链表就是为了从一个结点可以方便的得到上级和下级结点。所以那两条 
内存操作都将会转换成p1、p2相关的操作。根据前面得到的信息,经过简单的代换就可 
以得到我们需要的代码: 

*b=p1,*p1=a,*p2=c,b=a+1 
*b=c--->*(a+1)=c--->*(*p1+1)=*p2 
*c=a--->*(*p2)=*p1 
两次指针,可能看起来不是很习惯,再把*p1记成p1,*p2记成p2,那么就有: 
  *p2=p1 
  *(p1+1)=p2 
这就是堆溢出后导致的两个写内存操作,以后考虑堆溢出,不考虑细节的话基本上就可 
以用这两条代码代替。这时的p1、p2已经不是指那链表的位置了,而是指里面的内容。 
  二、利用。 
  要利用堆溢出,就考虑上面总结的两条代码的利用就是了。 
  1、改写内存参数,直接利用。可以改写重要变量,还有一个字符串的长度,格式 
串等,让起改写后再产生别的溢出等。这要改写一般只能改写数据段里面的东西,因为 
这位置相对固定并且可写。 
  2、改写函数指针性质的调用入口等。这个要写远程通用程序的难点还是shellcode 
的定位问题,只要有一个定位shellcode的办法,基本上就可以有一种堆溢出的利用办 
法。 
  (1)、unix等系统下面的s位程序的本地溢出。这个应该算比较简单好利用的一个 
应用了。shellcode通过环境块等传递,就可以比较精确的找到shellcode的位置。这样 
只需要改写一个函数指针内容,让其指向shellcode就可以了。 
  (2)、可以设置对一些可用于传递的shellcode域的读写断点,发现如果上面两条 
指令执行完后有如: 
      lea ebx,[ebp+0xxx] 
      push ebx 
      call dword ptr [0xxxxxxxxx] 
这样的代码,并且那ebx指向可传递shellcode的域,就能方便的利用,这样两个指针就 
可以分别选取0xxxxxxxxx和一个具有jmp ebx功能的地址。注意可能会要考虑前面两条 
指令或者那链表操作时候可能发生的异常。 
  (3)、利用p1、p2自身信息定位。 
  能够覆盖p1、p2,一般p1、p2前面会有一段空间能够控制,如果覆盖的长度可以控 
制。可以考虑保留p2的高位,改写其低位让起指向shellcode。这个要注意这时 
shllcode的前面4字节会被调用函数入口地址覆盖,所以不是所有会调用的函数入口都 
可以用。 
  (4)、利用SEH指针。 
  其实那双向链表经常是a,b--->p1,p2--->a,b的形式,所以把SEH链首fs:0,位置一 
般在ds:7ffxxxxx,同一系统比较固定覆盖,然后利用p2原来的值。这个有很多问题,跳 
到p1后,p1不是可控制代码,还有系统的SEH处理程序会检测fs:0首指针,如果不是指 
向堆栈位置,拒绝执行。主要是这个思路看能不能有别的办法。 
这个又考虑了覆盖fs:0首指针的低字节,这样异常结构链表位置就发生了变化,如果指 
向的另一块堆栈位置能够控制,就可以利用伪造异常链表的办法获得控制。其实单字节 
的溢出覆盖ebp低字节的利用原理也是差不多。而堆栈里面,往往会有动态BUFF拷贝过 
去的数据可以控制,所以这个要求也是容易办到。现在确定的是这个指针的位置不是固 
定的,有一定的变化范围。可能是0x7ff93000 、0x7ff9b000这样的值,但变化不是多 
大。 
  (5)、改写PEB指针,跳转到ret 0xxxxx这样的指令处,通过改变堆栈指针的办法, 
利用堆栈里面的可控制数据得到控制。 
  三、实际应用例子。.asp的分块编码堆溢出,其实这个漏洞不应该叫分块编码漏 
洞,因为漏洞原因不在于分块编码。 
  上面(2)、(3) 基本上都是可行的,但因为.asp的特殊之处,又使得上面的 
(2)、(3)对于这个漏洞不好使用。 
  1、对于(2),由于.asp的那段溢出没安装好异常处理程序,所以在那链表结构的 
处理过程中一般会发生异常,从而程序结束。如果精心构造覆盖p1、p2和用于链表处理 
的标记、长度的数据,可以不会发生异常,但处理完后马上又被别的不容易控制的数据 
覆盖,再次导致异常。 
这个现在在win2000+sp2的wam.dll里面找到一处可以利用的代码,但只能是下次重新连 
接才能得到控制。 
2、对于(3),由于申请的0字节内存,加上内存管理的8字节对齐,可以得到8个字 
节,再除去两条代码写内存浪费4字节,只剩下4字节,所以基本上不能用。利用另一个 
方式,可以申请大量内存,但这时只能是覆盖0xc000字节(问题在这),因为内存管理 
的8字节对齐,不可能只覆盖p2的低字节。 
3、对于(4),已经写出利用程序。 
4、对于(5),显然是可利用的,并且可能会写得比较通用。现在需要的是找一个通用 
的指针位置,就是没有语言版本、sp包的问题,所有的都通用。否则就需要有版本参 
数。 
外面发布的代码。基本上都是利用覆盖一个异常处理句柄入口地址(有版本问题),再 
加上猜测的shellcode地址,所以通用性大打折扣。其实一般堆溢出,利用上面的 
(2)、(3)还是可以做得比较通用的。 
WINDOWS系统的数据结构PEB总是映射到 0x7ffdf000,其偏移0x20就是一个函数指 
针,所以就有版本无关的一个指针位置0x7ffdf020。覆盖这个指针shellcode得到控制 
后需要恢复,因为很多调用要用到这个指针。这个调用的函数地址是ntdll.dll的 
RtlEnterCriticalSection。
阅读(1640) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~