AFL++模糊测试Skill aflpp

AFL++是一种模糊测试工具,专注于在C/C++项目中挖掘安全漏洞,支持多核并行测试、高级变异策略和成熟工具,适用于大规模模糊测试和漏洞发现。关键词:模糊测试,漏洞挖掘,安全测试,AFL++,多核并行测试。

漏洞挖掘 0 次安装 0 次浏览 更新于 3/14/2026

name: aflpp type: fuzzer description: > AFL++是AFL的一个分支,具有更好的模糊测试性能和高级功能。 用于C/C++项目的多核模糊测试。

AFL++

AFL++是原始AFL模糊测试器的一个分支,提供更好的模糊测试性能和更多高级功能,同时保持稳定性。与libFuzzer相比,一个主要优势是AFL++在多核运行模糊测试活动方面有稳定的支持,使其成为大规模模糊测试的理想选择。

何时使用

模糊测试器 最适合 复杂度
AFL++ 多核模糊测试,多样化变异,成熟项目 中等
libFuzzer 快速设置,单线程,简单框架
LibAFL 自定义模糊测试器,研究,高级用例

选择AFL++当:

  • 您需要多核模糊测试以最大化吞吐量
  • 您的项目可以使用Clang或GCC编译
  • 您想要多样化的变异策略和成熟工具
  • libFuzzer已达到瓶颈,您需要更多覆盖率
  • 您正在测试生产代码库,这些代码库受益于并行执行

快速开始

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    // 使用模糊测试器提供的数据调用您的代码
    check_buf((char*)data, size);
    return 0;
}

编译和运行:

# 先设置AFL++包装脚本(见安装)
./afl++ docker afl-clang-fast++ -DNO_MAIN=1 -O2 -fsanitize=fuzzer harness.cc main.cc -o fuzz
mkdir seeds && echo "aaaa" > seeds/minimal_seed
./afl++ docker afl-fuzz -i seeds -o out -- ./fuzz

安装

AFL++有许多依赖,包括LLVM、Python和Rust。我们建议使用当前的Debian或Ubuntu发行版进行AFL++模糊测试。

方法 何时使用 支持的编译器
Ubuntu/Debian仓库 最近的Ubuntu,仅基本功能 Ubuntu 23.10: Clang 14 & GCC 13<br>Debian 12: Clang 14 & GCC 12
Docker(从Docker Hub) 特定AFL++版本,Apple Silicon支持 截至4.35c: Clang 19 & GCC 11
Docker(从源码) 测试未发布功能,应用补丁 在Dockerfile中可配置
从源码 避免Docker,需要特定补丁 通过LLVM_CONFIG环境变量调整

Ubuntu/Debian

在安装afl++之前,用apt-cache show afl++检查包的clang版本依赖,并安装匹配的lld版本(例如,lld-17)。

apt install afl++ lld-17

Docker(从Docker Hub)

docker pull aflplusplus/aflplusplus:stable

Docker(从源码)

git clone --depth 1 --branch stable https://github.com/AFLplusplus/AFLplusplus
cd AFLplusplus
docker build -t aflplusplus .

从源码

参考Dockerfile获取Ubuntu版本要求和依赖。设置LLVM_CONFIG以指定Clang版本(例如,llvm-config-18)。

包装脚本设置

创建包装脚本以在主机或Docker上运行AFL++:

cat <<'EOF' > ./afl++
#!/bin/sh
AFL_VERSION="${AFL_VERSION:-"stable"}"
case "$1" in
   host)
        shift
        bash -c "$*"
        ;;
    docker)
        shift
        /usr/bin/env docker run -ti \
            --privileged \
            -v ./:/src \
            --rm \
            --name afl_fuzzing \
            "aflplusplus/aflplusplus:$AFL_VERSION" \
            bash -c "cd /src && bash -c \"$*\""
        ;;
    *)
        echo "Usage: $0 {host|docker}"
        exit 1
        ;;
esac
EOF
chmod +x ./afl++

安全警告:afl-system-configafl-persistent-config脚本需要root权限并禁用操作系统安全功能。不要在生成系统或开发环境上模糊测试。使用专用虚拟机。

系统配置

每次重启后运行以获得每秒最多15%的执行次数增加:

./afl++ <host/docker> afl-system-config

