首页
社区
课程
招聘
[翻译]针对Apple Safari的漏洞发现(评估复杂软件的漏洞利用)
2018-6-30 16:16 3467

[翻译]针对Apple Safari的漏洞发现(评估复杂软件的漏洞利用)

2018-6-30 16:16
3467

原文地址:http://http://blog.ret2.io/2018/06/13/pwn2own-2018-vulnerability-discovery/


漏洞发现是exploit开发生命周期的第一阶段。这个阶段的持续时间是无限制的,因为一个给定目标的搜索空间,代码质量和评估过程可能会大不相同。在手动和自动发现漏洞之间往往是选择先使用谁的问题,难以达到有效的平衡。

作为Pwn2Own 2018博客文章系列的第二部分,我们将讨论研究复杂软件目标(SafariWeb浏览器)的方法,缩小我们的评估范围,选择发现漏洞的策略,并为此开发独特的浏览器模糊测试工具(browser fuzzer)。


(上图是一个基于JS语法的Fuzzzer生成的测试用例片段)


有关此博客系列和我们整个Pwn2Own 2018 exploit-chain的顶级讨论,请查阅第一部分。

侦察 101 (Reconnaissance 101)

面对数百万行代码,挖掘大型软件的漏洞可能会有些困难。为了克服这个难题,建立目标的基础知识和一部分0day发展过程中最不引人注目的部分之一是至关重要的。这是基础侦察101。

软件有什么作用?用户如何与软件之间进行交互?项目如何构建?它的主要组分是什么?过去的漏洞是什么样的?

这一步实际上归结为汇总与目标相关的文档或安全文献,并花些时间对其进行研究。建立链接列表并做笔记,但不要试图理解其所有内容。


(上图表明:实际开发通常是通过从对现有资源的仔细研究开始的)


如果您没有与自己的目标相关的公开的研究或文档,也许查看与目标相关的材料(例如,Google的v8,Mozilla的SpiderMonkey,Microsoft的Chakra等)或设备(针对硬件攻击而言)可能会有帮助。

跳过这一步将意味着您会花费10倍的时间来完成这些资源为您提供的相同研究发现。

WebKit:对一个目标进行调零

在处理中小型目标时,研究所有内容通常是可行的......但是,当研究规模和复杂度更大的代码库时,这会变得越来越困难。

使用从现有文献学习到的知识(recon 101),重要的是尽量缩小具有评估价值的范围,直到剩下的攻击面数目在你的掌控范围之内。

我们使用了同样的方法,将WebKit的评估范围从300万行C / C ++代码限制到不足70k。通过限制广度,我们希望能够在代码库里的一个指定子集上执行有深度、有质量的评估。


(上图是:由SciTools用Understand生成的WebKit源目录的可视化树形图)


对于Pwn2Own 2018,我们选择专注于研究Safari内的JavaScript引擎——JavaScriptCore。这是在分析了现有研究的基础上作出的明智决定。尽管JS引擎中的bug日益罕见,但他们高度的可利用性很难缓解。

选择JavaScriptCore大大缩小研究范围,即使如此,JSC仍有大约350k行C/C++代码。为了帮助我们熟悉代码库,我们选择将代码量进一步缩小到最易于研究的范围。


(上图是:JavaScriptCore源目录的可视化树形图,其中JavaScript运行时以红色突出显示)


组成JS运行时的C / C ++代码(以红色突出显示)几乎直接映射到编写JavaScript时使用的高级对象。运行时实际上是任何JS引擎的表层。

这个高层主要是在/Source/JavaScriptCore/runtime中:


(上图为:JavaScriptCore运行环境的目录,在前两张图片中都呈现为红色)


仅专注于运行时的文件夹,我们缩小到大约70k行代码。这个数字还是非常可观的,缩小的范围形成了更加平易近人的任务。什么是“合理的”取决于你计划使用的资源和发现策略。

选择目标后,是时候选择一种发现漏洞的方法了。

评估策略

有效的软件(安全)评估有两种不同的方法。完全可以由个人喜好来选择其中之一,否则应当按照优先性和潜在的动机性来选择。

Fuzzing是许多安全爱好者的转战策略,因为它通常成本低且富有成效。Fuzzer可以在很短的时间内覆盖大量的攻击面,但是以人类能够提供的深度和“创造力”为代价的。使用Fuzzer快速查找bug会带来成就感,但也可能是“警告”,因其他人已在别的地方找到了相同内容。这些bug的保质期通常较短。

