[ayoung@blog posts]$ cat ./afl.md

afl

[Last modified: 2025-05-11]

基础

插桩编译

afl-gcc -g -o a a.c
./configure CC="afl-gcc" CXX="afl-g++" # autoconf
./configure --disable-shared CC="afl-gcc" CXX="afl-g++" # .so

开始fuzz

# -i 输入 -o 输出文件夹 从stdin读取输入
afl-fuzz -i testcase_dir -o findings_dir ./a

# 从文件读取输入 @@是占位符 表示替换的位置
./afl-fuzz -i testcase_dir -o findings_dir /path/to/program @@

eg afl-fuzz -m 300 -i ./zerotest/fuzz_in -o ./zerotest/fuzz_out ./zerotest/vuln -f

常见参数

-f testcase的内容会作为afl_test的stdin -m 分配的内存空间 -i 指定测试样本路径 -o 指定输出结果的路径 -t 设置程序运行超时值,单位为 ms -M 运行主(Master) Fuzzer -S 运行从属(Slave) Fuzzer /dev/null

启动文件选择

结果分析

last new path 如果报错要及时修正命令行参数,否则继续fuzz也是徒劳(因为路径不会改变) cycles done 如果变绿就说明后面即使继续fuzz,出现crash的几率也很低了,可以选择停止 uniq crashes 代表crash的数量

afl-whatsup工具可以查看每个fuzzer的运行状态和总体运行概况,加上-s选项只显示概况,其中的数据都是所有fuzzer的总和 afl-gotcpu工具可以查看每个核心使用状态

停止afl-fuzz时机:

fuzz结束判断

crash分析

ayoung@ay:~/fuzz_learn$ xxd findings_dir/crashes/id\:000000\,sig\:06\,src\:000000\,op\:havoc\,rep\:64 
00000000: dabf 1fbf d0a9 bf18 cbda bfbf bfd0 a9bf  ................
00000010: 18cb bfda bfdb bfbf bfb4 bfbf bfbf d6bf  ................
00000020: ff80 babf bfbf bf86 0000 0100 bfbf bf00  ................
00000030: bff5 ffbf bb00 0083 1000 00df aabf bfbf  ................
00000040: 4343 4343 4343 4343 4343 43bf dabf dbbf  CCCCCCCCCCC.....
00000050: bfbf b4bf bfaa ddbf bfbf bbba bfbf bfba  ................
00000060: bfbf bf64 d89f 64bf bbba 0002 bfbf 7f80  ...d..d.........
00000070: babf bfbf bf86 0040 0100 bfbf bf00 bff5  .......@........
00000080: ffbf bb00 0083 1000 00df 2f              ........../

gdb内部执行 pwndbg> r < findings_dir/crashes/id:000000,sig:06,src:000000,op:havoc,rep:64

简化crash

ayoung@ay:~/fuzz_learn$ cat findings_dir/crashes/id\:000000\,sig\:06\,src\:000000\,op\:havoc\,rep\:64 
ڿ�Щ��ڿ��Щ�˿ڿۿ�������ֿ�����������������ߪ���CCCCCCCCCCC�ڿۿ������ݿ�����������d؟d������������@����������/
ayoung@ay:~/fuzz_learn$ afl-tmin -i findings_dir/crashes/id\:000000\,sig\:06\,src\:000000\,op\:havoc\,rep\:64 -o minimized_crash -- ./a
afl-tmin 2.52b by <lcamtuf@google.com>

[+] Read 139 bytes from 'findings_dir/crashes/id:000000,sig:06,src:000000,op:havoc,rep:64'.
[*] Performing dry run (mem limit = 50 MB, timeout = 1000 ms)...
[+] Program exits with a signal, minimizing in crash mode.
[*] Stage #0: One-time block normalization...
[+] Block normalization complete, 139 bytes replaced.
[*] --- Pass #1 ---
[*] Stage #1: Removing blocks of data...
    Block length = 8, remaining size = 139
    Block length = 4, remaining size = 107
    Block length = 2, remaining size = 107
    Block length = 1, remaining size = 105
[+] Block removal complete, 34 bytes deleted.
[*] Stage #2: Minimizing symbols (1 code point)...
[+] Symbol minimization finished, 0 symbols (0 bytes) replaced.
[*] Stage #3: Character minimization...
[+] Character minimization done, 0 bytes replaced.
[*] --- Pass #2 ---
[*] Stage #1: Removing blocks of data...
    Block length = 8, remaining size = 105
    Block length = 4, remaining size = 105
    Block length = 2, remaining size = 105
    Block length = 1, remaining size = 105
[+] Block removal complete, 0 bytes deleted.

     File size reduced by : 24.46% (to 105 bytes)
    Characters simplified : 132.38%
     Number of execs done : 57
          Fruitless execs : path=16 crash=0 hang=0

[*] Writing output to 'minimized_crash'...
[+] We're done here. Have a nice day!

ayoung@ay:~/fuzz_learn$ cat minimized_crash 
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

无源码测试

afl qemu-mode编译 gcc编译 afl-fuzz -i fuzz_in -o fuzz_out -Q ./afl_test2

llvm mode

可以获得更快的Fuzzing速度,针对大型项目可以考虑启用

语料库蒸馏

afl-cmin 移除执行相同代码的文件

afl-cmin -i input_dir -o output_dir -- /path/to/tested/program [params]
afl-cmin -i input_dir -o output_dir -- /path/to/tested/program [params] @@

afl-tmin 减小单个输入文件的大小 默认instrumented mode

# instrumented mode
afl-tmin -i input_file -o output_file -- /path/to/tested/program [params] @@
# crash mode 把导致程序非正常退出的文件直接剔除
afl-tmin -x -i input_file -o output_file -- /path/to/tested/program [params] @@

批量处理:

for i in id*
do
    afl-tmin -i $i -o tmin-$i -- ~/path/to/tested/program [params] @@
done

使用完afl-tmin后再次使用afl-cmin,可能可以再过滤掉一些用例