为获得最佳性能,禁用内核安全缓解措施(需要grub引导程序,Docker中不支持):

./afl++ host afl-persistent-config
update-grub
reboot
./afl++ <host/docker> afl-system-config

cat /proc/cmdline验证 - 输出应包含mitigations=off

编写框架

框架结构

AFL++支持libFuzzer风格的框架:

#include <stdint.h>
#include <stddef.h>

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    // 1. 如果需要,验证输入大小
    if (size < MIN_SIZE || size > MAX_SIZE) return 0;

    // 2. 使用模糊测试数据调用目标函数
    target_function(data, size);

    // 3. 返回0(非零保留用于未来使用)
    return 0;
}

框架规则

在运行之间重置全局状态 依赖前次运行的状态
优雅处理边缘情况 在无效输入时退出
保持框架确定性 使用随机数生成器
释放分配的内存 创建内存泄漏
验证输入大小 处理无界输入

另见: 关于详细框架编写技术、处理复杂输入的模式和高级策略,请参见fuzz-harness-writing技术技能。

编译

AFL++提供多种编译模式,有不同的权衡。

编译模式决策树

选择编译模式:

  • LTO模式afl-clang-lto):最佳性能和插桩。首先尝试这个。
  • LLVM模式afl-clang-fast):如果LTO无法编译,回退到此。
  • GCC插件afl-gcc-fast):适用于需要GCC的项目。

基本编译(LLVM模式)

./afl++ <host/docker> afl-clang-fast++ -DNO_MAIN=1 -O2 -fsanitize=fuzzer harness.cc main.cc -o fuzz

GCC编译

./afl++ <host/docker> afl-g++-fast -DNO_MAIN=1 -O2 -fsanitize=fuzzer harness.cc main.cc -o fuzz

重要: GCC版本必须与用于编译AFL++ GCC插件的版本匹配。

使用Sanitizer

./afl++ <host/docker> AFL_USE_ASAN=1 afl-clang-fast++ -DNO_MAIN=1 -O2 -fsanitize=fuzzer harness.cc main.cc -o fuzz

另见: 关于详细sanitizer配置、常见问题和高级标志,请参见address-sanitizerundefined-behavior-sanitizer技术技能。

构建标志

注意,-g不是必需的,它由AFL++编译器默认添加。

标志 目的
-DNO_MAIN=1 使用libFuzzer框架时跳过主函数
-O2 生产优化级别(推荐用于模糊测试)
-fsanitize=fuzzer 启用libFuzzer兼容模式并在链接可执行文件时添加模糊测试运行时
-fsanitize=fuzzer-no-link 插桩而不链接模糊测试运行时(适用于静态库和对象文件)

语料库管理

创建初始语料库

AFL++至少需要一个非空种子文件:

mkdir seeds
echo "aaaa" > seeds/minimal_seed

对于真实项目,收集代表性输入:

  • 下载您正在模糊测试格式的示例文件
  • 从项目的测试套件中提取测试用例
  • 为您的文件格式使用最小的有效输入

语料库最小化

活动后,最小化语料库以仅保留唯一覆盖率:

./afl++ <host/docker> afl-cmin -i out/default/queue -o minimized_corpus -- ./fuzz

另见: 关于语料库创建策略、字典和种子选择,请参见fuzzing-corpus技术技能。

运行活动

基本运行

./afl++ <host/docker> afl-fuzz -i seeds -o out -- ./fuzz

设置环境变量

./afl++ <host/docker> AFL_FAST_CAL=1 afl-fuzz -i seeds -o out -- ./fuzz

解释输出

AFL++ UI显示实时模糊测试统计信息:

输出 含义
execs/sec 执行速度 - 越高越好
cycles done 队列传递完成的次数
corpus count 队列中唯一测试用例的数量
saved crashes 找到的唯一崩溃的数量
stability 稳定边的百分比(应接近100%)

输出目录结构

out/default/
├── cmdline          # SUT是如何调用的?
├── crashes/         # 使SUT崩溃的输入
│   └── id:000000,sig:06,src:000002,time:286,execs:13105,op:havoc,rep:4
├── hangs/           # 使SUT挂起的输入
├── queue/           # 复制最终模糊测试器状态的测试用例
│   ├── id:000000,time:0,execs:0,orig:minimal_seed
│   └── id:000001,src:000000,time:0,execs:8,op:havoc,rep:6,+cov
├── fuzzer_stats     # 活动统计信息
└── plot_data        # 绘图数据

