基于导向性漏洞挖掘的优化策略
2021-05-07金童
金童
(北方工业大学,北京 100144)
0 引言
模糊测试是一种基于缺陷注入的自动化软件漏洞挖掘技术通过向待测试的目标软件输入测试用例并执行程序,监控程序的运行状况,同时记录并进一步分析目标程序发生的异常,进而通过分析造成目标程序崩溃的测试用例来发现目标程序潜在的漏洞。
在模糊测试的过程中,测试用例执行、异常监视这两个重要的过程完全可以自动化实现。
模糊测试在挖掘的漏洞数量方面具有很大优势,与此同时,其不足也十分明显。比如:对访问控制漏洞无能为力、无法发现糟糕的设计逻辑、无法识别多阶段安全漏洞和无法识别多点触发漏洞。
模糊测试的高效性严格依赖输入测试样本的质量,因此模糊测试的核心就是核心测试样本的生成,其有两个关键点:(1)优质的测试样本种子;(2)合理的畸变策略。针对第(1)个关键点,以目标为导向选择确定优质测试样本种子,比如:能够发现未执行过的路径或者执行率较低的路径;向某个特定待测试区域不断逼近等。
目前常用的漏洞挖掘技术分为静态分析、动态分析、二进制比对、模糊测试等。静态分析是指在不运行软件的前提下进行的一种分析技术。其主要通过对目标程序的词法、语法、语义分析来发现软件中潜在的安全漏洞,特别是函数调用中参数的来源以及函数返回值,通过对参数进行来源分析与跟踪,很容易发现其中未对参数进行边界检查而造成的缓冲区溢出、堆溢出等类型的安全漏洞。动态分析是一种通过动态加载并运行的目标软件,监测程序运行时的堆栈信息、内存使用情况、变量的值等状态信息以及程序的输出来验证或发现软件漏洞的技术。二进制比对也称为补丁比对。作为软件安全漏洞的补救措施,软件开发商会定期或不定期地提供相应的修补程序即补丁。模糊测试是一种基于缺陷注入的自动化软件漏洞挖掘技术,其基本思想与黑盒测试类似。模糊测试通过向待测试的目标软件输入一些半随机的数据并执行程序,监控程序的运行状况,同时记录并进一步分析目标程序发生的异常来发现潜在的漏洞。
在模糊测试的过程中,测试用例执行、异常监视这两个重要的过程完全可以自动化实现。而且,通过模糊测试技术发现的漏洞一般是真正存在的(原因是对半有效数据的处理不当),即模糊测试技术存在误报率低的优点。其他的漏洞挖掘方法往往需要对目标程序的源代码或二进制代码进行深入的分析,这是过程的开销巨大,而模糊测试并不需要对目标程序的源代码或二进制程序进行分析即可进行。
我们这次使用的就是模糊测试中的灰盒测试。灰盒测试使用轻量级工具来以可忽略的性能开销确定输入所执行的路径的唯一标识符。通过改变提供的种子输入来生成新输入,如果新输入使用了有趣的新路径,则会添加到模糊器的队列中。AFL负责发现数百个高影响力漏洞,已被证明可以“凭空”生成有效的测试文件,并且拥有大量的安全研究人员致力于扩展它。
AFLGO作为定向灰箱模糊器,重点关注用户定义的目标位置并进行优化,根据自定义的功率计算方法来生成更短距离的测试种子。此处,距离是根据输入种子执行轨迹上的基本块到目标基本块的平均权重计算的,其中权重由程序的调用图和过程内的控制流图进行的过程内分析得到,并且自定义的功率计算方法是基于模拟退火的。
在实际情况下,生成的大量输入无法让程序执行到目标,这极大地影响了模糊测试的效率。为了使模糊的效率更高,我们在AFLGO的基础上对种子筛选部分进行了优化,它可以更高效地找到导致程序崩溃的种子。我们使用一种前馈神经网络,这是一种高效且可扩展的程序平滑技术,该技术可以模拟程序的分支行为。并且可以使种子进行更为高效的突变,最终可以使模糊测试的效率进一步提升。
1 相关工作
按测试输入的不同种类进行划分,模糊测试的测试输入可分为基于变异和基于生成两种方式。其中,基于变异的模糊测试在修改已知测试输入的基础上生成新的测试用例,而基于生成的模糊测试则是直接在已知输入样本格式的基础上生成新的测试输入。
根据不同的研究侧重点,本章分别介绍基于变异的模糊测试、基于生成的模糊测试。
1.1 基于变异的模糊测试。
AFLFast[1]采用特定的策略引导AFL优先选择低频路径的文件作为种子文件进行变异,以此在相同的测试时间内探索更多的路径。AFLGo[2]采用了模拟退火算法对种子进行赋能操作,为更接近目标点的种子给予更多的能量,从而可以筛选出更为优质的种子,使得模糊测试的效率进一步提高。
1.2 基于生成的模糊测试
基于生成的模糊测试主要基于模型或者语法生成能满足程序语法和语义检查的测试输入,常用于高度结构化的测试输入生成。
图1 AFLGo模型图Fig.1 AFLGo model diagram
SeededFuzz[3]使用各种程序分析技术来促进初始种子的生成和选择,这有助于实现定向模糊的目标。配备改进的种子选择和生成技术,SeededFuzz可以到达更多关键站点并发现更多漏洞。
2 模型设计
当前的导向性模糊测试旨在生成可能到达特定错误代码的输入,进一步期望触发该错误。但是在模糊测试过程中,生成导致程序错误输入的效率却并不高。在有限的时间内生成尽可能多的可以导致程序崩溃的输入就作为下一步的研究目标。而且在模糊测试过程中目标程序的执行时间占最大比例,只有增加优质输入(可以导致程序崩溃的输入)的生成才能大大提高模糊测试的效率。如果存在一种足够快的方法来生成更多优质输入的方法,则在有限的时间就能找到更多有效的引起程序崩溃的种子。这样,可以提高模糊测试的整体性能。
AFLGo的模型如图1所示,主要由四个部分组成:图形提取器、距离计算器、运行器和模糊器。
(1)图提取器生成调用图和相关的控制流图。是作为AFL LLVM pass的扩展而实现的,它由编译器AFL clang fast激活。
(2)距离计算器利用调用图和每个过程内控制流计算每个基本块的进程间距离。DC被封装为一个Python脚本,它使用networkx包来解析图,并根据Djikstra的算法进行最短距离计算。DC生成BB距离文件,该文件包含每个基本块级目标距离。
(3)仪器获取BB距离文件,并在目标二进制文件中指示每个BB。对于每个BB,它确定各自的BB级目标距离并注入扩展的蹦汇编代码,在每个跳转指令之后执行,以跟踪覆盖的控制流边缘。对于每个基本块,AFLGo仪器添加汇编代码:1)加载当前累积距离并添加当前BB的目标距离,2)加载并增加已运行BB的数量,3)将两个值存储到共享内存中。
(4)Fuzzer根据我们加入样本种子快速收敛筛选算法的退火功率计划,并模糊化插入二进制文件。当前种子距离的计算方法是将累积的基本块距离除以训练基本块的数量。
我们基于退火的功率计划为“更接近”目标的种子分配了比“更远”的种子更多的能量,并且这种能量差随温度降低而增加。
在模糊测试的起始阶段,首先对种子进行距离测量,及种子到目标点的距离。该测量结果在进行检测时已经完全确定,并且在运行时可以有效地计算出来。我们的程序分析是基于调用图和程序内控制流图进行的过程内分析,这与过程间分析相比可以节省很多时间。
首先我们使用前馈神经网络来模拟复杂的程序分支行为,进行有效的梯度计算。我们通过使用经过AFLGo测试过一定时间后的测试输入语料库来训练神经网络。
随后我们使用梯度或高阶导数来实现更快的收敛性,平滑的神经网络模型一旦经过训练,便可以用于有效地计算梯度和高阶导数,然后可以利用它们来更快地收敛到最优解,也就是得到更为高效的种子。
3 方法
和AFLGo类似,我们定义了一种距离度量(即种子到目标位置),该度量在进行模糊时已完全确定,并且可以在运行时有效地计算出来。尽管我们的度量是过程间的,但我们的程序分析实际上是基于调用图和控制流图进行的过程内分析。与过程间分析相比,我们展示了如何产生二次储蓄。而且调用图和控制流图在LLVM编译器的基础结构中很容易得到。
使用这种新颖的距离度量,我们定义了一种新颖的功率方法,该方法集成了最流行的退火功能,即指数冷却计划。根据我们的距离测度,基于退火的功率计划逐渐将更多的能量分配给更接近目标位置的种子,同时减少更远的种子的能量。
最后,我们结合了一种新的方案平滑方法,它使用代理潜亏神经网络模型来学习和迭代地平滑逼近目标程序,目的就是通过观察到的程序行为来精炼目标程序。这样就可以替代神经网络可以平滑地延展到观察到的程序行为,同时还可以对潜在的非线性和非凸行为进行准确建模。
同时我们通过梯度计算方法实现了新的边缘覆盖,这样我们就可以在保留就数据的同时还可以触发新的分支,从而生成新的训练数据。再将新的数据和过滤掉的旧数据重新训练神经网络,这样就能有效的防止训练数据样本数量无休止的增加,大大增加了重新训练的次数。
4 实验
为了显示我们工具的有效性,我们评估了配备工具后的AFLGo和原始的AFLGo,使用LAVA-M中的4个程序uniq、md5sum、who、base64,对比其他工具的测试方法,大部分都是把测试时间都控制在了7天左右,所以我们也将用同样的时间测试数据,这样对比结果就具有很高的有效性。
所有实验和测量均在运行Ubuntu 16.04,具有8核CPU,16GB内存和2TB硬盘的64位服务器上进行的。根据实验结果,我们的工具可以将模糊测试的性能提高到AFLGo的1.5倍多。对比AFLGo本身,改进后模型的测试结果都要明显好于AFLGo,总漏洞数以及去重后的漏洞数量都比之前的数量要多得多。
5 结语
最近,导向型模糊测试可以有效地发现具有潜在已知位置的错误。为了提高模糊测试的效率,本文提出高效的样本种子快速收敛筛选算法以使模糊测试在更短的时间内可以找到更多的漏洞。并且我们是在AFLGo框架的基础上进行实现的,这样利于对比实验的进行,使结果更有说服力。对LAVA-M中4个程序测试的结果表明,我们的工具可以使速度提高多达1.5倍以上。