现在的位置: 首页 > 综合 > 正文

ppstream溢出实况

2013年09月12日 ⁄ 综合 ⁄ 共 3111字 ⁄ 字号 评论关闭

        自从2007年元旦幻影爆出QQ的一个ActiveX插件漏洞后,第三方应用程序的ActiveX插件漏洞大量爆发。这里我选择了一个PPStream的ActiveX插件漏洞,以实例的方式重现整个调试过程。

    漏洞影响的版本是 PowerPlayer.dll 版本:2.0.1.3829,为了再现漏洞我下了一个PPStreamv1.0.4.730http://www.7703.com/soft/6/105/2007/03/7703_35839.html)。ID5EC7C511-CD0F-42E6-830C-1BD9882F3458的插件有漏洞,首先构造一个POC
<html>
<body>
<object id="ppc" classid="clsid:5EC7C511-CD0F-42E6-830C-1BD9882F3458"></object>
<script>
var buffer = '/x41';
while (buffer.length < 302)
buffer += '/x41';
buffer += 'ABCD';
 
ppc.Logo = buffer;
</script>
</body>
</html>
保存为poc.htm,IE访问后直接挂掉!OD附加IE后,再进行访问出现如图:
 

仔细观察不难看出[44434241]正是网页中的ABCD,堆栈中ESP=0012E128,而上一行是44434241,再根据状态栏中的违反访问,不难发现这是由于超长变量覆盖了RET地址,在执行ret后出现的景象,即典型的栈溢出!
    下面就要定位溢出点了,但是OD中反汇编窗口一片空白,因为EIP(44434241)指向的是一个无效地址,前一个EIP已经无法得知了!这里有四中方法可以定位:
1. 一般发生溢出都是由于strcpy等拷贝函数复制了超长局部变量产生的,所以可以分析strcpy函数的调用情况,找出可疑函数,后逐个下断点调试。这样的工作量很大,而且不一定可以成功。
2. 通过计算的方法得出:
int i;
   char(i%100+100);
   char(i/100+100);---------二次定位法!
这种方法思路很巧妙,但局限性太大。
3.在相应的栈内存中添加“内存写保护硬件断点”(要转到数据窗口添加),这种方法要注意,可能在断点内存处会发生多次写操作,所以要仔细分析!
4.这是我我经常用的一种方法。从堆栈中加以回溯,因为事发时ESP一下的数据部分并没有毁掉(不能覆盖太长,可以用二分法计算)。即问题函数的父/爷函数返回地址还在,这个方法很快!
 

图中0012E164的红色字清楚的说明了问题,所以地址73D47764的上一条call函数就是问题函数的父函数。
73D4775F下断点。重新加载OD,进入73D4775F,按F8,如果哪个函数执行后出错了,那个就是问题函数。可以进入问题函数探个究竟(如下图),按F8/F9直到026FF8D4 retn
问题非常明显,此时ESP0012E124)――>44434241,就是上面的ABCD。我们的分析完全正确。如果再F7一步就到了我的第一张图!
 

    下面就是具体的实现形式了,要根据不同的溢出情况而定。这里不具体说了,给出通用跳转指令的地址:win2k,winxp,win2003下的通用地址:
0x7FFA1571    pop pop ret
0x7FFA0EB7      push esp, ret
0x7FFA4512      jmp esp
0x7FFA54CD      jmp esp
0x7FFA9C1B      push esp, ret
0x7FFC0172      push esp, ret
只针对CN...
例:0x7ffa0eb7 在c里反过来写就是 /xb7/x0e/xfa/x7f
微软为了防止溢出,在函数返回前加了cookie保护,就是编程时的/GS开关,在XP中的IE就用了它。这个cookie也就是一个存在于ebp之上的一个数值,你要覆盖函数的返回地址,肯定要经过覆盖这个值,肯定会改变这个值的,所以只要返回的时候检测一下这个值是否被修改,即可判断是否有溢出情况出现,示意图如下:

|---------| | |
 | ....   | | |
|---------| | |
|被修改   |-- - <== 这里是cookie的值,可以看出,你要修改ebp,要修改返回地址的值,这个cookie的值也肯定要被修改.
|---------|
|被修改   |   <=== ebp指针的地址  
|---------|  
|0012E124 |     <===返回地址
|---------|  

现在问题明确了,怎么绕过这个检测值呢?方法有很多.
比如可以覆盖这个cookie的值,不过需要代码中有代码会从被我们覆盖的内存区域取出数据做指针的情况.中剩下的这些代码中没有这种代码.
再者因为这是个溢出,所以可以覆盖堆栈的任何地址,windows下异常处理机制也用到了栈,他们把异常处理的函数地址做成单链表保存在栈中,栈是我们可以覆盖的,我们可以用shellcode函数的地址来覆盖这个异常函数的地址,这样一来如果我们能使得程序出现异常,那么系统就会取出栈中异常函数的地址来处理异常,我们的shellcode也就可以执行了.
不过好在还有另外一种办法。

XPIE程序的栈地址是在00120000开始的地址到0012ffff结束,紧接着下一个段的地址是:00130000,OD查看这个段的属性.
 
 
可以看到访问的权限是R,也就是只读.
那么好办了,我们可以利用已有的栈溢出可覆盖地址的特性,如果可以覆盖这个只读的地址,肯定会产生一个内存访问错误,也就是一个异常,这样一来,我们就达到了产生异常的目的.
这样我们就可以在溢出后让shellcode直接得到运行权限。
    因为ie溢出在溢出之前是可以申请堆内存的,这样我们可以用javascript来申请大量的堆内存,全部填充0x90字符接shellcode这样的模式,然后用随便一个已经申请了的堆内存的地址(shellcode的地址)来覆盖整个堆栈,这样无论这个异常处理在什么地址,我们都可以用正确的内存地址(shellcode地址)覆盖它。这就是在IE类溢出中常用的Heap spraying(具体代码在ppstream.htm中),我把/41换成了/05,填充数量可以从图中算得:00130000-0012E124=1EDC(7900),保守点填充了10000。
"%u9090%u9090%uC033%u5050%u5050%u0BB8%uD505%uFF77%u00D0"
UNICODE形式的shellcode,这里主要是为了测试,弹出一个对话框!
 

在下图中可以看到我的shellcode的确在堆里。
 

ppstream1.htm是换了一个能执行计算器的shellcode(from:http://www.milw0rm.com/
 
后记
    因为这个漏洞出现在PowerPlayer.dll中,没有用种/gs的执行保护编译模式,所以也可以不用Heap spraying,用最传统的覆盖RET地址法,这里主要为了通用。
    ppstream.htm用的是硬编码的MessageBox,可能其它机器上不一样!ppstream1.htm可以通用。
       Shellcode编写这一块没涉及,但它可以写的东西太多了。从编码解码到绕过卡巴。
    这里的内容虽然很基础但也包含了一些自己的思考,我还有很多很多要学习的地方。这篇文章的参考资料太多了一并谢过。
 
调试环境Windows XP SP2+IE6.0OllyDBG.

抱歉!评论已关闭.