freeBuf
主站

分类

云安全 AI安全 开发安全 终端安全 数据安全 Web安全 基础安全 企业安全 关基安全 移动安全 系统安全 其他安全

特色

热点 工具 漏洞 人物志 活动 安全招聘 攻防演练 政策法规

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

Flash 0Day: CVE-2018-15982 Exploit复现
FreeBuf_298532 2018-12-27 10:00:36 543768

*本文中涉及到的相关漏洞已报送厂商并得到修复,本文仅限技术研究与讨论,严禁用于非法用途,否则产生的一切后果自行承担。

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

0x00 背景

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复现,在此记录下完整的分析过程,并尝试解释上述问题,与大家分享。但水平有限,文中错误之处恳请斧正。

0x01 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为例,首先构造如下测试代码:

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

image.png

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

image.png

这样就找到了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方法入口点插入类似的辅助调试语句:

image.png通过对已知符号函数下断点,命中断点后根据Call Stack也是可以找到JIT Code的入口点的。

image.png0x02 漏洞成因

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

image.pngSetObject对应的Native实现如下:

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

image.png2.setObject_impl内部会调用add_keySet将key(String)按索引保存至Metadata对象的keySet属性:

image.png3.add_keySet将传入的key(String)依次保存到KeySet中:

image.pngAMV2中StringClass继承于MMgc::RCObject,根据MMgc文档,必须使用DRCWB宏来管理MMgc::RCObject对象指针,如果未使用,MMgc::RCObject的引用计数不会增加,GC后,String内存被释放,该对象指针变成一个悬挂指针:

image.png

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

触发漏洞的PoC如下:

image.png

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

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

image.png2.GC后,KeySet包含了部分指向原String对象的悬挂指针:

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

image.png0x03 漏洞利用

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

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

image.png

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

具体实现步骤如下:

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

image.pngimage.png2.使用0x100个大小为0x30 Bytes的Class5对象(this.vec5[i])尝试占位空洞内存,根据MMgc,创建一个Class5对象可能会重用两个已经释放的String内存(0x18*2=0x30 Bytes):

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

image.png3.释放array_key指向的内存,此时this.vec5[?]成为悬挂指针,再使用0x100个大小为0x30 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的内存:

image.pngimage.png4.通过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]同样指向这块内存:

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

image.png6.利用任意地址读写,搜索PE的IAT、EAT,泄露VirtualProtect地址

image.pngimage.png7.劫持ExecMgr::call虚函数调用,替换成VirtualProtect,Bypass DEP和CFG:

image.pngPayload.call会在Native层调用FunctionObject::AS3_call,AS3_call内部会调用ExecMgr::call,ExecMgr::call的函数调用与VirtualProtect类似并且ExecMgr::call这个间接调用不受CFG保护,因此通过劫持这个虚函数调用来执行VirtualProtect:

image.png8.通过劫持Payload的JIT Code指针,替换成Shellcode,调用Payload.Call(null) 最终执行Shellcode:

image.png最终效果:

image.png

0x04 参考文献

1)http://blogs.360.cn/post/PoisonNeedles_CVE-2018-15982.html

2)https://developer.mozilla.org/en-US/docs/Archive/MMgc

3)https://help.adobe.com/en_US/primetime/api/psdk/asdoc-dhls_2.3/index.html

4)https://www.freebuf.com/column/191383.html

5)https://www.freebuf.com/vuls/73074.html

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

# 0day # Adobe Flash Player
本文为 FreeBuf_298532 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
漏洞复现专栏
FreeBuf_298532 LV.3
这家伙太懒了,还未填写个人描述!
  • 4 文章数
  • 0 关注者
Look Mom, I dont use Shellcode议题Exploit复现
2018-11-26
深入理解Double Free:CVE-2015-2419 Exploit分析
2018-11-13
CVE-2018-8174:从UAF到任意地址读写
2018-06-12
文章目录