模糊测试(fuzz testing)是一种自动化的软件测试技术,通常用于识别程序中的潜在漏洞。其概念最早由威斯康辛大学的巴顿·米勒于1989年提出。AFL是一种fuzz方法,目前广泛使用在模糊测试中。本篇博客介绍了使用模糊测试的目的,以及AFL实现模糊测试的原理,并依据案例具体实现AFL。
我们为什么需要fuzz
经常使用microsoft word的人知道,虽然microsoft word已经是一款十分成熟的软件,但是依旧存在大量能够使 Microsoft Word 崩溃的坏文件。极端条件下,少数字节错位,会使整个应用程序毁于一旦。在旧式的、无内存保护的操作系统中,整个计算机通常就这样宕掉了。 这种情况下Microsoft Word 不能意识到它接收到了坏的数据,并发出一条错误信息,并且仅仅因为少数字节损坏Microsoft Word 就破坏自己的栈、堆,甚至于影响了整个操作系统。发生在microsoft word上的报错事实上也发生在许多其他软件中,因为错误的输入导致系统坏掉是令软件开发者头痛的事情,开发者需要知道哪些输入会带来系统毁灭性的打击。
在模糊测试中,用随机坏数据(也称做 fuzz)攻击一个程序,然后等着观察哪里遭到了破坏。模糊测试的技巧在于,它是不符合逻辑的:自动模糊测试不去猜测哪个数据会导致破坏(就像人工测试员那样),而是将尽可能多的杂乱数据投入程序中。由这个测试验证过的失败模式通常对程序员来说是个彻底的震撼,因为任何按逻辑思考的人都不会想到这种失败。
模糊测试是一项简单的技术,但它却能揭示出程序中的重要 bug。它能够验证出现实世界中的错误模式并在您的软件发货前对潜在的应当被堵塞的攻击渠道进行提示。
fuzz方法分类
现阶段fuzz方法可以分成3类:
- 黑盒模糊测试:黑盒测试又称为功能测试,主要检测软件的每一个功能是否能够正常使用。在测试过程中,将程序看成不能打开的黑盒不考虑程序内部结构和特性的基础上通过程序接口进行测试,检查程序功能是否按照设计需求以及说明书的规定能够正常打开使用。
- 白盒模糊测试:白盒测试也称为结构测试,主要应用于单元测试阶段,检测软件编码过程中的错误。程序员的编程经验、对编程软件的掌握程度、工作状态等因素都会影响到编程质量,导致代码错误。
- 灰盒模糊测试:是介于白盒测试与黑盒测试之间的一种测试,灰盒测试多用于集成测试阶段,不仅关注输出、输入的正确性,同时也关注程序内部的情况。灰盒测试不像白盒那样详细、完整,但又比黑盒测试更关注程序的内部逻辑,常常是通过一些表征性的现象、事件、标志来判断内部的运行状态。
黑盒模糊测试和白盒模糊测试的优点与缺点列举如下:
测试方法 | 黑盒测试 | 白盒测试 |
---|---|---|
优点 |
|
|
缺点 |
|
|
AFL进行fuzz的过程
AFL(American Fuzzy Lop)是由安全研究员Micha? Zalewski开发的一款基于覆盖引导(Coverage-guided)的模糊测试工具,它通过记录输入样本的代码覆盖率,从而调整输入样本以提高覆盖率,增加发现漏洞的概率。
AFL的具体实现包括下面几步:
- 从源码编译程序时进行插桩,以记录代码覆盖率(Code Coverage);
- 选择一些输入文件,作为初始测试集加入输入队列(queue);
- 将队列中的文件按一定的策略进行“突变”;
- 如果经过变异文件更新了覆盖范围,则将其保留添加到队列中;
- 上述过程会一直循环进行,期间触发了crash的文件会被记录下来。
AFLCC实现fuzz测试
环境设置
# set up env
docker pull aflplusplus/aflplusplus
docker run -ti -v /location/of/your/target:/src aflplusplus/aflplusplus
docker exec -it [container_id] /bin/bash # enter the container
mkdir my_test
cd my_test
mkdir fuzz_in # for input file
mkdir fuzz_out # for output file
my_test作为工作路径,其中应该包括:afl_test.c, fuzz_in文件夹和fuzz_out文件夹。
afl_test.c
#include <stdio.h>
int main(int argc, char *argv[])
{
char buf[10]={
0};
gets(buf);//存在栈溢出漏洞
printf(buf);//存在格式化字符串漏洞
return 0;
}
/my_test/fuzz_in/testcase
asdfaslkx
编译和测试
afl-gcc -g -o afl_test afl_test.c # compile, which will procuce file: afl_test
afl-fuzz -i fuzz_in -o fuzz_out ./afl_test # try afl fuzz test
正确运行后,fuzz_out
文件夹中应该有产生新的文件,并有如图结果:
️afl-fuzz
程序不会自己停止,需要人为暂停。暂停的时间如何选择:
- 查看
cycles done
字段:其颜色会随着数值增加从洋红色到黄色、蓝色和绿色,一般到了绿色就可以停止了,此时即便继续测试也没有什么收获。 - 查看
last saved crash
字段:如果距离上一次查到崩溃点已经过去很长时间了,则无需继续进行测试。
结果解读
- process timing: 当前afl进行了多长时间,距离上一次crash多长时间
- overall results: 总体的结果,出现了多少次crash和hang
- cycle progress: 输入队列的距离
- map coverage: 目标二进制文件中的插桩代码所观察到覆盖范围的细节
- stage progress:Fuzzer现在正在执行的文件变异策略、执行次数和执行速度
- findings in depth:有关我们找到的执行路径,异常和挂起数量的信息
- fuzzing strategy yields:关于突变策略产生的最新行为和结果的详细信息
- item geometry:有关Fuzzer找到的执行路径的信息
在fuzz_out
文件夹会生成crashes
、hangs
和queue
三个文件夹,会存储程序坏掉的情况,过慢的情况,以及测试队列的有关信息。
文章评论