ღ Miranda

CVE-2012-1876 IE mshtml.dll堆溢出分析

前言

CVE-2012-1876mshtml.dll上的一个堆溢出漏洞,在2012年Pwn2OwnVupen使用两个0day攻破win7+IE9,其中一个就是CVE-2012-1876,当时还利用了另一个漏洞,绕过了所有保护机制,这篇文章分析一下CVE-2012-1876这个漏洞。

poc

环境

系统: windows 7 x86 SP1
浏览器: IE8

由于win7上的mshtml.dll模块开启了ASLR,所以下面前后地址可能不同,在实际调试时也要注意。

调试分析

设置IE的堆页,直接附加IE运行poc.htmlwindbg并不会捕捉到异常,因为异常是在子进程中发生的,需要设置windbg支持子进程调试:

异常发生在mshtml!CTableColCalc::AdjustForCol+0x15处,往上追溯edi的来源:

edi来自于esi+18h,而这里没有esi的赋值,往上层查找,在IDA里查看交叉引用,发现这个函数仅被mshtml!CTableLayout::CalculateMinMax调用,看一下这个函数的声明:

CTableLayout类的一个类函数,第一个参数是this指针,第二个参数是CTableCalcInfo结构体指针。下面可以调试分析一下,在这个函数上下断点:

__thiscall是从右向左入栈的,所以[ebp+8]为第一个参数this指针,this指针为0x06addea8:

第一个为虚函数表的地址0x6c989960,这个对象就是<table>对象。

这里[ebx+54h]的值为1,就是poc中的span=1:

跳过中间一段,单步到下面的语句:

汇编:

EnsureSizeWorker的定义:

EnsureSizeWorker函数汇编如下:

调用时ediCTableLayout+0x90,这里调用了_HeapRealloc进行堆的分配,参数有两个,分配大小和存放返回的堆地址的空间,这里是esi,是CTableLayout+0x90+0xc:

看到这里是大小为0x70的堆。

获取span列数,最大为1000:

在这里的call下断点再运行,到我们在trigger中设置span后断下:

这里获取的列数为1000,就是在poc中设置的列数,接下去看汇编代码和详细注释:

回到最开始的问题,可以知道esi的来源:

调试分析一下,在6cc1f43b处的mov下断点,可以看到ecx的值每次增加1c,最终超过了堆的大小0x70造成了溢出:

由此可知,ecx每次增加1cAdjustForCol向堆中复制1c的数据,一共调用中有四次复制:

经过前面的分析,esi就是堆地址,大小为0x70,看看数据的来源ecxebx

至于数据的来源ecx,可以向前追溯,其实是CTreeNode对象的一个成员:

ecx其实就是with变量乘以100,左移4,加9,最后还会减1poc中设置的是41,即(41*100)<<4+9-1=0x10048。追溯一下ebx的来源,ebx来自于GetPixelWidth的返回值,这个值只是把width乘以了100:

调试看看与我们的推测是否符合:

poc.html中,我们重新设置了spanwidth,分别设置为最大的100042765,就会重新复制,但这次计数器会累加到1000,显然超过了0x70,造成了溢出,在第五次复制时溢出:

漏洞成因就是因为当改变了span后,仍然用原来span为1时分配的堆进行复制,导致了溢出。

发表评论

电子邮件地址不会被公开。