代码审计对于已经过严格审查的代码来说既枯燥又令人沮丧。但是,对于那些坚持审计的人来说,往往会导致更大的bug,这些bug是大多数Fuzzer以及一些审计人员检测不到的。这些bug往往更持久,并且经常用于贸易。

对于这次研究,我们使用繁重的fuzzing方法是合乎情理的。我们为JSC定位的这个层面是一个很高的目标,因为这些年来它被选择的次数非常多。它是浅薄的,也是WebKit中由Fuzzer或源代码审查者提供的审查次数最高的代码之一。在这个领域发现的bug在当今环境中不可能持续很长时间。

本文的其余部分详细介绍了在构建JS Fuzzer时我们应当虑的方法和注意事项。

Fuzzing 语法

经典的Fuzzing技术,如位翻转( bit-flipping),简单输入变异和测试用例剪接,通常不适用于高结构化的上下文输入,如解释型语言(Javascript)。为了Fuzz这些输入,最好的方法是使用语法来综合正确的语法和合理的语义测试用例。

实际上,语法通常是由分析师手写的,作为一套结构化数据的“规则”。举个例子,我们来写一些简单的语法以生成数学表达式:

digit :=
1
2
3
...
operator :=
+
-
*
...

使用这些'语言'模板,我们可以建立新的高级语法结构(数学表达式):

expr :=
    +digit+ +operator+ +digit+

为了使这个概念具体化,我们要求测试用例生成器使用我们编写的语法规则,并输出任意数量的随机expr:

1 + 1
1 * 2
3 - 2
2 + 3
...

同样的想法可以推广到更复杂的任务中,例如生成语法正确的JavaScript代码。这可以归结为阅读规范并将其转换为语法定义。

用语法合成JavaScript

fuzzer的JS测试用例是由Mozilla的dharma通用版本推出的语法提供的,扩展为包含一些简便方法,使我们能够生成更多有联系的代码。

我们为dharma提供了两类JS语法:库和驱动。

库语法要有三个目的:

  • 定义规则以初始化特定的JavaScript对象或类型(数组,字符串,Maps等);
  • 定义规则以生成针对该对象或类型的所有有效的成员函数(例如,array.sort());
  • 定义语法或语义相似的规则集合;

驱动语法为我们提供了库语法之间的高级支架。通常,库语法将先使用已在库中定义的规则来初始化一组不同的JavaScript变量。在此之后,他们产生了随机化的结构,其中:

  • JavaScript变量之间的强制交互;
  • 在随机点修改,删除或重新初始化变量;
  • 根据变量的类型调用适当的成员函数;

集合使我们能够在驱动语法中表达高级“准则” 。下面是一个例子,我们来看看我们为JSArray对象编写的一些集合:

CallbackMethod :=
+every+
+filter+
+reduce+
    ...

InPlaceMethod :=
+sort+
+splice+
+shift+
... 

如果我们希望一个数组随机修改自己,我们只能使用众多方法中的一种,可以在我们构建的任何更复杂的语法结构中包含单个语句+JSArray:InPlaceMethod+。没有集合的话,我们只能手动指定每个可能性。

集合中的每个条目都会生成该特定成员函数(或API)的随机选择的签名,可能会在必要时触发生成其他JavaScript构造:

sort :=
sort()
sort(+GenericFunc:TwoArgNumericCmp+)
...

这使我们可以很灵活地编写驱动语法。我们只需提供测试用例生成的粗略样式,然后指定它们之间应该完成的命令。

最后,我们使用一个'mega-driver'来做大部分fuzzing。这个语法会初始化我们编写的每个库语法中的变量,然后对它们进行无序的生成操作:


(上图是:一个无序的“mega-driver”语法生成的测试片段)


最初,这个语法旨在作为我们收集代码的覆盖范围并改进底层库语法的“管理”。只要我们对运行时的功能收集的代码覆盖范围广,稍后,这个计划就会建立更有趣的环境并阐述驱动语法。

这并没有结束,因为我们在构建库语法时发现了一个可利用的问题。

可扩展的Fuzzing线束 (Harness)

在构建用于更好地生成测试用例的JS语法的同时,我们还开发了另一种在Python中使用的分布式和可伸缩的Fuzzing线束。根据惯例,这个线束的基础架构是使用一个“主”节点和任意数量的“辅助”节点所构建的。

主节点负责:

  • 管理辅助节点的配置;
  • 将储器中的辅助节点记录的崩溃以及测试样例分类;
  • 合并辅助节点收集的代码覆盖率的指标;

