20199118 2019-2020-2 《网络攻防实践》综合实践

1.论文分析

CCS‘ 17 Designing New Operating Primitives to Improve Fuzzing Performance

①论文摘要
  • 模糊化是一种软件测试技术,通过重复地将突变的输入注入目标程序来发现错误。众所周知,模糊化是一种高度实用的方法,它比以往更受欢迎。目前对引信的研究主要集中在产生更容易引发漏洞的输入,本文提出了另一种提高引信性能的方法,即缩短引信的执行时间。我们观察到,由于文件系统争用以及在120个核上并行运行时work()系统调用的可伸缩性,AFL(一种最先进的模糊器)的速度降低了24倍。其他引信也会受到同样的可伸缩性瓶颈的影响,因为它们遵循类似的设计模式。为了提高引信性能,我们设计并实现了三种新的专门用于引信的操作原语,解决了这些性能瓶颈,并在多核机器上实现了可扩展的性能。我们的实验表明,当以120核为目标的google'sfuzzer测试套件时,所提出的原语分别将afl和libfuzzer的速度提高了6.1到28.9倍和1.1到735.7倍。此外,Primitives还将EAFL的吞吐量提高到7.7×30核,这在数据中心更为常见。我们的引信不可知论原语可以很容易地应用于任何具有基本性能改进的引信,直接受益于大规模的引信和基于云的引信服务。
②论文介绍
  • 攻击者利用漏洞完全或部分控制用户设备或实现用户隐私。从恶意攻击来看,实施和使用流行软件和操作系统内核的各种金融组织和社区都投入了大量精力来查找和修复红外产品中的安全漏洞,而在应用程序和库中查找漏洞的一项努力则是模糊的。模糊化是一种软件测试技术,通过向目标程序注入随机变异的输入来工作。与其他的漏洞发现技术相比,模糊技术的一个主要优点是,它可以在较少的人工操作和对目标软件的预先了解的情况下确保高穿透性,并且是在各种关键软件中发现漏洞的最实用方法之一。例如,ARTCoverage驱动的引信(American Fuzzy Lop,AFL)在开源软件中发现了上千个漏洞。不仅如此,甚至谷歌Chrome的安全性也很大程度上依赖于其模糊的基础结构,即clusterfuzz[3,20]。例如,clusterfuzz是一个分布式框架结构,由数百个虚拟机组成,每天处理5000万个测试用例。最近公布的doss-fuzz[22]是谷歌致力于使开源软件更安全的一项工作,它也由clusterfuzz提供支持,clusterfuzz平均每天处理10万亿次输入测试,并在5个月内发现了1000多个漏洞[14]。除了谷歌,微软还提出了SpringField项目[31],该项目为开发人员提供基于云的模糊服务,以便在他们的软件中发现安全漏洞。这一运动清楚地表明,大规模引信正在得到普及[1,25],通过观察复杂的软件栈和操作系统,引信的性能至关重要。换句话说,一个更好的模糊器比其他的模糊器更快地攻击目标程序中更多的安全漏洞。解决这个问题有两个广泛的研究方向:1)产生一个更容易触发漏洞的输入(即,达到错误所需的时间更短);2)缩短每个迭代的执行时间(即,在给定时间内覆盖更多)。先前的研究主要集中在第一种方法。特别是,覆盖驱动引信[21,29,41]通过目标程序的运行时覆盖率来评估测试用例,然后尝试生成可能覆盖未接触分支的测试用例。更先进的技术包括进化技术[12,34]、无条理模型(如马尔可夫链[7]),或将模糊与符号执行相结合[13,27,36]。然而,缩短每一次模糊迭代的执行时间也带来了巨大的好处。这种方法减少了在给定模糊策略的情况下发现新错误的时间。如今,由于其内部的复杂性和安全缓解措施,要找到流行软件中可利用的漏洞,需要几天、几周甚至几个月的时间。因此对性能有很大的不同,从而节省了大量的模糊操作人员。

