论文学习_Grey-Box Concolic Testing on Binary Code

摘要:我们提出灰盒混合测试技术------一种结合白盒与灰盒模糊测试优势的新型基于路径的测试用例生成方法。从宏观上看,该技术像白盒模糊测试(即混合测试)那样系统化探索被测程序的执行路径,同时保持了灰盒模糊测试的简洁性:仅使用轻量级插桩,且不依赖SMT求解器。我们在名为Eclipser的系统中实现了该技术,并将其与先进灰盒模糊测试工具(包括AFLFast、LAF-intel、Steelix和VUzzer)以及符号执行器KLEE进行对比。实验结果表明,我们的方法在代码覆盖率和漏洞发现数量上均优于其他工具。

引言

模糊测试已成为发现闭源二进制代码安全漏洞的事实标准。安全从业者青睐模糊测试是因为其总能发现附带验证证据的漏洞。微软和谷歌等大型软件公司现已在其软件开发生命周期中采用模糊测试作为确保产品安全的重要手段。

尤为显著的是,以AFL、AFLFast、Steelix、VUzzer、Angora、CollAFL和T-Fuzz为代表的灰盒模糊测试工具正成为漏洞发现领域的前沿技术。灰盒模糊测试通过进化过程生成测试用例,具体而言:它执行测试用例并根据适应度函数进行评估,随后优先选择适应度更优的用例,通过进化操作寻找满足目标的测试用例,并持续迭代整个过程以期触发导致程序崩溃的缺陷路径。现有灰盒模糊测试工具采用代码覆盖率作为适应度函数,因此有时被称为基于覆盖率的模糊测试工具。例如,AFL及其后续改进工具采用近似分支覆盖率,而VUzzer则使用加权基本块命中计数作为适应度函数。显然,通过最大化代码覆盖率能够增加触发被测程序关键执行路径的可能性。

然而,现有灰盒模糊测试工具即使在基于覆盖率的引导下,仍难以有效探索新分支,因为代码覆盖率对输入变异的敏感度不足。具体而言,两个不同输入的程序执行可能获得相同的代码覆盖率,即使它们在条件分支处的比较数值存在差异。换言之,代码覆盖率仅能在条件分支被随机生成输入穿透时提供反馈,但无法直接帮助生成此类输入。这种敏感度缺失导致灰盒模糊测试工具在某些场景下难以生成高覆盖率测试用例,例如当被测程序将输入与特定魔数值进行比较时。即使当前最先进的灰盒模糊测试工具如AFLGo、Steelix和VUzzer也在不同程度上存在相同问题。

因此,尽管灰盒模糊测试在漏洞发现方面表现卓越,但学界普遍认为其无法作为唯一的测试用例生成算法。为此,灰盒模糊测试工具常需辅以高成本的白盒分析技术(如动态符号执行与细粒度污点分析)或通过提供初始种子输入来引导测试用例生成过程。例如,Angora和Driller分别通过细粒度污点分析与动态符号执行来提升灰盒模糊测试的代码覆盖率。

与此同时,白盒模糊测试(亦称动态符号执行或混合测试)虽能通过求解分支条件系统化生成测试用例,但其根本上受限于可扩展性问题(暂不论经典路径爆炸问题)。首先,白盒模糊测试工具需分析被测程序的每条指令,由于对每条指令进行插桩,每次模糊测试迭代都会产生可观的计算开销。其次,符号执行为每条执行路径构建符号化路径约束,通过SMT求解器求解此类约束计算代价高昂。此外,为受符号输入影响的每个内存单元存储符号表达式需要占用大量内存空间。

本文提出一种称为灰盒混合测试的新型测试用例生成技术,并在名为Eclipser的工具中实现。灰盒混合测试能像白盒模糊测试那样高效生成满足分支条件的测试用例,同时保持技术简洁性:不依赖高开销的程序分析技术。因此,它能够像灰盒模糊测试那样扩展到真实应用程序的测试场景。我们的方法类似于白盒模糊测试中广泛使用的代际搜索策略------通过单次程序执行过程中解析所有遇到的条件分支来生成一代测试用例。灰盒混合测试同样执行基于路径的测试用例生成,但它以灰盒方式解析条件分支:通过插桩被测程序并观察其执行行为来生成测试用例。灰盒混合测试与白盒模糊测试的关键区别在于,我们的方法依赖于近似形式的路径约束,这类约束部分描述了触发被测程序各执行路径的输入条件。近似路径约束帮助我们在无需依赖CPU或内存密集型操作(如SMT求解)的情况下,找到能够穿透条件分支的输入。虽然灰盒混合测试生成的路径约束本质上不够精确,但实践中其精度足以快速探索多样化的执行路径。此处的核心设计决策是以精度换取简洁性。

诚然,精度缺失会导致对被测程序路径探索的不完整性,但Eclipser通过交替执行灰盒混合测试与经典灰盒模糊测试(如Driller的设计)来弥补这一缺陷。即使灰盒混合测试未能完全覆盖被测程序的所有条件分支,灰盒模糊测试模块仍会持续探索新路径与分支,反之亦然。我们发现实践中这种设计决策使Eclipser在漏洞发现与代码覆盖率方面,有效超越了当前最先进的灰盒与白盒模糊测试工具的能力边界。我们针对当前先进模糊测试工具对Eclipser进行了评估。通过将本系统与以源代码生成高覆盖率测试用例见长的先进符号执行器KLEE进行对比实验,验证了Eclipser作为测试用例生成工具的实用性。实验结果显示,在无需SMT求解器辅助的情况下,Eclipser于广泛用于测试用例生成算法评估的基准套件GNU coreutils上,实现了比KLEE高出8.57%的代码覆盖率。

