您的位置:首页 > 其它

转载CVE-2013-2551利用技巧分析

2013-11-17 10:11 495 查看














CVE-2013-2551利用技巧分析

转载自:http://hi.baidu.com/4b5f5f4b/item/33d5c21e33ed12181994ec6c

北欧知名网络军火商VUPEN近日发表博文公布了其在PWN2OWN上,搞掂IE10+WIN8所使用的漏洞原理及高级利用技巧。之前对WIN8系统新加入的诸如HiASLR、v-table Guard等内存防护机制有所耳闻,一直拭目以待业内有人能公开相应的绕过技术。VUPEN虽然早在去年就声称已经IE10+WIN8下的完美漏洞利用,但一直捂到现在才向世人披露技术细节。
 根据VUPEN的文章来看,这个漏洞是由于负责VML解析的模块VGX.DLL,在处理<v:stroke>标签的dashstyle.array.length属性时,没有对传入的参数进行完备验证而导致整数溢出。攻击者利用这个漏洞能够对任意地址进行读写操作——通过读取敏感内存信息、改写对象虚表,就能够完美绕过重重内存防护机制实现任意代码执行。值得说明的是IE10在默认情况下是不支持VML的,但通过在HTML中加入有关对文档模式的声明,可以使IE10正常解析VML标签。关于浏览器文档模式的说明文档,通过在HTML页面<HEAD>标签下加入以下代码,可以使IE10支持VML
<head>

<meta http-equiv="x-ua-compatible" content="IE=EmulateIE9" >

</head>

VUPEN出品的文章绝对是上等的干货,像我这样内功还不到火候的初学者反来复去读上好几遍仍是一头雾水。于是根据VUPEN博文中提供的信息构造了POC,windbging一番才觉得头脑清爽了一些,隧撰此文已备忘。

一、漏洞成因

VML标签<v:stroke>有一个属性dashstyle,使用JS语句读取dashstyle属性的值会使函数COAStroke::get_dashstyle被调用。该函数首先会判断当前COAStroke对象中是否有类型为COALineDashStyle的成员变量,如果没有则创建之。COALineDashStyle类型有一成员函数get_array,返回一COALineDashStyleArray类型的对象。COALineDashStyleArray对象有以下成员函数:



设置或者读取dashstyle.array.length属性时,对应的put_length或get_length函数就会被调用;利用数组下标访问dash.array属性时,对应的put_item或get_item函数就会被调用。

使用JS语句对dashstyle属性赋值时,例如:stroke.dashstyle = "1 2 3 4",函数vgx!ParseDashStyle会被调用,将将控制流转向_MsoFCreateArray函数来创建一个ORG数组。在_MsoFCreateArray中调用_MsoFInitPx函数根据数组成员个数来、进行内存分配,每个数组成员占四字节内存所以ORG数组的缓冲区大小为数组成员个数 X 4(byte)。在对dashstyle.array.length属性赋值时,数组成员的个数会改变,在put_length函数中会根据新设置的值来重新为ORG数组成分配内存。漏洞相关代码如下:









漏洞成因就在于put_length函数判断当前长度current_length和desired_length长度时,使用跳转指令是用于判断有符号数的jge指令,而数组长度是一个unsiged int类型的变量

.text:4242D108           cmp     eax, esi                          ;比较当前长度和预期长度的大小

.text:4242D10A           jge       short loc_4242D161     ;如果当前长度大于预期长度,则跳转到loc_4242d161处执行

因此当传入desired_length的值为有符号数0xFFFFFFFF时,会导致在执行以下指令时发生整数溢出,数组的长度被改写为0xFFFF=65535,但对应的内存却没有被分配。

.text:4241B8ED           sub     [esi], bx                           ;current_length - (current_length - desired_length) = desired_length

之后通过下标访问数组就可以实现任意地址内存读写!要想成功触发漏洞,须得使用JS将dashstyle.array.length的值设置为0xFFFFFFFF,但是如果直接使用如下语句
dashstyle.array.length = 0xFFFFFFFF
会提示错误有"溢出"发生,后来尝试将0xFFFFFFFF改为(0 - 1)就能够成功触发漏洞了。