在本文中,做出了以下贡献:

  • 我们识别和分析了三个主要的性能机器人瓶颈,这些瓶颈源于大规模的模糊化,它们是由现有的操作原语的密集使用造成的,这些原语只适用于一般用途。
  • 我们设计并实现了三种新的特定于引信的操作原语,可以提高多核机中最先进的引信的性能和可扩展性。
  • 我们应用并评估了我们提出的操作原语。通过利用我们提出的策略,AFL对每秒30、60和120核的执行次数分别提高了7.7倍、25.9倍和28.9倍。与此同时,libfuzzercan在30、60和120核心上的速度分别提高了170.5倍、134.9倍和735.7倍。

  • ①将候选测试用例从自己/他人的输出目录读取/同步到一个缓冲区中,并为新的输入转换缓冲区,并将其馈送到目标进程;
  • ②分叉子进程,以跟踪位图中记录的有效路径执行程序;
  • ③等待子进程终止TE并返回其退出状态;
  • ④如果通过观察共享跟踪位图来覆盖新路径,则将生成的输入保存到输出目录中;
  • ⑤重复此模糊过程;
  • ⑥在多核系统上,每个轴都独立并行运行。
②论文背景
* 首先描述现代引信的工作方式,然后解释引信所依赖的操作原语是如何和为什么成为关键的可扩展性瓶颈。

模糊解释:

  • 模糊化是一种广泛应用的软件测试技术,用于查找不适用的缺陷。它通过向目标程序注入随机变化的输入来测试软件,并监视目标的行为是否异常(例如,崩溃、跟踪、挂起或断言失败)。触发异常行为的输入报告为潜在错误。

  • 为了快速检测bug,各种技术被提议通过智能策略明智地改变输入,并有效地探索程序状态。特别是,流行的模糊器,比如使用过去的代码覆盖率来确定当前的变化输入是否有趣,并将其用作下一次执行的反馈。为了获得覆盖率信息,模糊器需要检测系统仿真层。通常,模糊器从一组种子输入开始,运行目标程序,并根据过去执行的反馈(例如覆盖率或崩溃)改变输入。整个过程被称为模糊循环,模糊器可以在一定的时间内迭代,或者直到达到饱和点。

  • 模糊回路包括以下步骤:

    • ①将具有最高优先级的测试用例(或输入)从一个磁盘加载到内存缓冲区。
    • ②通过随机修改输入中的确定字节或将随机字节添加到输入的末尾来改变缓冲的输入。
    • ③使用新生成的输入启动目标应用程序,并监视其运行时执行。
    • ④如果测试用例很有趣,将磁盘的输入保存为新的测试用例,以便在连续运行中(例如,探索新的分支)进行进一步的变异。
    • ⑤对另一个模糊迭代重复步骤①。

AFL设计:

  • AFL是最先进的引信,它发现了许多重要的安全漏洞的非平凡的,现实世界的软件。现在,本文将重点介绍法兰的具体设计,以及其设计考虑多核系统的性能和可扩展性。
    总体设计和工作流程:

    • ①可变输入
    • ②启动目标应用程序
    • ③记账结果
    • ④平行模糊
  • 可扩展模糊的危险:在模糊循环中,模糊器使用几个操作系统原语,当缩放模糊器以并行运行多个实例时,这些原语开始成为性能瓶颈,导致端到端性能比单个模糊度差。本文详细介绍了引信过程每个阶段的潜在系统瓶颈。

AFL的可扩展性:

  • 为了评估这些瓶颈的影响,我们设计了RANAFL,这是一种最先进的模糊器,通过将核心数量从1到120变化来模糊libjpeg库、JPEG解压器。
  • 下图显示了模糊库的执行次数,这表明flis的可伸缩性非常差。执行次数在15个核心处饱和,在120个核心处完全崩溃。考虑到数据中心中的典型服务器是一台具有32或64核的2或4插槽机器,当前最先进的引信无法充分利用典型服务器。

  • 作者的主要工作:

    • ①目前对引信的研究主要集中在产生更容易引发漏洞的输入,本文提出了另一种提高引信性能的方法,即缩短引信的执行时间。
    • ②为了提高引信性能,设计并实现了三种新的专门用于引信的操作原语,解决了这些性能瓶颈,并在多核机器上实现了可扩展的性能。
    • ③操作原语还将EAFL的吞吐量提高到7.7×30核。
  • 提出了一个新的系统调用snapshot(),它是一个轻量级的、可伸缩的、替代了模糊化。下图 Illustrates是一个如何使用快照系统调用的简化示例。Snapshot()创建进程的快照之后,进程可以继续执行。根据请求,snapshot()将进程的状态恢复为快照状态。其原型如下:

2.操作原语设计

