企业动态
行业资讯

IE漏洞攻防编年简史

DOM(文档对象模型)提供了操作HTML/XML文档的接口。IE浏览器中跟DOM实现相关的代码主要在mshtml dll中。mshtml中的CMarkup类负责构造整个htmI树结构,其成员函数CreateElement会调用全局的CreateElement函数束构造不同标签对应的元素。比如<object>标签.会构造对应的CObjectElement元素:<area>标签.会构造对应的CAreaElement元素。这些Element类都是CElement类的子类。接下来的逆向工作主要基于IE8 8.00.7601.17537版本的mshtml dll。

对于每个不同的标签,IE测览器内部有不同的CTagDesc结构。这些CTagDesc结构中的其中一项就是对应元素的CreateElement函数指针。因此,全局的CreateElement函数,会根据不同的标签柬获得对应的CTagDesc结构,然后再从里面取得对应该标签的CreateElement函数指针然后call过去进行调用。具体可参看全局CreateElement函数的反汇编代码,如图2.2.6所示。

这里有一些小细节,有的时候直接用IDA反汇编如mshtml dll这样的dll文件的时候没有找到对应的符号表,可以先使用Symbol Type Viewer这样的小工具将符号表下载下来放到跟dll同目录然后再使用IDA对相关的dll文件进行反汇编。

接下来,以CObjectElement为例,介绍其创建过程,其他Elenlent的创建过程类似。CObjectElement的初始化是在成员函数CrcateElement函数中完成的。创建过程如下:先分配内存,然后调用构造函数,最后将返回的对象指针保存在传入的CElemen**参数中。反汇编代码如图。

图2.2.9

HeapAlloc进行堆内存分配,高版本的一些mshtml dll中可能是由ProcessHeapAllocClear这个函数进行内存的分配。传给HeapAlloc的字节数是0E0h可知,当前IE浏览器版本中的CObjectElement大小为E0h。

接下来调用CObjectEtemem的构造函数完成CObjectElement对象的初始化,构造函数会自动调用父类的构造函数。调用完构造函数后.会将新建的CObjcctElemenl对象指针保存在传入的参数CElemen**中。这是通过代码

movecx,[ebp+arg_8]mov[ecx],eax

完成的。

IE浏览器采用引用计数束跟踪DOM对象的生命周期。引用计数(Reference Counting)算法对每个对象计算指向它的指针的数量。当有一个指针指向该对象时计数值加1 ,当删除一个指向酸对象的指针时,计数值减l。如果计数值减为0,说明不存在指向该对象的指针.此时就可以安全的销毁泼对象。垃圾回收过程就是回收引用计数为0的对象。引用计数算法的优点是算法实现简单,并且进行垃圾回收时无需挂起应用程序,回收速度快。

缺点是出于每一次对对象的指针操作都要对对象的引用计数进行更新,因此会减缓系统的整体运行速度。另外,使用引用计数算法的每个对象都需要额外的空问存储计数值。除此之外,引用计数算法的最大缺点是无法处理循环引用。循环引用指的是两个对象互相指向对方。此时两个对象的引用计数都依赖于对方.因此始终无法减至0。

IE浏览器实现引用计数的核心就是IUnknown接口。该接口提供了两个非常重要的特性:生存期控制与接口查询。对象内部通过引用计数来实现对象的生存期控制。调用程序不甩在意对象的内部实现细节.通过接口查询即可获得指向对象的指针。IE浏览器中的很多类都继承于IUnknown。IUnknown有三个方法。

图2.2.10

以上节介绍的<obiect>标签的内部实现CObjectElement类为例.该类最终继承于CElement。而CElement继承于CBase,CBase则实现了IUnknown接口。用户要查询<object>标签对应的CObjectElement对象,需要调用CObjectElement::QueryInterface函数。而CObjectElement的QueryIntefface函数最终会调用到CElement的QueryInterface接口.CElement的QueryInterface接口最终会调用PrivateQueryInterface 来获得对象指针。

PrivateQueryInterface会先调用CElement::CreateTearOffThunk函数退回对象包装后的指针.然后在接下来调用CCaret::AddRef函数(call eCX)增加引用计数。

而CElement::CreateTearOffThunk函数仅仅是简单的调用全局的CreateTearOflThunk函数。全局的CreateTearOflThunk函数反汇编部分代码如图

图 2.2.11

再来看看释放引用时所做的工作。对于CElement,用户不再需要其引用时,调用CElement::Release即可。CElement::Release是对CElement::PrivateRelease的封装,而CElemem::PrivateRelease主要的工作是调用父类CBase的PrivateRelease函数。CBase::PrivateRelease负责减少引用计数。