因此,辅助节点的责任包括:

  • 测试用例的生成;
  • 在JSC下启动测试用例并报告崩溃;
  • 通过随机的抽样测试案例来收集代码覆盖的数据;


(上图是:可从主节点获取的fuzzer控制面板的视图)


我们针对JSC的调试构建了辅助节点,并使用运行在Ubuntu 16.04上的ASAN进行编译。对此而言,我们未对JavaScriptCore代码库进行特殊的修改。

抽象语料库的覆盖率

有一小部分时间,我们的线束将使用DynamoRIO来收集针对JSC执行的随机抽样的代码覆盖率。线束将所有的代码覆盖信息汇总为我们的JS语法能够为JSC生成的语料库的粗略近似值。

在主节点上,我们自动生成并公开了控制面板中的lcov报告,以便快速直观地了解整体代码覆盖范围。这份报告将每隔几分钟更新一次,汇总来自辅助节点的任何新的覆盖数据,便于实时追踪语法的改进。


(查看由Fuzzer主节点生成的JSC的lcov报告)


有时候,我们还使用Lighthouse下载并探索运行覆盖率的聚合。通过编译时优化和禁用内联,线束能够明确地收集编译时优化和内敛禁用的JSC 发布版本的覆盖范围,以便我们在反汇编器中拥有更清晰的视图。


(用Lighthouse探索最新的JSC代码覆盖率)


虽然在源代码可用时评估汇编层的覆盖率似乎不太直观,但“更接近这一层”有以下优势:

  • 在反汇编器中,在复杂的边缘情况下的“放大”更常见;
  • Lighthouse比lcov生成的静态HTML报告更具交互性;
  • Lighthouse为我们提供了详细的功能级别的属性和覆盖范围统计信息,以便按照顺序和优先级排序;
  • C++模板化代码可有一个源实现,但能够为它们发射许多二进制函数;

这种工具组合为我们提供了调整语法的宝贵意见,以确保边缘案例的覆盖、非标准操作模式以及JSC运行时内显着的执行差距。

我们一旦掌握了某些东西,便希望能使用覆盖率来增强和指导自己的手动审计源代码的能力,但正如语法部分所述,我们被过早发现所阻碍。

漏洞发现

当我们的“语料库”开始超过作用域目标(正在运行的文件夹)的约50%的代码覆盖率,就会出现许多独特的崩溃。fuzzing时被良好的可见覆盖所补充也并不罕见。我们的目标是覆盖大于 60%的代码,最后几个百分点的难题(边缘情况,不常见的代码)是bug经常发生的地方。

当对这些新的崩溃进行分类时,我们注意到一个特别有趣的调用堆栈:


(WTFCrashWithSecurityImplication(...)将引人注意)


在最小化崩溃的测试用例后,我们留下了以下概念性证明(PoC):

// initialize a JSArray (someArray1), with more JSArrays []
var someArray1 = Array(20009);
for (var i = 0; i < someArray1.length; i++) {
someArray1[i] = [];
}

// ???
for(var index = 0; index < 3; index++) {
someArray1.map(
async function(cval, c_index, c_array) {
c_array.reverse();
});
}

// print array contents & debug info
for (var i = 0; i < someArray1.length; i++) {
print(i);
print(someArray1[i].toString());
}
print(describeArray(someArray1))

这个脚本(poc.js)会间歇性地演示一些异常行为,我们认为是因fuzzing线束所捕获的原始JSC的崩溃引起的。

通过多次运行JSC测试用例后,我们观察到了令人费解的现象,其中一些JSPromise对象可以随机存储在someArray1中:



(针对JSC的调试版本测试最小化的PoC)


这绝不应该发生。someArray1应该只包含在我们最小化测试用例的第一步创建的JSArrays中。这里发生了一些严重错误。

结论

评估任何足够大的软件的安全漏洞本质上是一项艰巨的任务。在这篇文章中,我们讨论了研究目标,缩小范围以及将定制工具作为基本方法来对付复杂的评估过程。

在我们的下一篇博文中,我们将详细介绍如何使用高级调试技术对我们缩小后的可疑测试用例(JSC错误)进行根本原因的分析(RCA)。根据我们对潜在问题的理解,我们可以得出关于其准确的安全影响的结论。

翻 译:看雪翻译小组 Logdty

校 对:看雪翻译小组 sudozhange

(感谢校对人员的仔细校对)


[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

最后于 2019-1-28 13:04 被admin编辑 ,原因:
收藏
点赞1
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回