攻击互通性:以 OLE为例
翻译 by 银雁冰
说明:本文为 Haifei Li (haifei.li@intel.com )和 Bing Sun (bing.sun@intel.com ) 在 2015年美国黑帽大会 (BlackHat)的演讲 PPT。该 PPT对历史 Office漏洞的原因做了深度探讨,是 Office漏洞分析领域的经典 paper。对 Office漏洞有兴趣的小伙伴可以认真读一下这篇文章。
原文链接: https://www.blackhat.com/docs/us-15/materials/us-15-Li-Attacking-Interoperability-An-OLE-Edition.pdf
相关译文链接:http://bbs.pediy.com/thread-219234.htm
Ø 尽管我们要讨论的是 OLE,代表对象链接与嵌入 (Object Linking and Embedding ),本次演讲我们只讨论嵌入 (Embedding )。
Ø 限于演讲时间
Ø 这真是个很大的领域
Ø 什么是 OLE?
Ø 历史上与 OLE相关的 0day
Ø 深入解析 OLE
Ø 攻击面
Ø 结论
Ø 对象链接与嵌入
Ø 基于组件对象模型 (COM)
Ø 它服务于 Office/WordPad的大部分互通性
Ø 与默认 /第三方应用程序一起工作,以给 Office/WordPad用户丰富的文档特性
Ø 将一个文档嵌入另一个文档
Ø 通过双击 ” 清单 ” 里的文档,读者将能够打开另一个文档
Ø 对 Office 用户来说非常方便
Ø 几乎所有之前的严重的 Office/WordPad零日漏洞都涉及到 OLE
Ø CVE-2014-4114/6352( 又名 ” 沙虫 ” 零日漏洞 )
Ø 报告于 2014年 10月,非常严重的逻辑漏洞
Ø 在原始样本里面发现两个 OLE对象
Ø 在对 CVE-2014-4114 的初次修复中,微软并没有做到有效修复 (译者注:这直接导致了 CVE-2014-6352的公告 )
Ø CVE-2014-1761
Ø 2014年 3月被谷歌报告,是一起高度针对性的攻击
Ø RTF 文件格式解析错误,并不是一个位于 OLE 对象的漏洞,但是利用了 OLE 机制来加载一个未开启 ASLR 的模块 ”MSCOMCTL.DLL” ,用来绕过 ASLR
Ø CVE-2013-3906
Ø 2013年 8月被我们检测到并报告
Ø 微软图形组件错误,并不是一个位于 OLE 对象的漏洞,但是利用了 ActiveX/OLE 机制来进行 Office 中的堆喷射
Ø CVE-2012-0158/CVE-2010-3333
Ø 位于 MSCOMCTL.OCX中的多年的老漏洞 (译者注: CVE-2010-3333应位于 mso.dll中,这里或许 CVE-2012-1856更为合适,后者是 MSCOMCTL.OCX中的一个 UAF漏洞 )
Ø 经典 OLE 漏洞
Ø 到今天还可以看到野外的样本
Ø 补充一下:一个相似的 0day攻击,也位于 MSCOMCTL.OCX(CVE-2015-2424 )
Ø 在 2014年 6月 15日被 iSight的小伙伴公布
Ø http://www.isightpartners.com/2015/07/microsoft-office-zero-day-cve-2015-2424-leveraged-by-tsar-team
Ø OLE对象不仅制造严重的零日漏洞,也在另外的 Office/WordPad漏洞利用中起到了极大的帮助作用
Ø 加载未开启 ASLR 的模块
Ø 在 Office 进程中进行堆喷射
Ø …
Ø 漏洞类别覆盖从内存破坏到逻辑漏洞
Ø 之前几乎没有关于于 OLE内部机制的研究,但是我们要提到两个:
Ø “Attacking Interoperability”
Ø http://hustlelabs.com/stuff/bh2009_dowd_smith_dewey.pdf
Ø Mark Dowd, Ryan Smith, and David Dewey 写于 2009年
Ø 我们这次演讲的题目是为了纪念这篇 paper里面的伟大工作
Ø Parvez Anwar的博客上有一些与 Office/OLE相关的工作
Ø https://www.greyhathacker.net/
Ø 为了解释 OLE的内部原理,首先我们需要理解当一个用户打开一个含有 OLE的文档时会发生什么
Ø 初始化 /加载一个 OLE对象可以通过 ole32!OleLoad ()这一 API来简单实现
Ø 我们关注两个主要步骤
Ø 步骤 1 :调用 CoCreateInstance 来初始化 OLE 对象
Ø 步骤 2 :调用 IPersistStorage 来初始化 OLE 对象的初始状态 ( 数据 )
Ø 接下来我们详细分析这两个步骤
ole32!wCreateObject+0x101:
75b41553 e8b387feff call ole32!CoCreateInstance (75b29d0b)
0018de38 0018de98 00000000 00000403 64c0c954
0:000> k
75b3f2af ole32!wCreateObject+0x101
75b3f1d4 ole32!OleLoadWithoutBinding+0x9c
632c4eb4 ole32!OleLoad+0x37
0:000> db poi(esp)
0018de98 02 26 02 00 00 00 00 00-c0 00 00 00 00 00 00 46
0:000> db poi(esp+4*3)
64c0c954 12 01 00 00 00 00 00 00-c0 00 00 00 00 00 00
Ø CLSID来自文档,指明用户想要初始化哪一个 OLE对象
Ø 因为 Office/WordPad支持一系列的文档类型,不同类型定位 CLSID的方式都不一样
Ø Office Open-XML格式 (.docx, .xlsx, .pptx, 等等 )
Ø RTF(.rtf)
Ø Office二进制格式 (.doc, .xls, .ppt, .pps, 等等 )
Ø Office甚至支持 HTML格式
Ø 我们只举例给出 Open-XML格式和 RTF格式里面的 CLSID来源
Ø 对于 Open-XML格式, CLSID从 ”OLESS ”二进制数据文件中读入
Ø RTF文档用过时的 OLE1.0格式来定义一个 OLE对象
Ø https://msdn.microsoft.com/en-us/library/dd942402.aspx
Ø 指定一个 CLSID是通过指定位于 ”\objdata ”控制字中相应的 ProgID 来完成的
Ø 在运行时, ProgID将会通过 CLSIDFromProgID被“转换”成 CLSID(如果 ProgID不合法,而且接下来的 native数据遵循 OLESS格式, CLSID将会从 OLESS native数据中读取 )
ole32!wCreateObject+0x1f9:
75b3eb41 ff5118 call dword ptr [ecx+18h]
ds:0023:6fb614a8= {packager!CPackage::Load (6fb66171)}
0:000> k
75b3f2af ole32!wCreateObject+0x1f9
75b3f1d4 ole32!OleLoadWithoutBinding+0x9c
5c0e4eb4 ole32!OleLoad+0x37
Ø 容器调用 OLE对象的 IPersistStorage 接口中的 ”Load() ”方法来初始化 OLE对象的初始状态
Ø https://msdn.microsoft.com/en-us/library/windows/desktop/ms679731(v=vs.85).aspx
Ø IID: 0000010a-0000-0000-C000-000000000046
当初始化的时候为 OLE对象加载其初始“状态”
Ø 如何处理 IStorage —加载它的初始状态,其实取决于 OLE 对象
Ø 因为执行 IPersistStorage接口的代码位于 OLE提供者 (OLE对象 )
Ø Storage Data (由 ” IStorage”参数提供 )是存储在文档文件里的
Ø 和 ”CLSID”域一样,它也来自文档文件 (这可以由攻击者提供 )
Ø 但是两者也有一些不同
Ø OLE容器 (Office/WordPad)读取 CLSID是为了去初始化 OLE对象
Ø OLE容器读取 Storage Data并将它传递给 OLE对象,由 OLE对象负责处理读入的数据
Office Ope n-XML 格式中的 Storage Data
Ø 由 OLESS 数据文件 提供
Ø 下面的例子展示了 Flash Player OLE对象的 Storage Data
Ø D27CDB6E-AE6D-11CF-96B8-444553540000
Ø 从 OLESS 数据文件 (oleObject.bin)中读入 Storage Data
Ø 从 ”Contents”节里面读入
RTF 中的 Storage Data
Ø 由 OLE1 Native Data 提供
Ø 相关描述见这里: https://msdn.microsoft.com/en-us/library/dd942053.aspx
Ø 我们已经解释了 OLE 初始化 过程中的两个关键步骤
Ø 接下来,让我们看一下 ”Verb” 动作
Ø 本质上,执行 ”Verb”动作其实只是调用了 OLE对象的 IOleObject::DoVerb 方法
Ø IOleObject
Ø https://msdn.microsoft.com/en-us/library/windows/desktop/dd542709(v=vs.85).aspx
Ø IID: 00000112-0000-0000-C000-000000000046
Ø 这个接口上有 24个方法
Ø 这个 IOleObject::DoVerb 方法 有一些参数,但是我们只需要关注其中一个,即第一个参数: ”iVerb”,这个参数在特定场景下可以被攻击者控制
Ø 举个例子,通过提供 PowerPoint放映文件 (.ppsx, .pps)
packager!CPackage::DoVerb:
731e580c 8bff mov edi,edi
0:000> dd esp
0031c89c 660651c6 0054ec80 FFFFFFFD 00000000
Ø 所以,什么是攻击者可能会在一次基于文档的攻击中使用的呢?
Ø 我们需要理解一个攻击者可以从文档中提供什么数据
Ø 攻击者是否能够提供在 OLE初始化过程中 CoCreateInstance 函数所需的 CLSID
Ø 答案是: Yes (前面已经解释 )
Ø 攻击者是否能够提供在 OLE 初始化 过程中的 IPersistStorage::Load 所需的 Storage
Ø 答案是: Yes (前面已经解释 )
Ø 攻击者是否能够提供在 OLE”Verb”动作执行时所需的 ”Verb”id ?
Ø 答案是: Yes (前面已经解释 )
Ø 这是最常见的的一种
Ø 你想要去解析一些数据;我给你伪造的数据
Ø 有时候这会导致内存破坏,有时候这可能会变成一个逻辑漏洞
Ø 事实上,大多数之前被公开的 OLE漏洞都位于 IPersistStorage::Load 方法
Ø 让我们来给出几个例子
Ø 大多数之前的分析已经展现过下图了,在 MSCOMCTL.OCX模块中
Ø 但是,漏洞函数究竟来自哪里?
Ø 往前追踪,我们到了这里
Ø sub_276008D9函数到底是什么?
Ø 在一番逆向后,我们意识到这其实是 IPersistStorage::Load方法
Ø 事实上,这个基于栈的溢出位于 IPersistStorage::Load 方法
Ø 在 2014年 7月的 McAfee实验室博客上被报告
Ø https://blogs.mcafee.com/mcafee-labs/dropping-files-temp-folder-raises-security-concerns
Ø Demo: http://justhaifei1.blogspot.com/2014/08/demonstration-of-windowsoffice-insecure.html
Ø 还未被修复!
Ø 最近, (谷歌的 )James Forshaw在他发现的一个 NTLM反射权限提升漏洞中的利用中利用了这个特性:
https://code.google.com/p/google-security-research/issues/detail?id=325
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
上传的附件: