AFL++ 简介 AFL++是在AFL基础上进行改进的模糊测试工具,其源码 可以从github上得到。AFL++会将测试用例进行变异并作为输入交给目标程序,当这个测试用例能够触发新的路径时,就会被保存并进一步变异测试。
安装流程 AFL++的安装可以通过docker安装,也可以通过源码安装,本实验通过源码安装 根据readme 进行安装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 # 系统版本 Ubuntu20 sudo apt-get update sudo apt-get install -y build-essential python3-dev automake cmake git flex bison libglib2.0-dev libpixman-1-dev python3-setuptools cargo libgtk-3-dev sudo apt-get install -y lld-14 llvm-14 llvm-14-dev clang-14 || sudo apt-get install -y lld llvm llvm-dev clang sudo apt-get install -y gcc-$(gcc --version|head -n1|sed 's/\..*//'|sed 's/.* //')-plugin-dev libstdc++-$(gcc --version|head -n1|sed 's/\..*//'|sed 's/.* //')-dev sudo apt-get install -y ninja-build # for QEMU mode sudo apt-get install -y cpio libcapstone-dev # for Nyx mode sudo apt-get install -y wget curl # for Frida mode sudo apt-get install python3-pip # for Unicorn mode git clone https://github.com/AFLplusplus/AFLplusplus cd AFLplusplus make distrib sudo make install
基本使用 利用afl-training中的vulnerable.c 来进行实验
有源码 1 2 3 CC=afl-clang-fast AFL_HARDEN=1 make echo core | sudo tee /proc/sys/kernel/core_pattern afl-fuzz -i inputs -o out ./vulnerable
可以看到afl++能够成功运行这个目标程序,并且能够触发崩溃
无源码 测试整个程序 1 2 3 gcc -o vul vulnerable.c echo core | sudo tee /proc/sys/kernel/core_pattern afl-fuzz -Q -i inputs -o out ./vul
由于这个程序没有利用afl++编译插桩过,因此需要利用qemu模式,即运行afl++的时候需要加上参数-Q
测试某个函数 vulnerable.c
假设要fuzz的目标函数是process ,查阅AFL++的文档,了解到可以用AFL++的persistent mode 。文档中提到,使用该模式需要确认目标函数的地址,并且编写persistent hook 来传入对应的参数。因此实验流程如下
确认目标函数在程序中的偏移地址
1 2 3 4 5 6 # 确定process的地址 nm vul | grep "T process" # 值为00000000000012c9 # AFL++在qemu模式的情况下进行fuzz的时候,如果程序启用了PIE,需要加上基地址0x4000000000 # 可以使用 checksec --file=vul 来确认是否启用了PIE export AFL_QEMU_PERSISTENT_ADDR=0x40000012c9
参照样例 编写persistent hook
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #include "/home/xu/lab-tools/git-lab/aflplusplus/AFLplusplus/qemu_mode/qemuafl/qemuafl/api.h" #include <stdio.h> #include <string.h> #define g2h(x) ((void *)((unsigned long)(x) + guest_base)) #define h2g(x) ((uint64_t)(x) - guest_base) void afl_persistent_hook (struct x86_64_regs *regs, uint64_t guest_base, uint8_t *input_buf, uint32_t input_buf_len) { printf ("Placing input into 0x%lx\n" , regs->rdi); printf ("length of input_buf is %d\n" ,input_buf_len); memcpy (g2h(regs->rdi), input_buf, input_buf_len); } #undef g2h #undef h2g int afl_persistent_hook_init (void ) { return 1 ; }
运行AFL++来进行模糊测试
1 2 3 4 5 6 7 8 9 gcc -fPIC -shared read_into_rdi.c -o read_into_rdi.so export AFL_QEMU_PERSISTENT_HOOK=./read_into_rdi.so export AFL_QEMU_PERSISTENT_GPR=1 export AFL_QEMU_PERSISTENT_MEM=1 export AFL_QEMU_PERSISTENT_EXITS=1 mkdir outputs export AFL_NO_FORKSRV=1 AFL_DEBUG=1 afl-fuzz -Q -i inputs -o outputs ./vul
可以看到afl++能够成功运行程序并且触发崩溃
由于无法从AFL++的界面中直观地看出是否进入persistent mode,因此可以通过在vulnerable.c中添加一些输入来确定是否达到我们的预期,比如在main函数中添加printf("function : main\n")
,在process函数中添加printf("function : process\n")
,然后在运行afl++的指令前加上AFL_DEBUG=1
,如果看到main的输出只有一次,process函数反复输出,说明程序的运行达到了我们的预期。