分析结果

查看实时活动统计信息:

./afl++ <host/docker> afl-whatsup out

创建覆盖率图:

apt install gnuplot
./afl++ <host/docker> afl-plot out/default out_graph/

重新执行测试用例

./afl++ <host/docker> ./fuzz out/default/crashes/<test_case>

模糊测试器选项

选项 目的
-G 4000 最大测试输入长度(默认:1048576字节)
-t 1000 每个测试用例的超时时间(默认:1000ms)
-m 1000 内存限制,以兆字节为单位(默认:0 = 无限)
-x ./dict.dict 使用字典文件指导变异

多核模糊测试

AFL++在多核模糊测试方面表现出色,具有两个主要优势:

  1. 每秒更多执行次数(与物理核心线性缩放)
  2. 非对称模糊测试(例如,一个ASan作业,其余无sanitizer)

启动活动

启动主要模糊测试器(在后台):

./afl++ <host/docker> afl-fuzz -M primary -i seeds -o state -- ./fuzz 1>primary.log 2>primary.error &

启动次要模糊测试器(根据需要的内核数量):

./afl++ <host/docker> afl-fuzz -S secondary01 -i seeds -o state -- ./fuzz 1>secondary01.log 2>secondary01.error &
./afl++ <host/docker> afl-fuzz -S secondary02 -i seeds -o state -- ./fuzz 1>secondary02.log 2>secondary02.error &

监控多核活动

列出所有运行中的作业:

jobs

查看实时统计信息(每秒更新):

./afl++ <host/docker> watch -n1 --color afl-whatsup state/

停止所有模糊测试器

kill $(jobs -p)

覆盖率分析

AFL++通过边插桩自动跟踪覆盖率。覆盖率信息存储在fuzzer_statsplot_data中。

测量覆盖率

使用afl-plot可视化覆盖率随时间变化:

./afl++ <host/docker> afl-plot out/default out_graph/

改进覆盖率

  • 使用字典进行格式感知模糊测试
  • 运行更长的活动(cycles_wo_finds表示瓶颈)
  • 尝试多核模糊测试的不同变异策略
  • 分析覆盖率差距并添加有针对性的种子输入

另见: 关于详细覆盖率分析技术、识别覆盖率差距和系统覆盖率改进,请参见coverage-analysis技术技能。

CMPLOG

CMPLOG/RedQueen是任何模糊测试器中最佳路径约束解决机制。要启用它,模糊测试目标需要为其插桩。在构建模糊测试目标之前设置环境变量:

./afl++ <host/docker> AFL_LLVM_CMPLOG=1 make

编译和链接框架时不需要特殊操作。

要运行带有CMPLOG插桩模糊测试目标的模糊测试器实例,添加-c0到命令行参数:

./afl++ <host/docker> afl-fuzz -c0 -S cmplog -i seeds -o state -- ./fuzz 1>secondary02.log 2>secondary02.error &

Sanitizer集成

Sanitizer对于发现不立即导致崩溃的内存损坏错误至关重要。

AddressSanitizer (ASan)

./afl++ <host/docker> AFL_USE_ASAN=1 afl-clang-fast++ -DNO_MAIN=1 -O2 -fsanitize=fuzzer harness.cc main.cc -o fuzz

注意: 内存限制(-m)由于20TB虚拟内存预留而不支持ASan。

UndefinedBehaviorSanitizer (UBSan)

./afl++ <host/docker> AFL_USE_UBSAN=1 afl-clang-fast++ -DNO_MAIN=1 -O2 -fsanitize=fuzzer,undefined harness.cc main.cc -o fuzz

常见Sanitizer问题

问题 解决方案
ASan减缓模糊测试 在多核设置中仅使用1个ASan作业
堆栈耗尽 ASAN_OPTIONS=stack_size=...增加堆栈
GCC版本不匹配 确保系统GCC与AFL++插件版本匹配

另见: 关于全面sanitizer配置和故障排除,请参见address-sanitizer技术技能。

高级用法

技巧和窍门