快照系统调用:
  • 命令是指“抓拍”,在快照时,用户可以注册一个回调函数、回调和一个共享地址范围的向量,共享的回调操作系统应该保持完整。例如,在模糊处理的情况下,shared_addrin指示模糊处理和目标处理之间共享的跟踪位图。当快照过程终止时,操作系统将调用注册的回调函数。目前,我们不支持嵌套的快照。Snapshot比Fork更轻、更可伸缩。它甚至比pthread_create有更好的性能,因为它不需要分配和释放线程堆栈,而pthread_create需要线程堆栈。

  • 模糊化上下文中,作者将一个完整的模糊测试分为三个阶段,描述快照在不同阶段如何与内核和目标进程协作。

    • ①在作者的设计中,在执行任何模糊运行之前,首先需要保存用户空间执行上下文,或者具体地说,保存所有当前寄存器值和信号掩码。然后它进入一个循环,继续等待来自Fuzzer实例的新的模糊请求。在接收到请求时,进程使用快照保留其内核上下文(beg_snapshot)并注册回调函数:callback()。这个用户回调函数作为每一个模糊执行的结尾,稍后我们将更详细地描述它。

    • ②模糊化过程中:要求页复制,目标进程在返回快照后,继续使用运行时参数和环境变量执行其真正的主函数,当目标应用程序运行时,由于我们对页权限的只读修改,每个内存写操作(在页边界处)都会触发一个页错误。如之前所述,适用于任何可写页面。在我们修改的页面错误处理程序中,我们首先检查错误地址是否在最初的快照页面中。如果是这种情况,那么页面数据的副本将被修改并链接到具有额外写入权限的相应PTE。对于没有相应物理页面的未分配页面,我们只需要安装新页面,并使用额外的写入权限更新相应的PTE。最后,我们刷新TLB条目以保持一致性。

    • ③在模糊化之后:快照恢复。在终止快照进程之前,我们调用注册回调函数。在正常终止的情况下,即从main()返回,它首先将退出状态通知其父进程,即控制引信实例。为了处理targetprocess callssexit()终止的情况,我们修改了sys_exit_group的entry函数,并检查进程是否快照。如果是这样,它会调用用户空间中注册的回调函数。另一方面,如果目标进程在执行的中间超时或崩溃,它将收到相应的信号,在默认情况下终止受害者进程。为了将异常状态通知给父进程并避免重新创建目标进程,我们的插入指令注册了一个特定的处理程序,用于每次注册时的每个关键信号。

双文件系统服务:
  • 作者引入了第二个操作原语双文件系统服务,为模糊化提供高效、可扩展的文件操作,其核心思想是利用Neithera Fuzzer实例和目标实例都需要这样一个强大的一致性模型。只有Fuzzer实例需要一致性,以便将突变状态序列化到持久存储中以获得持久性。在意外故障(例如电源或系统崩溃)时,预计测试用例会丢失,但Fuzzer始终可以在可接受的时间段内复制它们。新的文件系统服务提供了文件系统的两级分层:一个内存文件系统,另一个磁盘文件系统。

  • 在引信之间有效地共享测试用例信息(如文件名和跟踪位图)的共享内存测试用例日志示例。通过共享测试用例信息,模糊器可以判断其他模糊器创建的测试用例是否有用,而无需重新执行测试用例或重新枚举测试用例目录。从概念上讲,测试用例日志是一个固定大小的循环日志,支持push()和pop()操作。与传统的循环日志不同,一旦所有迷糊器执行mpop()操作,就会从日志中删除元素。

共享内存测试用例日志
  • 引入了一个共享内存测试用例日志来实现真正的协作模糊化,而不需要任何开销。测试用例日志是一个固定大小的内存循环日志,它帮助模糊器有效地管理和共享生成的测试用例。每个测试用例日志都由主模糊器实例创建和控制。同时,任何其他实例都可以作为从服务器访问日志。日志的每个元素存储测试用例的信息,包括其文件名、大小、哈希值和跟踪位图。与传统的循环队列一样,我们的测试用例日志维护也需要。只允许master将新元素推送到日志头中。注意,与传统的循环队列不同,任何连接到log canperformpop()以获取最旧元素的从属队列。每个从机维护其localtail(taili)。一旦所有的奴隶都弹出最古老的元素,我们就把全球铁路向前移动一个。对于可伸缩性,测试用例日志是以无锁方式进行反签名的。此外,即使过程确实在运行,我们的固定大小的设计保证了内存的绑定。
