Flash 0Day: CVE-2018-15982 Exploit复现

栏目: 编程工具 · 发布时间: 7年前

内容简介:2018年12月5日,360发表博客《“毒针”行动 – 针对“俄罗斯总统办所属医疗机构”发起的0day攻击》披露了其在2018年11月29日捕获到的使用Flash 0day:CVE-2018-15982漏洞配合微软Office Word文档发起的APT攻击事件。文章从攻击流程,漏洞成因,漏洞利用,补丁分析,攻击载荷分析等多角度全面介绍了这次攻击的技术细节,非常值得大家仔细阅读学习。也许是因为篇幅有限,文章关于漏洞成因和漏洞利用部分细节描述略简,阅读完文章后可能会有如下一些问题:

*本文原创作者:elli0tn0phacker,本文属于FreeBuf原创奖励计划,未经允许禁止转载

0×00 背景

2018年12月5日,360发表博客《“毒针”行动 – 针对“俄罗斯总统办所属医疗机构”发起的0day攻击》披露了其在2018年11月29日捕获到的使用Flash 0day:CVE-2018-15982漏洞配合微软Office Word文档发起的APT攻击事件。文章从攻击流程,漏洞成因,漏洞利用,补丁分析,攻击载荷分析等多角度全面介绍了这次攻击的技术细节,非常值得大家仔细阅读学习。

也许是因为篇幅有限,文章关于漏洞成因和漏洞利用部分细节描述略简,阅读完文章后可能会有如下一些问题:

1)在没有符号表的情况下,如何定位存在漏洞的函数add_keySet;

2)DRCWB是什么;

3)漏洞利用部分动态调试情况;

4)HackingTeam Bypass DEP/CFG执行Shellcode的技术细节。

笔者在学习了这篇文章后,完成了该CVE的Exploit复现,在此记录下完整的分析过程,并尝试解释上述问题,与大家分享。但水平有限,文中错误之处恳请斧正。

0×01 Flash 调试

众所周知,Flash没有符号表,难以对相应的Native Code下断点。同时AVM拥有自己的Custom Heap,因此也无法通过开Page Heap第一时间定位漏洞现场。所以Flash的调试往往比有符号表的浏览器的调试略微复杂一些。在学习了前人的经验后,笔者一般通过如下方法调试Flash:

Flash编译器会将AS3 code编译成ABC code,在执行阶段AVM2会对每一段ABC code验证后生成对应的一段JIT code,在没有符号表的情况下,如果可以对生成的JIT code下断点,再单步跟踪就可以找到调用的Native Code了。

以调试Metadata::setObject为例,首先构造如下测试代码:

Flash 0Day: CVE-2018-15982 Exploit复现 这里将需要分析的setObject方法单独放在一个测试方法testMetadata()中,如果可以对testMetadata()下断点,那命中断点后单步跟踪就很容易定位到setObject对应的Native Code了。那如何对testMetadata()下断点呢,《漏洞战争》中提到了DbgFlashVul这个工具,可以对as3方法下断点:

Flash 0Day: CVE-2018-15982 Exploit复现

命中testMetadata() JIT后的代码,继续跟入,很快就找到了setObject的Native Code实现:

Flash 0Day: CVE-2018-15982 Exploit复现

这样就找到了setObject_impl,进一步跟入最终可以找到add_keySet的代码。

需要注意的是这个 工具 中inline hook的几个native 函数的特征码不同flash版本是不同的,因此需要根据flash版本更新 Hook函数的特征码才可以正常使用。

如果不熟悉这款工具的话,还可以通过另一种方法来定位JIT Code:借助已知符号表函数下断点,再根据Call Stack定位。AS3提供ExternalInterface.call(functionName:String,…arguments)方法来调用JS,而mshtml.dll和jscript9.dll的符号表是已知的,因此我们可以在需要断下AS3方法入口点插入类似的辅助调试语句:

Flash 0Day: CVE-2018-15982 Exploit复现 通过对已知符号函数下断点,命中断点后根据Call Stack也是可以找到JIT Code的入口点的。

Flash 0Day: CVE-2018-15982 Exploit复现 0×02 漏洞成因

CVE-2018-15982是一个存在于flash PSDK com.adobe.tvsdk.mediacore.metadata包的UAF漏洞。Metadata类提供了一个类似Key-Value的容器,Key为String,Value为Object。该漏洞存在于Metadata的SetObject方法, SetObject方法用来向Metadata对象存放数据:

Flash 0Day: CVE-2018-15982 Exploit复现 SetObject对应的Native实现如下:

1.传入Key(String)和value(Object),调用setObject_impl:

Flash 0Day: CVE-2018-15982 Exploit复现 2.setObject_impl内部会调用add_keySet将key(String)按索引保存至Metadata对象的keySet属性:

Flash 0Day: CVE-2018-15982 Exploit复现 3.add_keySet将传入的key(String)依次保存到KeySet中:

Flash 0Day: CVE-2018-15982 Exploit复现 AMV2中StringClass继承于MMgc::RCObject,根据MMgc文档,必须使用DRCWB宏来管理MMgc::RCObject对象指针,如果未使用,MMgc::RCObject的引用计数不会增加,GC后,String内存被释放,该对象指针变成一个悬挂指针:

Flash 0Day: CVE-2018-15982 Exploit复现

所以这个Bug的根本原因是:将String对象传递给KeySet后,没有增加String对象的引用计数,GC后String对象被释放,但是KeySet中仍然保存了该String对象的地址,最终形成悬挂指针。