实际上IE当中这种对对象的创建和销毁的场景比比皆是,这也是在缓冲区漏洞在IE上面几近绝迹后UAF中兴的基础。

2.3 时代关键字

Deferred/Delayed Free Control Flow Guard Isolated Heap

上文已经简单的给出一个例子帮助理解UAF的成因和触发了。但是由于IE中对象众多调用关系复杂,微软作为防守的一方并不能像挖掘缓冲区溢出漏洞一样容易的穷举并修复所有潜在的漏洞。但是微软分别以发布补丁的方式在14年的6月和7月分别引入了隔离堆和延迟释放的漏洞利用缓解措施。并且在Win8.1Update3和Win10中引入了新的机制Control Flow Guard。我们简单记录说明一下这些机制。

UAF的触发和利用依赖于被释放的对象的重用。利用的过程必须依赖非法IE对象被确定的分配和释放。而隔离堆和延迟释放分别在对象的分配和释放的时候加入了保护。

在IE中CVE-2014-0282修补前CTextArea::CreateElement分配内存的时候有这样的代码

图2.3.1

漏洞修补之后代码是这样的。

图2.3.2

可以比较明显的看到存在UAF隐患的对象的内存分配已经单独使用了隔离堆进行内存分配。

而延迟释放是这样的。正常的对象释放使用HeapFree就立即释放了,而加入延迟释放之后需要被释放的对象会被统一记录然后根据规则再进行延迟释放。

再说一下CFG(Control Flow Guard)这个机制。CFG的机制是基于控制流完整性Control-Flow Integrity的设想。这里通过对二进制可执行文件的改写,对jmp的目的地址前插入一个在改写时约定好的校验ID,在jmp的时候看目的地址前的数据是不是我们约定好的校验ID,如果不是则进入错误处理流程。

图2.3.3

在Call的过程中会引入一个CFG的校验函数。CFG需要编译器和操作系统的双重配合。当这个校验函数在不支持的操作系统上运行的时候直接就return了。当在被支持的操作系统(win10和win8.1 update3)的时候就会跳转到一个ntdll里面的一个检测函数。检测的机制我们不在详细展开。

由于在溢出漏洞和UAF的大部分利用当中都依赖于覆盖某个地址然后劫持程序的EIP跳转到我们的恶意代码的地址进行执行。CFG在控制非法地址跳转方面直接斩断了大部分漏洞利用的可能。

3.1 后UAF时代

就目前来看,14年之后由于新的缓解措施的加入使得攻防双方的优势几乎一边的倒向了微软为首的防守者的阵营。

浏览器的漏洞利用已经没有固定的套路。如浏览器内部的脚本引擎的设计错误导致从脚本层面突破IE而进行漏洞的相关利用(CVE-2014-6332),对浏览器中flash插件的漏洞发掘利用得到ring3权限,然后配合对较老字体解析引擎代码发掘出来的提权漏洞再进行提权拿到系统权限(Hacking Team相关利用)。漏洞利用方式不一而足,有机会在修订简史的时候一并补充。

0×03 IE漏洞防护措施关键时点

2015年7月 CFG编译器支持 VS2015 RTM版本引入/guard开关对Control Flow Guard特性提供编译器支持。

2014年11月 CFG系统级别支持 Windows8.1 update3 对Control Flow Guard提供系统层面的支持,之后的windows系统均在操作系统层面支持该特性。

2014年7月 MS14-037补丁发布引入Delayed Free特性。

2014年6月 MS14-035补丁发布引入Isolated Heap特性。

2008年1月 SEHOP系统级别支持 发布vista Service Pack 1补丁包,引入对SEHOP特性的操作系统支持。自vista sp1后的windows系统均在操作系统层面支持该特性。

2007年1月 ASLR系统级别支持 windows vista系统引入对ASLR特性操作系统级别的支持。自vista后的windows系统均在操作系统层面支持该特性。

2006年年初 safeseh/stack cookie/aslr/dep编译器支持 VS2005引入/safeseh编译开关缓和溢出漏洞对seh的攻击,引入/GS编译开关插入Stack Cookie缓和对返回地址的攻击,加入/dynmicbase编译开关引入对ASLR特性的编译器支持,加入/NXCOMPAT编译开关引入对DE特性的编译器支持。自VS2005之后的编译器均支持上述编译开关。

2004年8月 DEP系统级别支持。微软推出XP Service Pack 2补丁包引入对DEP特性的操作系统支持,自XP SP2后的windows系统均在操作系统层面支持该特性。


 
版权所有:郑州三中网安科技有限公司 豫ICP备2020036495号-1    豫公网安备 41019702002241号 | 站点地图 | 人才招聘 | 联系我们