技巧 为什么有帮助
尽可能使用LLVMFuzzerTestOneInput框架 如果模糊测试活动至少有85%稳定性,这是最高效的模糊测试风格。否则尝试标准输入或文件输入模糊测试
使用字典 帮助模糊测试器发现格式特定的关键字和魔法字节
设置现实的超时 防止来自系统负载的假阳性
限制输入大小 更大的输入不一定探索更多空间
监控稳定性 低稳定性表示非确定性行为

标准输入模糊测试

AFL++可以模糊测试从stdin读取的程序,无需libFuzzer框架:

./afl++ <host/docker> afl-clang-fast++ -O2 main_stdin.c -o fuzz_stdin
./afl++ <host/docker> afl-fuzz -i seeds -o out -- ./fuzz_stdin

这比持久模式慢但不需要框架代码。

文件输入模糊测试

对于读取文件的程序,使用@@占位符:

./afl++ <host/docker> afl-clang-fast++ -O2 main_file.c -o fuzz_file
./afl++ <host/docker> afl-fuzz -i seeds -o out -- ./fuzz_file @@

为获得更好性能,使用fmemopen从内存创建文件描述符。

参数模糊测试

使用argv-fuzz-inl.h模糊测试命令行参数:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef __AFL_COMPILER
#include "argv-fuzz-inl.h"
#endif

void check_buf(char *buf, size_t buf_len) {
    if(buf_len > 0 && buf[0] == 'a') {
        if(buf_len > 1 && buf[1] == 'b') {
            if(buf_len > 2 && buf[2] == 'c') {
                abort();
            }
        }
    }
}

int main(int argc, char *argv[]) {
#ifdef __AFL_COMPILER
    AFL_INIT_ARGV();
#endif

    if (argc < 2) {
        fprintf(stderr, "Usage: %s <input_string>
", argv[0]);
        return 1;
    }

    char *input_buf = argv[1];
    size_t len = strlen(input_buf);
    check_buf(input_buf, len);
    return 0;
}

下载头文件:

curl -O https://raw.githubusercontent.com/AFLplusplus/AFLplusplus/stable/utils/argv_fuzzing/argv-fuzz-inl.h

编译和运行:

./afl++ <host/docker> afl-clang-fast++ -O2 main_arg.c -o fuzz_arg
./afl++ <host/docker> afl-fuzz -i seeds -o out -- ./fuzz_arg

性能调优

设置 影响
CPU核心数量 与物理核心线性缩放
持久模式 比fork服务器快10-20倍
-G输入大小限制 更小 = 更快,但可能错过错误
ASan比率 每4-8个非ASan作业1个ASan作业

故障排除

问题 原因 解决方案
低exec/sec (<1k) 未使用持久模式 创建LLVMFuzzerTestOneInput风格的框架
低稳定性 (<85%) 非确定性代码 通过stdin或文件输入模糊测试程序,或创建这样的框架
GCC插件错误 GCC版本不匹配 确保系统GCC与AFL++构建匹配并安装gcc-$GCC_VERSION-plugin-dev
未找到崩溃 需要sanitizer AFL_USE_ASAN=1重新编译
内存限制超出 ASan使用20TB虚拟 使用ASan时移除-m标志
Docker性能损失 虚拟化开销 为生产模糊测试使用裸机或VM

相关技能

技术技能

技能 用例
fuzz-harness-writing 编写有效框架的详细指南
address-sanitizer 模糊测试期间的内存错误检测
undefined-behavior-sanitizer 检测未定义行为错误
fuzzing-corpus 构建和管理种子语料库
fuzzing-dictionaries 为格式感知模糊测试创建字典

相关模糊测试器

技能 何时考虑
libfuzzer 快速原型设计,单线程模糊测试足够
libafl 需要自定义变异器或研究级功能

资源

关键外部资源

AFL++ GitHub Repository 官方仓库,包含全面文档、示例和问题跟踪器。

Fuzzing in Depth AFL++团队的高级文档,涵盖插桩模式、优化技术和高级用例。

AFL++ Under The Hood 技术深入探讨AFL++内部机制、变异策略和覆盖率跟踪机制。

AFL++: Combining Incremental Steps of Fuzzing Research 研究论文描述AFL++架构和相对于原始AFL的性能改进。

视频资源