最先进的定标引信:
  • 遵循模糊循环的所有应用程序模糊器都可以从至少一个操作原语中获益。下表总结了这些原则在最近几年开发的10种已知的开源引信上的适用性。作者首先解释了这3种操作原则如何普遍提高应用引信的性能。其中,美国AFL和LibFuzzer两种典型的引信被广泛使用并成功地发现了大量的缺陷。它们也为许多后来的研究工作和模糊7奠定了基础。

  • 共享内存测试用例日志界面概述。应用模糊器可以利用这些接口在运行实例之间共享测试用例,实现可扩展的协同模糊。模糊器实例调用push test case()以将其生成的测试用例的元数据(例如,文件名、跟踪位图)保存到其测试用例日志中,并调用epop testcase()以引用其他模糊器实例生成的测试用例的信息。因此,不再需要目录枚举和测试用例重新执行。

3.实验与评估

  • 在Linux v4.8.10上实现并应用了作者的设计决策。我们为模糊器实现了一个新的x86_64系统快照,以克隆目标程序的一个实例。它支持快照运行进程的内存和其他系统状态,并将快照进程回滚到其原始状态。快照的系统调用号为329,它的实现涉及750行代码(loc),引入linux内核。快照还需要进行页面故障处理过程的协作。NEL以便在模糊运行期间跟踪内存更新。我们还修改了内核中用户进程的退出和信号处理例程,以防止快照在运行时意外终止,同时确保进程在不在快照中的情况下能够以预期的方式正常处理这些信号。这些变化涉及到内核源代码中不同位置的大约100个loc散射,我们还开发了一个库,其中包含大约100个loc的共享内存测试用例日志的6个接口。特别是,测试用例日志是作为Linux中的/dev/shmutility支持的posix共享内存对象来实现的。此外,我们还编写了一个100 loc的简单双文件系统服务守护程序,它可以由模糊器为分区上的私有工作目录启动,并定期刷新测试用例。

  • 下图显示了原始版本和我们优化版本的flby每秒执行次数模糊了谷歌的模糊器测试套件plus libjpeg 1到120核。在相应的情况下,从90个核开始,每个模糊实例都超时,这导致没有进一步的执行,因为没有有效的输入测试案例用于由于AFL的库存版本中存在严重的性能瓶颈而导致的突变。

  • 下图显示了LibFuzzer在1到120核上模糊Google的模糊器测试套件的原始版本和优化版本的每秒执行次数。

  • 根据执行次数和模糊LibFuzzer所花费的时间来评估共享内存测试用例日志。下图显示了新执行的数量和在同步阶段花费的时间百分比。

  • 对oursnapshot()系统调用againstfork()系统调用和pthread_create()函数的计算。下图显示了模糊LibFuzzer时impactofsnapshot()系统调用。下图显示了用于创建新进程的所有原语的可伸缩性,以及优化数据库,同时模糊LibFuzzer。

  • 下图反应文件系统对该文优化版本的LibFuzzer的影响。

4.结论

  • 在不同的组织和社区中,模糊化是发现几种安全性bug的关键工具之一。然而,随着越来越多的代码库和微小的错误消失在空气中,模糊现在花费数天、数周甚至数月的时间来发现关键的错误,这不仅需要大量的计算资源,而且会导致货币支出。到目前为止,以前的工作只专注于生成有趣的输入测试用例来快速发现新的bug,但是从系统的角度来说已经放弃了设计方面的工作。在这项工作中,我们仔细研究和概述了两种最先进的引信的各个组成部分及其与操作系统的相互作用,发现了三个设计缺陷,我们解决了两种引信:AFL和LibFuzzer。利用我们提出的操作原语,在每秒30、60和120个核上的执行次数分别提高了7.7倍、25.9倍和28.9倍。同时,LibFuzzer在30、60和120核上的速度分别提高了170.5倍、134.9倍和735.7倍。

5.改进

①适用的引信:我们只分析和改进了一般应用程序模糊器的性能和可扩展性,这些模糊器可以用具体的输入值来处理目标。我们的操作原语可能对许多其他模糊工具带来的好处较小,这些模糊工具主要用于符号执行、污染分析或指令模拟,以发现安全漏洞。操作系统核心引信也是超范围的,这些引信可能存在不同的性能瓶颈,需要相应的解决方案。

②跨平台实施:我们在Linux平台上实现了设计选择的工作原型。然而,由于MacOS和Windows应用程序的流行,对在它们中查找错误的需求更大。我们将在不久的将来把我们的实现移植到这两个平台上。

6.学习感悟、思考等

  • 通过对顶会论文的学习分析加深了对网络攻防技术的认识,理论与实践相结合,提高了自己对使用网络攻防技术的能力。
  • 培养了实践学习的能力,对网络攻防的实际运用产生了极大的兴趣。

参考资料

posted @ 2020-07-04 15:36  陈剑源  阅读(302)  评论(0编辑  收藏  举报