AFL(2)

简述

转载自:https://stfpeak.github.io/2017/06/12/AFL-Cautions/

上一篇文章介绍了AFL在业界的应用、安装以及简单的demo,这里讲介绍AFL更细节的地方,由于还没有很详细讲解AFL的材料,我将直接阅读afl/docs文件夹下的材料,并将有用的技术细节和使用方法挑选出来,以便更好的理解AFL。首先afl/docs文件夹下结构如下:
在这里插入图片描述

DOCS

简介

模糊测试是识别实际软件中安全问题的最强大,最成熟的策略之一;但是相对较浅;
盲目的,随机的突变使得极不可能到达测试代码中的某些代码路径,从而使某些漏洞完全不在该技术的范围之内。

AFL工作流程

Fuzz流程:

读取输入的初始testcase, 将其放入到queue中;
从queue中读取内容作为程序输入;
尝试在不影响流程的情况下精简输入;
对输入进行自动突变;
如果突变后的输入能够有新的状态转移,将修改后的输入放入queue中;
回到2。

对代码进行插桩

在使用AFL 编译工具 afl-gcc对源码进行编译时,程序会使用afl-as工具对编译并未汇编的c/c++代码进行插桩。过程如下:

afl-as.h定义了被插入代码中的汇编代码;
afl-as逐步分析.s文件(汇编代码),检测代码特征并插入桩。
过程如下图所示:
在这里插入图片描述

过程描述:

编译预处理程序对源文件进行预处理,生成预处理文件(.i文件)
编译插桩程序对.i文件进行编译,生成汇编文件(.s文件),afl同时完成插桩
汇编程序(as)对.s文件进行汇编,生成目标文件(.o文件)
链接程序(ld)对.o文件进行连接,生成可执行文件(.out/.elf文件)
当然llvm/clang插桩方式是另外的一套机制,通过修改LLVM IR(中间语言)实现。

AFL编译程序

$ CC=/path/to/afl/afl-gcc ./configure $ make clean all C++ 程序, 设置
CXX=/path/to/afl/afl-g++.

测试库文件:

it is essential to link this executable against a static version of the instrumented library, or to make sure that the correct .so file is loaded at runtime (usually by setting LD_LIBRARY_PATH). The simplest option is a static build, usually possible via:

$ CC=/path/to/afl/afl-gcc ./configure –disable-shared

AFL编译链接可执行文件和库文件时,建议使用static link(静态链接库,libxxx.a文件),当使用动态链接库时,将动态链接库(如当前目录)加到环境变量中:export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.

选择初始化用例

保证文件足够小,fuzzing测试速度不至于太慢;
选取不同的testcase时,选取不同类型的testcase。
使用afl-cmin精简testcase

如果测试用例导致afl-fuzz速度慢,可以使用LLVM-based mode(compile with
clang),可以提速两倍,或者使用 -d option

持续模式

LLVM模式还提供了一种“持久”的进程内模糊测试模式,该模式可以很好地适用于某些类型的自包含库,并且对于快速目标,可以将性能提高5-10倍;以及“延迟分叉服务器”模式,该模式可以为启动开销较高的程序提供巨大的好处。两种模式都需要您编辑模糊程序的源代码,但是更改通常仅在策略上仅放置一两行。

模糊二进制

./afl-fuzz -i testcase_dir -o findings_dir /path/to/program @@
在这里插入图片描述
-m 设置内存限制,当不限内存时,set -m none
-f xxx 当一个程序读取文件名固定时,set -f xxx(xxx为文件名)
-t 当fuzzing的程序数据交互时间较长,set -t xxx(xxx为超时时间)

模糊屏幕

在这里插入图片描述
屏幕具体含义请参考:status_screen.txt

输出目录说明

队列/-每个独特执行路径的测试用例,以及用户提供的所有起始文件。这是第2节中提到的综合语料库。在将该语料库用于其他目的之前,可以使用afl-cmin工具将其缩小为较小的大小。该工具将找到较小的文件子集,以提供等效的边缘覆盖率。

崩溃 --导致被测试程序接收到致命信号的独特测试用例(例如,SIGSEGV,SIGILL,SIGABRT)。这些条目按接收到的信号分组。

挂起/-导致测试程序超时的独特测试用例。将某物归类为挂起之前的默认时间限制为1秒和-t参数的值中的较大者。可以通过设置AFL_HANG_TMOUT来微调该值,但这很少需要。

在crash文件夹,找到命令程序崩溃的输入。

如果需要重新开始AFL Fuzzing时,删除输出文件夹,或者指定另外的输出文件夹
如果需要继续已经停止的AFL Fuzzing测试,使用afl-fuzz -i-(如:…/ afl-fuzz -i- -o discover_dir / path /
to / program @@)来继续Fuzzing。

