一、AFL简介
- AFL 采用新型的编译时插桩和遗传算法自动发现新的测试用例,这些用例会触发目标二进制文件中的新内部状态。这大大改善了模糊测试的代码覆盖范围。
- AFL既可以对源码进行编译时插桩,也可以使用AFL的QEMU mode对二进制文件进行插桩,但是前者的效率相对来说要高很多。

确定性变异:
bitflip:按位翻转,1变为0,0变为1;这一阶段还会按照不同的长度和步长进行多种不同的翻转,每次翻转1/2/4/8/16/32 bit,依次进行。
arithmetic:整数加/减算术运算
interest:把一些特殊内容替换到原文件中。所谓的特殊内容是AFL预设的一些比较特殊的数,比如可能造成溢出的数。
dictionary:把自动生成或用户提供的token替换/插入到原文件中。
随机变异:
havoc:“大破坏”,是前面几种变异的组合
splice:“连接”,此阶段会将两个文件拼接起来得到一个新的文件,并对这个新文件继续执行havoc变异。
二、AFL安装和使用
2.1、安装

-
afl-gcc 和afl-g++ 分别对应的是gcc 和g++ 的封装
-
afl-clang 和afl-clang++ 分别对应clang 的c 和c++ 编译器封装À。
-
afl-fuzz 是AFL 的主体,用于对目标程序进行fuzz。
-
afl-analyze 可以对用例进行分析,通过分析给定的用例,看能否发现用例中有意义的字段。
-
afl-qemu-trace 用于qemu-mode ,默认不安装 ,需要手工执行qemu-mode 的编译脚本进行编译,后面会介绍。
-
afl-plot 生成测试任务的状态图
-
afl-tmin 和afl-cmin 对用例进行简化
-
afl-whatsup 用于查看fuzz 任务的状态
-
afl-gotcpu 用于查看当前CPU 状态
-
afl-showmap 用于对单个用例进行执行路径跟踪

2.2、准备被测程序
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
int AFLTest(char *str)
{
int len = strlen(str);
if(str[0] == 'A' && len == 6)
{
raise(SIGSEGV);
//如果输入的字符串的首字符为A并且长度为6,则异常退出
}
else if(str[0] == 'F' && len == 16)
{
raise(SIGSEGV);
//如果输入的字符串的首字符为F并且长度为16,则异常退出
}
else if(str[0] == 'L' && len == 66)
{
raise(SIGSEGV);
//如果输入的字符串的首字符为F并且长度为66,则异常退出
}
else
{
printf("it is good!\n");
}
return 0;
}
int main(int argc, char *argv[])
{
char buf[100]={0};
gets(buf);
//存在栈溢出漏洞
printf(buf);
//存在格式化字符串漏洞
AFLTest(buf);
return 0;
}
2.3、使用 afl-gcc 插桩编译
(编译插桩是指在代码编译期间修改或新增代码,插桩是为了覆盖率而实行的方法)


方法1:
CC="afl-gcc" CXX="afl-g++" ./configure --prefix="out_binary_Path"
sudo make && make install
方法2:直接修改 Makefie 文件,修改编译器:
CC = afl-gcc
CXX = afl-g++
./configure --prefix="out_binary_Path"
sudo make && make install
2.4、准备种子语料库
2.4.1、搜集种子语料库
2.4.2、精简语料库
2.4.2.1、去重

2.4.2.2、裁剪体积

A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@

2.5、开始测试









2.6、fuzz结果分析

-
crashes/README.txt:保存了目标执行这些crashes文件的命令行参数。
-
hangs:导致目标超时的独特测试用例。
-
fuzzer_stats:afl-fuzz的运行状态。
-
plot_data:用于afl-plot绘图。









三、并行fuzz测试

-
主实例: afl-fuzz -M master -i good-seeds/ -o good-outputs -m none -- ./test
-
从实例1 : afl-fuzz -S slave1 -i good-seeds/ -o good-outputs -m none -- ./test
-
从实例2: afl-fuzz -S slave2 -i good-seeds/ -o good-outputs -m none -- ./test
-
主实例: afl-fuzz -M master -i- -o good-outputs -m none -- ./test
-
从实例1 : afl-fuzz -S slave1 -i- -o good-outputs -m none -- ./test
-
从实例2: afl-fuzz -S slave2 -i- -o good-outputs -m none -- ./test

这两种类型的Fuzzer执行不同的Fuzzing策略,前者进行确定性测试(deterministic ),即对输入文件进行一些特殊而非随机的的变异;后者进行完全随机的变异。
可以看到这里的-o指定的是一个同步目录,并行测试中,所有的Fuzzer将相互协作,在找到新的代码路径时,相互传递新的测试用例,如下图中以Fuzzer0的角度来看,它查看其它fuzzer的语料库,并通过比较id来同步感兴趣的测试用例。
afl-whatsup 可以查看每个fuzzer的运行状态和总体运行概况( 依靠读afl-fuzz输出目录中的fuzzer_stats文件来显示状态的,每次查看都要需要手动执行),加上-s选项只显示概况,其中的数据都是所有fuzzer的总和。
四、黑盒 fuzz(无源码AFL测试)
4.1、qemu_mode模式安装

-
参考 我的AFL入门之路 - 知乎 (zhihu.com) ,更改一些配置:
-
4.2、示例


