AFL


比较有名的Fuzz工具

image-20240801102741189

Fuzz流程

image-20240801162250704

AFL原理

image-20240802170615459

fork-server

作用:如上图,相当于目标程序和afl-fuzz的中间媒介,相当于一个传递测试用例和执行结果的管道。

优化 AFL 在模糊测试中执行目标程序的方式,从而加速测试过程并降低资源消耗。

主要原理:fork-server在程序启动后,会将其保留在内存中,并提供一个通信接口,这样之后AFL每次生成测试用例向目标程序发送时都需要重新加载和初始化目标程序所带来的开销。从而可以达到减少启动时间和资源消耗、通信和控制、效率提升的作用。

实现细节:AFL通过在启动目标程序时创建子进程(fork)来实现fork-server。,这个fork的功能是加载目标程序并等待AFL发送测试用例,然后通过管道或其他IPC(进程间通信)机制将测试用例发送给fork-server,然后frok-server会将测试用例发送给目标程序执行,并将执行结果返回给AFL。

确定性变异

  1. 位翻转
  2. 字节翻转
  3. 添加或删除字节

不确定性变异

  1. 随机数生成
  2. 基于系统时间的变异
  3. 从外部源(如文件、网络请求)获取的数据等。

AFL的Fuzz方式

  1. 开源软件:AFL软件进行编译的同时进行插桩,以方便Fuzz
  2. 闭源软件:配合QEMU直接对闭源的二进制代码进行Fuzz

术语

语料库

就是我们要从语料库中选择种子,语料库就是模糊测试数据的集合,种子就是其中的一个数据。

插桩

即在程序中的一些地方插入输出代码,来检测程序执行到了哪里。

image-20240801110148179

特点

image-20240801111149620

举例

int had_exec[100] = {0};
void a(){
    had_exec[0] = 1;  //(1)
	//...
}
void b(){had_exec[1] = 1;}
void c(){had_exec[2] = 1;}
int main(){
    //...
    if (had_exec[0] = 1)  //(2)
        puts("function a had has been called");
}

AFL++ 的使用

安装:

sudo apt install afl++
git clone https://github.com/AFLplusplus/ASLplusplus.git
cd AFLplusplus
make
sudo make install

装到了ubantuFuzz-tools/AFLplusplus文件夹下,运行afl-fuzz --version查看版本

1、开源fuzz

测试程序test.c

#include <stdio.h>
#include <unistd.h>
int main(){
    int a, idx;
    char buf[100];
    
    scanf("%d", &idx);
    buf[idx] = '\0';
    
    read(0, &a, 0x2);
    if (a == 0xdead)
        *(int *)0 = 0xdeadbeef;
    return 0;
}

使用AFL++对test.c进行模糊测试

export AFL_USE_ASAN=1
afl-gcc -fsanitize=address test.c -o test   # 使用afl-gcc对test.c进行编译

image-20240801201521060

afl-as

image-20240801164105285

afl-fuzz命令

afl-fuzz -i seed-dir -o out-dir -m none ./test
# 其他参数
-x    # 指定字典,afl-fuzz过程中会将字典中的数据包含到-i的原始输入数据的变异样本当中去
-M 4   # 并行fuzzing实例数,此处并行4个fuzzing实例
-S   # 指定随机种子,会影响随机变异输入。后面可以跟一个整数值或者文件路径。

image-20240801164655880

结果

fuzz的结果输出到了out-dir/default/crashes目录下

cd /out-dir/defalut/crashes
ls    # 即可查看到crash信息
./test.out < out-dir/default/crashes/id:000000,sig:11,src:000000,time:46,execs:10,op:quick,pos:0

2、闭源fuzz

运行qemu的编译脚本

qemu是基于路径信息覆盖制导的fuzz技术

分别为x86 arm 交叉编译的arm下

image-20240805184627096

然后,假设test.c是测试程序

cd ../    # cd到AFLplusplus目录下
make install 
gcc test.c -o test.out   # 因为是闭源fuzz,所以我们不使用afl-gcc来编译
afl-fuzz -i input-dir/ -o output-dir/ -m none -Q ./test.out  # -Q 就是使用qemu 

crash分析

1、Sanitizer

如果不开启Sanitizer,即使程序存在漏洞,如果没有执行到有漏洞的代码段,那么程序也不会出现异常,这样Fuzz的效率就会大大降低。

开启Sanitizer后,虽然性能和时间上会有所损耗,但找bug的能力会大大提高。

2、AdressSanitizer

image-20240801192256882

image-20240801192330585

image-20240801192451238

3、ThreadSanitizer

4、UndefinedBehaviorSanitizer

5、MemorySanitizer

AFL-Fuzz实战

1、测试对象:libpng

wget https://nchc.dl.sourceforge.net/project/libpng/libpng16/1.6.36/libpng-1.6.36.tar.xz  # 下载libpng项目
tar xvf libpng-1.6.36.tar.gz    # 解压
cd libpng-1.6.36
./autogen.sh
# 把编译器指定为afl的编译器
CC=afl-clang-fast CXX=afl-clang-fast++ ./configure --enable-static  # afl-clang是另一个编译器  # --enable-static  用于生成静态库,fuzz开源库时会需要
make -j4		# 编译

2、准备环境(准备种子)

获取官网提供的测试集作为输入

mkdir huzz_in fuzz_out
cd fuzz_in
wget http://lcamtuf.coredump.cx/afl/demo/afl_testcases.tgz
tar vxf afl_testcases.tgz

3、开始fuzz

afl-fuzz -i fuzz_in/png/full/images -o fuzz_out .libs/pngimage @@    # @@代表测试输入样本

总结

image-20240801201702678


文章作者: 0x00dream
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 0x00dream !
  目录