并行Fuzzing测试

每个afl-fuzz进程占用CPU的一个核,实际上如果是多核的主机,AFL就可以并行工作,并行模式也为AFL与其他Fuzzing工具,符号执行引擎(符号或共轭执行引擎)交互提供了便利。

像这样运行第一个(“ master”,-M):

$ ./afl-fuzz -i testcase_dir -o sync_dir -M fuzzer01 […other stuff…]

…然后,启动次要(-S)实例,如下所示:

$ ./afl-fuzz -i testcase_dir -o sync_dir -S fuzzer02 […other stuff…]
$ ./afl-fuzz -i testcase_dir -o sync_dir -S fuzzer03 […other stuff…]

警告:显式指定-f选项时,请务必谨慎。每个模糊器必须使用一个单独的临时文件。否则,事情会往南走。一个安全的例子可能是:

$ ./afl-fuzz […] -S fuzzer10 -f file10.txt ./fuzzed/binary @@ $
./afl-fuzz […] -S fuzzer11 -f file11.txt ./fuzzed/binary @@ $
./afl-fuzz […] -S fuzzer12 -f file12.txt ./fuzzed/binary @@

分布式模糊测试: https://github.com/MartijnB/disfuzz-afl

验证crash

如果程序Fuzzing过程发生崩溃,那么会在afl / output / crash文件夹下记录引发崩溃的输入文件,使用gdb单步调试可以定位触发崩溃的代码位置。但是有些比较复杂的程序利用gdb可能比较难定位问题,使用-C选项。

在这种模式下,模糊器将一个或多个崩溃的测试用例作为输入,并使用其反馈驱动的模糊策略来非常快速地枚举程序中可以到达的所有代码路径,同时将其保持在崩溃状态。

LLVM模式

LLVM模式(afl-clang)模式编译程序Fuzzing速度是afl-gcc模式的2倍,但是使用此模式必须先安装llvm套件,请参见学习LLVM项目 -clang,配置LLVM_CONFIG(导出LLVM_CONFIG =llvm-config)。 ),然后在afl / llvm_mode /文件夹下执行make,会在afl /目录下生成afl-clang-fast / afl-clang-fast ++。使用afl-clang-fast编译C程序:

$CC=/path/to/afl/afl-clang-fast ./configure […options…]
$make

最后还是会调用clang / clang ++来编译程序,在编译程序时会检查编译选项(makefile中的CFLAGS),clang提供很多内存检查的工具,如ASAN / MSAN / UBSAN等,以及afl编译选项AFL_QUIET(Qemu模式) ,这些选项可以直接填充进makefile的编译选项也可以设置到环境变量中,afl-gcc / afl-clang在开始编译前会检查这些环境变量。

环境变量设置详情见:env_variables.txt

持久化模式

一些库提供了无状态的API,或者可以在处理不同的输入文件之间重置其状态。执行此类重置后,可以重复使用一个长期存在的过程来测试多个测试用例,从而消除了重复执行fork()调用和相关OS开销的需求。

该程序的基本结构是:

while (__AFL_LOOP(1000)) {

/* Read input data. */
/* Call library code to be fuzzed. */
/* Reset state. */

}

/* Exit normally */

循环内指定的数值控制AFL从头重新启动过程之前的最大迭代次数。这样可以最大程度地减少内存泄漏和类似故障的影响;1000是一个很好的起点,而更高的值会增加出现打h的可能性,而不会给您带来任何实际的性能优势。

ASAN结合使用

在发现内存问题中ASAN / MSAN / UBSAN发挥着重要的作用。有大牛表示:“没有ASAN的AFL模糊测试只是一个浪费CPU”。

使用ASAN方法:

在调用“全部清除”之前设置AFL_USE_ASAN = 1
将-fsanitize = address选项添加到makefile中
使用ASAN编译选项尝试编译成32位系统程序(-m32),因为Address Sanitize使用影子内存机制,在32机器上需要大约800M的内存,但是在x86_64系统上需要大约20TB的内存。

Qemu Mode

在无源码的情况下Fuzzing二进制文件,详细请参见afl / qemu_mode / README.qemu

AFL技术白皮书

参见AFL-技术白皮书

总结

这里多次提到ASAN / MSAN等工具,随后将进一步详细讲解AFL + ASAN结合使用,此乃当前白盒测试领域的神器。

发布了11 篇原创文章 · 获赞 0 · 访问量 343

猜你喜欢

转载自blog.csdn.net/qq_37316433/article/details/104482992