二、信息i泄漏
VUPEN博文中第四部分介绍了如何利用这个漏洞来泄漏攻击者可控的数据地址。VML DOM对象的_vgRuntimeStyle属性由COARuntimeStyle类型负责处理,该类有两个成员函数put_marginLeft和get_marginLeft。使用JS语句设置或者读取_vgRuntimeStyle.marginLeft属性时,对应的put_marginLeft或者get_marginLeft函数就会被调用。如果是第一次访问marginLeft属性,那么在put_marginLeft函数中会调用CVMLShape::GetRTSInfo->CParserTag::GetRTSInfo来创建一个CRuntimeStyleInfo类型对象,该对象大小为0xAC,对marginLeft属性的值对应的字符串指针就保存在这块内存偏移0x58的内存单元中。同样get_marginLeft函数在读取marginLeft属性时,也是通过访问这个偏移0x58位置上的字符串指针来完成。



所以如果事先给marginLeft属性赋予攻击者可控的数据,如ROP+SHELLCODE啥的,再借助这个漏洞读取到CRuntimeStyleInfo对象内存偏移0x58上的指针,就可以获得攻击者可控数据在内存中的地址。ORG数组缓冲区大小由攻击者可控,CRuntimeStyleInfo大小为固定0xAC字节(实际分配0xB0),若想通过数组越界访问某个CRuntimeStyleInfo对象偏移0x58处的内存,在很多exp中可以看到的做法可通过以下三步实现。

1、在内存中连续创建CRuntimeStyleInfo对象



2、间隔释放之前创建的CRuntimeStyleInfo对象



3、精心构造dashstyle的属性,使ORG数组缓冲区大小为0xB0字节,以便这块缓冲区就能够和某个CRuntimeStyleInfo相毗邻



但是在W8下由于加入了HiASLR内存保护机制,使得从堆上分配的内存地址具有更强的随机性,尝试使用以下JS代码连续创建CRuntimeStyleInfo对象,但是可以看到分配的内存块并不连续:
for(var i=0; i<0x400; i++){

       var runtimeStyle              = document.getElementById("rect" + i.toString())._vgRuntimeStyle

     runtimeStyle.marginLeft      = unescape("TTWILLYOUMARRYME")

 }
在windbg中下断点:

 vgx!CParserTag::GetRTSInfo+0x1a ".printf \"[*]memory block:0x%08x\",@eax;.echo;gc",之后可以看到windbg记录的信息。



不难看出在W8下,连续分配同样大小的内存,内存地址并不连续切具有一定随机性。于是VUPEN采用的办法是在创建CRuntimeStyleInfo对象之前,事先创建一个缓冲区大小为0xB0的ORG数组。然后在循环0x400次,在每一次循环中创建一个CRuntimeStyleInfo对象,如果某一个CRuntimeStyleInfo对象的内存恰好和ORG数组缓冲区相邻,那么就能够读取到其偏移0x58位置上的指针。
 for (var i=1; i<0x400; i++) {

        a[i].marginLeft   = "TTWILLYOUMARRYME"                                                         //对marginLeft属性设置攻击者可控的数据

        marginLeftAddress = vml1.dashstyle.array.item(0x2E+0x16);                            //读取某个CRuntimeStyleInfo对象偏移0x58处的字符串指针   

        if(marginLeftAddress != 0){ 

               marginLeftAddress = decimalToHexString(marginLeftAddress);

               alert("i=0x" + i.toString(16) + " 0x:" + marginLeftAddress);

               break;

        }
 }

执行效果如下图所示,泄漏的地址为0x06F1A044;使用调试器查看该地址上数据——正是攻击者可控的数据"TTWILLYOUMARRYME"



最后读取敏感内存信息的代码作一简单说明:
marginLeftAddress = vml1.dashstyle.array.item(0x2E+0x16);   
1、0x2E=0x2C+2;其中0x2C为dashstyle属性中有效成员的个数,而下一堆块头部有8字节堆管理数据,数组中每个成员占4字节,所以再加
2、0x16 X 4= 0x58,从而读取到相邻CRuntimeStyleInfo对象偏移0x58位置上的字符串指针。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  cve-2013-2551