堆溢出的研究
根据我的下面文章的总结,其实堆溢出与格式串溢出特像,就是“一个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) |