触发漏洞的PoC如下:

Flash 0Day: CVE-2018-15982 Exploit复现

通过setObject向Metadata的KeySet属性存放了0×100个String(“0”, “1”, “2” … “255”),然后通过触发异常强制GC,最终array_key这个Vector.<String>中将包含指向已释放内存的String的悬挂指针, 动态调试如下:

1.通过setObject向Metadata的KeySet属性存放了0×100个String(“0”, “1”, “2” … “255”):

Flash 0Day: CVE-2018-15982 Exploit复现 2.GC后,KeySet包含了部分指向原String对象的悬挂指针:

Flash 0Day: CVE-2018-15982 Exploit复现 通过调试可以看到Metadata.KeySet指向一片连续的内存区域(从0x02b8ddb0开始),保存了key(String)的指针(这和我们之前静态分析add_keySet函数的逻辑是一致的),GC后因为String在保存到Metadata.keySet内存区域的时候没有通过DRCWB宏增加引用计数,导致String被释放,从而Metadata.keySet中保存了一系列指向原来String的悬挂指针(如动态调试中的KeySet [10],KeySet [11])。通过图示的方法可以更加容易理解这个PoC的效果:

Flash 0Day: CVE-2018-15982 Exploit复现 0×03 漏洞利用

由漏洞原理分析可以知道,通过触发漏洞可以获得一个包含一系列悬挂指针的Metadata.KeySet,每个悬挂指针指向的内存大小为0×18 Bytes(StringClass大小)。接下来考虑如何占位并利用这些悬挂指针实现远程代码执行。

这里的利用思路是:利用UAF将两个自定义类Class3,Class5的对象指针都指向这块内存,通过操作这两个对象实现类型混淆,从而进一步实现任意地址读写,混淆方法如图所示:

Flash 0Day: CVE-2018-15982 Exploit复现

这样就可以通过Class5的m_1, m_2读取Class3的m_ba, m_Class1地址,也可以通过操作Class3.m_Class1.m_1实现任意地址的读写。

具体实现步骤如下:

1.内存准备,触发漏洞,获得一个包含一系列悬挂指针的KeySet,并保存到变量arr_key中,为后面遍历占位对象使用:

Flash 0Day: CVE-2018-15982 Exploit复现 Flash 0Day: CVE-2018-15982 Exploit复现 2.使用0×100个大小为0×30 Bytes的Class5对象(this.vec5[i])尝试占位空洞内存,根据MMgc,创建一个Class5对象可能会重用两个已经释放的String内存(0×18*2=0×30 Bytes):

Flash 0Day: CVE-2018-15982 Exploit复现 因为String.length和Class5.m_1都在偏移0×10处,可以通过遍历arr_key[i].length来判断是否找到占位Class5。最终获得一个悬挂指针 array_key[i] -> this.vec5[?] -> Class5,占位的Class5在this.vec5[?]中的索引待定。

Flash 0Day: CVE-2018-15982 Exploit复现 3.释放array_key指向的内存,此时this.vec5[?]成为悬挂指针,再使用0×100个大小为0×30 Bytes的Class3对象尝试第二次占位(this.vec3[i]),Class3占位成功后,this.vec5[?].m_1会指向Class3.m_ba,通过遍历this.vec5找到这个被Class3占位的this.vec5[?],标记为index_1,通过this.vec5[index_1]就可以操作占位的Class3的内存:

Flash 0Day: CVE-2018-15982 Exploit复现 Flash 0Day: CVE-2018-15982 Exploit复现 4.通过3获得的this.vec5[index_1]修改占位的Class3的m_Class1为m_ba,通过遍历this.vec3[i].m_Class1.m_1找到这个占位的Class3即this.vec3[?],标记为index_2,从而this.vec3[index_2]同样指向这块内存:

Flash 0Day: CVE-2018-15982 Exploit复现 5.这样就得到了指向同一片内存的两个指针this.vec5[index_1],this.vec3[index_3],通过操作这两个指针就可以实现Class5和Class3的类型混淆,从而实现任意地址读写:

Flash 0Day: CVE-2018-15982 Exploit复现 6.利用任意地址读写,搜索PE的IAT、EAT,泄露VirtualProtect地址

Flash 0Day: CVE-2018-15982 Exploit复现 Flash 0Day: CVE-2018-15982 Exploit复现 7.劫持ExecMgr::call虚函数调用,替换成VirtualProtect,Bypass DEP和CFG:

Flash 0Day: CVE-2018-15982 Exploit复现 Payload.call会在Native层调用FunctionObject::AS3_call,AS3_call内部会调用ExecMgr::call,ExecMgr::call的函数调用与VirtualProtect类似并且ExecMgr::call这个间接调用不受CFG保护,因此通过劫持这个虚函数调用来执行VirtualProtect:

Flash 0Day: CVE-2018-15982 Exploit复现 8.通过劫持Payload的JIT Code指针,替换成Shellcode,调用Payload.Call(null) 最终执行Shellcode:

Flash 0Day: CVE-2018-15982 Exploit复现 最终效果:

Flash 0Day: CVE-2018-15982 Exploit复现


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Convergence Culture

Convergence Culture

Henry Jenkins / NYU Press / 2006-08-01 / USD 30.00

"Convergence Culture" maps a new territory: where old and new media intersect, where grassroots and corporate media collide, where the power of the media producer, and the power of the consumer intera......一起来看看 《Convergence Culture》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具