CVE-2011-0073浅析-firefox释放重引用漏洞

来源:互联网 发布:unity3d webgl 编辑:程序博客网 时间:2024/06/05 17:04

本文转载自对CVE-2011-0073的分析
确保XP SP3上安装了firefox(3.6.16)和windbg(设置好符号表)。用windbg附加firefox,打开POC后程序被断下。
(firefox3.6.16可以在《漏洞战争》的配套资料中找到,原文提供了POC附件)
这里写图片描述
查看函数调用栈。
这里写图片描述
可以看到最近的一次函数调用的返回地址是1046659e,使用命令!address 0x1046659e查看这个模块所属的地址。
这里写图片描述
可见这个地址属于模块xul.dll,用IDA Pro对这个文件进行反汇编之后,跳转到地址1046659e处查看。
这里写图片描述
显然程序的控制流是在执行call dword ptr [ecx+70h]时转向了地址0x7c34e7ba,从而触发了内存访问异常。根据C++成员函数this指针调用约定,可以推测此处的call指令应该调用的是某个对象的方法。ecx寄存器中保存着虚函数表的基地址,eax寄存器中保存着这个对象的地址。查看ecx和eax可以看到其中的内容都是一些很奇怪的数据。
这里写图片描述
根据函数的控制流图来看,eax中的的值来源于esi,而后者的值即为函数的参数。
这里写图片描述
由于异常是在该函数内部执行指令call dword ptr [ecx+70h]时触发的,所以可以用IDA Pro将该函数重命名为FireHere。根据Windbg显示的call stack,上一层函数调用的返回地址为0x10688447,但是跳转到该地址查看,可以发现此处调用的不是FireHere。
这里写图片描述
当前windbg没有获得正确的call stack信息,所以通过查看当前栈的信息来手动分析。
这里写图片描述
所有形如0x104XXXXX的地址都可以看作是函数的返回地址。
这里写图片描述
这里写图片描述
距离0x1046659e最近的一个函数返回地址为0x104a9484,跳转过去。
这里写图片描述
根据调用栈中的信息还可以判断,在执行0x104a947f处的call FireHere指令时,压栈的参数eax的值为0x03087060。
这里写图片描述
在偏移8字节的地方看到了可疑地址0x12001000,那么可以模拟一下在FireHere中发生悲剧的整个过程。
这里写图片描述
上文已经分析过,程序在调用FireHere时压入的参数即eax的值为0x03087060,它来源于调用函数sub_104a9473时传入的参数。再次回顾栈中的数据,可以确定这个参数是0320c580。查看其偏移0x1c字节的数据。
这里写图片描述
[0320c580+1c]等于0,但是根据程序的控制流来判断,只有当这个值不为0的话程序才会把这个值压栈并且调用函数FireHere。那么只有一种可能—在sub_104a9473中,[0320c580+1c]的值会被改写。为了判断它在何处被改写,可以下内存访问断点。
这里写图片描述
在0x106f0e1b处断下,而这个地址在函数sub_106f0df8内,用IDA Pro查看这个函数的控制流图。
这里写图片描述
可以看到loc_106f0e17对内存数据进行了清零。
这里写图片描述
函数先以这个值为参数调用FireHere,随后又以其为参数调用sub_10466536。
这里写图片描述
我在分析的时候发现打开POC网页不会出现异常,异常反而是在关闭POC网页时发生的。所以,猜想这个函数是在网页关闭时才调用的。为了分析清楚程序在执行过程中调用FireHere函数的次数以及调用FireHere和释放内存之间的先后顺序,设置下面的断点。

bp 104665A6 ".echo leave FireHere;gc"bp 1046657E ".echo enter FireHere;gc"bp 1046658D ".echo loc_1046658D hit;gc"bp 1046659E ".echo loc_1046659E hit;gc"bp 106F0E12 ".echo free memory;reax;gc"

这里写图片描述
这里写图片描述
从函数FireHere的流程图可以看到,循环执行的次数取决于0x104665a3和0x10466588这两处判断。
这里写图片描述
可以设置以下断点并打印一些信息。

bp 1046659E ".echo value of 0xBBBBBBBB+8 in the entry of loc_1046659E;dd esi+8 l1;gc"bp 1046657E ".echo value of 0xBBBBBBBB+8 in the entry of FireHere;dd poi(esp+8)+8 l1;gc"

这里写图片描述
在0xBBBBBBBB内存被释放后,[0xBBBBBBBB+8]被改写为0x12001000,于是程序的控制流会跳转到loc_10466583中,而[0xBBBBBBBB+8 ]+8=0x12001000+8=0x12001008,可以看到0x12001008地址上的值也不为0,于是程序的控制流会继续向下执行,最终触发异常。
这里写图片描述
Q: 被释放了的内存为什么会被程序引用?
A: 在地址为0xBBBBBBBB这块内存被释放之后, 地址为0xBBBBBBBB+8的内存单元中被写入了攻击者可控的值0x12001000。由于这个值不为0,导致在函数FireHere内部的循环中会再次引用已释放内存单元[0xBBBBBBBB+8]中的数据。
Q: 为什么引用被释放的内存会触发漏洞?
A: 根据程序对内存单元[0xBBBBBBBB+8]以及内存单元[[0xBBBBBBBB+8]]中数据的使用方式来看,内存单元[0xBBBBBBBB+8]中保存的是一个对象指针,内存单元[[0xBBBBBBBB+8]]中保存的是该对象的虚函数表指针。程序误将从[0xBBBBBBBB+8]读取的值0x12001000作为对象指针,并从地址为0x12001000的内存单元上读取了由漏洞利用Javascript代码写入的攻击者可控数据0x12001000作为虚函数表指针,当执行指令call dword ptr[ecx+70h]调用对象的成员函数时就会跳转到内存单元[0x12001000+70h]中保存的攻击者可控的地址0x7c34e7ba上执行任意代码。
这个漏洞的exploit为了绕过ASLR+DEP,使用从firefox加载的用于支持Java的msvcr71.dll中选取指令序列作为ROP Gadgets。由于这个DLL是一个非ASLR模块,所以其指令地址是固定的,0x7c34e7ba就是该DLL中一个作为ROP Gadgets指令序列的起始地址。但是在没有安装Java的机器上firefox不会加载msvcr71.dll,所以在这里会触发内存访问异常。

0 0
原创粉丝点击