利用Elderwood工具包编写漏洞利用程序(第二部分)
在本文的三部曲最终章,我们深入研究了工具包使用者如何控制程序流,以及他们的策略对漏洞利用可靠性的影响。
文档对象模型(DOM)
HTML文档对象模型(DOM)是HTML页面的表示形式,用于访问和修改属性。浏览器通过JavaScript提供DOM接口,使网站能够具有交互性和动态生成的内容。这个接口非常复杂,存在许多安全漏洞,例如攻击者在CFR入侵中使用的释放后使用(use-after-free)漏洞。Elderwood组织至少应对Internet Explorer中此前三个此类漏洞的发现和利用负责。
释放后使用漏洞
当程序释放一个内存块,然后在程序执行的后续时间点尝试使用它时,就会发生释放后使用漏洞。如果在内存块被重用之前,攻击者能够在其位置分配新数据,他们就可以获得程序流的控制权。
利用释放后使用漏洞
- 程序分配并随后释放内存块A
- 攻击者分配内存块B,重用先前分配给块A的内存
- 攻击者将数据写入块B
- 程序使用已释放的块A,访问攻击者留在那里的数据
为了利用CVE-2012-4792,漏洞利用程序分配并释放了一个CButton对象。当Internet Explorer的其他地方维护着对已释放对象的弱引用时,漏洞利用程序用他们自己的数据覆盖了CButton对象。然后利用程序通过弱引用触发对CButton对象的虚函数调用,从而获得程序执行控制权。
堆准备
当发生16次相同大小的分配后,Internet Explorer将切换到使用低碎片堆(LFH)进行进一步的堆分配。由于这些分配存在于不同的堆上,它们无法用于利用,必须被忽略。为了安全地跳过前16次分配,漏洞利用作者通过在div标签上分配className属性,创建了3000个与CButton对象大小相似的字符串分配。
|
|
所选字符串的内容(重复的"ab")并不重要,重要的是由其创建的分配大小。LFH对于小于256字节的分配具有8字节的粒度,因此80到88字节之间的分配将从同一区域分配。以下是内存中字符串的内存转储示例:
|
|
然后,漏洞利用作者将每隔一个div标签的className设置为null,从而在调用CollectGarbage()时释放先前创建的字符串。这将在分配的堆内存中创建空洞,并创建可预测的分配模式。
|
|
接下来,作者创建500个按钮元素。如前所述,他们释放每隔一个元素以创建空洞,并调用CollectGarbage()以启用分配的重用。
|
|
在漏洞利用中许多重用代码的示例中,用于堆操作的JavaScript数组被称为arrObject。这恰好是JavaScript Cookbook第70页上关于如何创建数组的示例中给出的变量名。
触发漏洞
下面的代码负责创建释放后使用条件。applyElement和appendChild调用创建了正确的条件和新分配。释放将在q标签上设置outerText属性后调用CollectGarbage()时发生。
|
|
此时,存在一个指向已释放内存的指针(陈旧指针)。为了继续利用,必须将其指向的内存替换为攻击者控制的数据,然后必须使用该指针。
值得注意的是,漏洞触发器是漏洞利用中唯一被try/catch块包裹的部分。在测试中,我们确认这个try/catch不是触发漏洞或成功利用的必要条件。如果作者担心未处理的异常,他们可以将所有代码包装在try/catch中,而不是仅包装这部分。这种情况表明漏洞触发器与开发者自己编写的任何代码是分开的,可能是自动生成的。
此外,漏洞触发器是漏洞利用代码中模糊测试器可以独立生成的部分。这样的安全测试工具可能在每次页面加载时将许多DOM操作包装在try/catch块中,以最大化测试可能性而无需重新启动浏览器。考虑到代码中留下的其他不必要操作的数量,很可能是模糊测试器的输出被粘贴到漏洞利用代码中,并且其使用的try/catch保持完整。
替换对象
为了用他们控制的内存替换已释放的CButton对象,攻击者从LFH消耗20个分配,然后将第21个分配作为替换目标。选择针对第21个分配可能是通过观察或实验做出的,而不是基于堆内存的精确知识。正如我们将在下一节中讨论的,这个假设导致漏洞利用行为不可靠。如果作者对堆操作有更好的理解并更改这几行代码,漏洞利用可能会更加有效。
|
|
window.location行有两个目的:创建替换对象并触发陈旧指针的使用。与为此漏洞利用创建的大多数其他堆分配一样,调用unescape()函数来创建字符串。这次略有不同。漏洞利用作者使用%u编码来完全控制分配中的第一个DWORD,即对象的vtable。
对于替换的对象,内存将如下所示:
|
|
当设置window.location时,浏览器会转到字符串中提供的URL。此位置更改将释放当前页面创建的所有分配,因为它们不再需要。这会触发已释放对象的使用,此时攻击者获得浏览器进程的控制权。在这种情况下,这会导致浏览器在当前域上加载"/[不可打印字节]https://www.google.com/settings/account"。由于此URL不存在,在CFR网站上加载漏洞利用的iframe将显示错误页面。
总之,漏洞利用程序用攻击者控制的数据覆盖了已释放的CButton对象。在这种情况下,使用了一种非常脆弱的技术来覆盖已释放的CButton对象,因此漏洞利用无法可靠地获得对受攻击浏览器的执行控制。漏洞利用编写者没有覆盖大量可能最近释放的对象,而是假设他们覆盖的第21个对象始终是正确的已释放CButton对象。这降低了漏洞利用的可靠性,因为它假定了已释放CButton对象在空闲列表中的预定位置。
现在漏洞可以被利用,可以通过使用我们在前一篇文章中提到的提供的地址0x10ab0d0c与工具包集成。通过将控制权转移到该地址加载的SWF,受害者将运行提供的ROP链和分阶段有效负载。
可靠性
与普遍看法相反,即使在"支持"的平台上,漏洞利用也可能失败。释放后使用漏洞利用依赖于堆的复杂操作来执行受控内存分配。关于内存状态的假设可能因总可用内存、先前访问的网站、存在的CPU数量甚至主机上运行的软件更改而被打破。因此,我们认为漏洞利用可靠性是在这些不同场景中成功执行有效负载与总尝试次数的度量。
我们模拟了Elderwood对CVE-2012-4792漏洞利用的真实使用情况,以确定其整体可靠性。我们构建了一个Windows XP测试系统,其中包含漏洞利用所需的Internet Explorer、Flash和Java版本。我们的测试例程从访问随机网站(从几个流行网站中选择)开始,然后转到托管漏洞利用的测试网站。我们认为这接近真实使用情况,因为受感染的网站不太可能是任何人的主页。
在这些理想条件下,我们确定漏洞利用的可靠性在我们的测试中为60%。尽管如前面的代码片段所述,不需要创建空洞来触发漏洞以成功利用它,但我们发现如果不执行这些操作,可靠性会降至约50%。我们在下面描述了可靠性如此低的一些原因:
-
对SWF提供的恒定内存地址的依赖。如果内存分配发生在其他地方,而不是漏洞利用假设的地址,浏览器将崩溃。例如,如果在0x10ab0d0c加载了非ASLR插件,漏洞利用将永远不会成功。如果在Windows XP上在默认加载地址0x10000000加载大型模块,也可能发生这种情况。
-
假设第21个对象将被陈旧的CButton指针重用。如果陈旧的CButton指针重用任何其他地址,则此假设将导致漏洞利用失败。在这种情况下,漏洞利用将从"ab"字符串的分配中解引用0x00410042。
-
使用垃圾收集器触发漏洞。使用垃圾收集器是触发此漏洞的好方法,但它可能具有不确定的副作用。例如,如果堆合并,陈旧的指针很可能指向攻击者无法控制的缓冲区,并导致浏览器崩溃。
即使在测试此漏洞利用之前,很明显由于它依赖Flash和其他插件来绕过DEP和ASLR,它只能针对受影响浏览器的子集。我们构建了具有这些约束的理想测试环境,并发现它们的替换技术是不可靠行为的重要来源。由于替换技术的脆弱性,近50%应该被利用的网站访问者没有被利用。
结论
在提供了易于使用的DEP和ASLR绕过接口后,此工具包的用户只需制定对象替换策略即可创建有效的漏洞利用。我们对此漏洞利用中对象替换代码的评估表明,作者对此概念的掌握很差,因此漏洞利用不可靠。如果作者对堆操作有更好的理解或遵循已发布的对象替换方法,此漏洞利用的可靠性会高得多。相反,作者依赖于关于内存状态的假设,并且他们的部分工作似乎是从烹饪书示例代码中复制的。
到目前为止,可以认为许多复制示例代码的例子是假旗操作的结果。我们的分析表明,在漏洞利用最重要的部分,用户显示的技能水平与漏洞利用的其余部分保持一致。如果攻击者假装无能,这个关键代码部分不太可能以超过表面的方式受损。相反,这次攻击活动失去了近一半本可以利用的少数网站访问者。
安全行业的许多人认为APT组织在野外使用漏洞利用之前会"武器化"它们。然而,继续使用Elderwood工具包进行战略性网站入侵表明,这个攻击团体既不需要扎实的工程实践,也不需要高度可靠的漏洞利用代码来实现其目标。