研究背景

灰盒模糊测试介绍

模糊测试本质上是通过生成的测试用例反复执行被测程序的过程。灰盒模糊测试在反馈循环中进化测试用例,该循环通过称为适应度函数的标准来评估每个测试用例执行被测程序的效果。尽管具体实现存在差异,但大多数灰盒模糊测试工具采用代码覆盖率作为适应度函数。例如,AFL使用分支覆盖率(含一定噪声)来决定下一步应对哪个输入进行模糊测试。

尽管基于覆盖率的灰盒模糊测试近期取得成功,但其存在一个主要缺陷:模糊测试过程需要过多不必要的尝试才能找到触发特定分支的测试用例。这主要归因于所用适应度函数的敏感度不足。非正式地说,若输入值的微小修改能轻易改变适应度值,则该适应度函数是敏感的。而节点覆盖率、分支覆盖率等代码覆盖率度量指标均不敏感,因为覆盖真分支与假分支的两次执行之间不存在中间适应度值。因此,寻找能够翻转给定分支条件的输入变得十分困难。

在基于搜索的软件测试领域,敏感适应度函数的必要性已获得广泛认可------该领域将测试用例生成视为优化问题。分支距离是其中著名的适应度函数,它衡量条件分支操作数值之间的距离。模糊测试领域近期开始采用这一理念:Angora利用分支距离提升测试性能。Eclipser借鉴了相似思路,但利用敏感度直接推断并求解近似分支条件。这两种方法相互正交且互为补充。

研究动机

复制代码
1 int vulnfunc(int32_t intInput, char * strInput) {
2     if (2 * intInput + 1 == 31337)
3         if (strcmp(strInput, "Bad!") == 0)
4             crash();
5 }
6 int main(int argc, char* argv[]) {
7     char buf[9];
8     int fd = open(argv[1], O_RDONLY);
9     read(fd, buf, sizeof(buf) - 1);
10     buf[8] = 0;
11     vulnfunc(*((int32_t*) &buf[0]), &buf[4]);
12     return 0;
13 }

我们的系统直接处理原始二进制可执行文件,但为便于解释使用C语言表示。该程序接收文件作为输入,将文件前4字节作为整数,后4字节通过末尾添加空字符转换为5字节字符串(第10行)。这两个值作为参数传递给vulnfunc函数。为触发第4行的崩溃,需要向该函数提供整数值15,668和字符串"Bad!"作为输入。当前灰盒模糊测试工具能否发现触发此崩溃的测试输入?灰盒模糊测试工具对这类简单漏洞的发现效果如何?为回答这些问题,我们在Intel Xeon E3-1231 v3处理器(3.40 GHz)单核上,分别使用6种先进模糊测试工具及Eclipser对示例程序进行各1小时的模糊测试。我们选取了四种开源灰盒模糊测试工具(AFL、AFLFast、AFLGo和LAF-intel),同时选择了主流符号执行器(即白盒模糊测试工具)KLEE。需注意部分工具(KLEE、LAF-intel和AFLGo)仅能操作源代码,因此我们使用源代码运行这些工具,而对其他工具则使用编译后的二进制文件运行。为运行AFLGo,我们将第4行作为目标位置为其提供引导。

除LAF-intel外,所有灰盒模糊测试工具均未能发现触发漏洞的测试用例。LAF-intel之所以成功,是因为它将多字节比较语句分解为多个单字节比较,这有效提升了代码覆盖率指标对输入变异的敏感度。但需注意,即使采用开销较低的源码级插桩,LAF-intel发现漏洞的速度仍比Eclipser慢671倍。值得注意的是,该结果甚至可与KLEE相媲美:Eclipser发现漏洞的速度虽比KLEE慢两倍,但Eclipser直接运行于二进制代码,而KLEE需要源代码。此外,符号执行在遇到更多条件分支时会因SMT求解而迅速变慢,而复杂路径条件对Eclipser的性能影响较小。实际上,如第五-C节所述,Eclipser在GNU coreutils上实现了比KLEE更高的代码覆盖率,第五-E节也证明Eclipser能够扩展到处理大型真实应用程序。此示例凸显了灰盒混合测试的潜力。虽然我们的技术牺牲了白盒模糊测试的精确性,但它能快速生成测试用例以探索被测程序不同的执行路径,且不依赖任何高开销分析。

研究内容

灰盒混合测试是一种从给定种子输入生成测试用例的方法。从宏观上看,其行为类似于采用代际搜索策略的动态符号执行------通过种子输入执行被测程序时,通过扩展执行路径中所有可行的分支条件来生成一代测试用例。灰盒混合测试以类似方式运行,但选择性地求解路径中遇到的分支条件,且不依赖SMT求解。我们方法的核心是为种子的每个输入字节维护近似路径约束的独立子集。这些约束有助于生成不同的测试用例,通过求解约束可驱动被测程序执行相同(或相似)的执行路径。利用这些测试用例,我们观察到路径中某些条件分支虽采取相同执行路径,却对不同的输入值进行比较。我们运用这种执行行为以灰盒方式穿透条件分支。我们的技术能像白盒模糊测试(即混合测试)那样有效解析分支条件,同时保持系统如灰盒模糊测试般的轻量与可扩展性。

相关推荐
西岸行者4 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意4 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码5 天前
嵌入式学习路线
学习
毛小茛5 天前
计算机系统概论——校验码
学习
babe小鑫5 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms5 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下5 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。5 天前
2026.2.25监控学习
学习
im_AMBER5 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J5 天前
从“Hello World“ 开始 C++
c语言·c++·学习