关于 fuzzer
面向代码审计与测试的模糊测试 Skill,指导 Agent 从全代码库审计中选定目标,再编写、构建并运行模糊测试。涵盖 C/C++、Rust、Go 及无源码二进制的工具选择与结果报告。
主要功能
- 01先审计完整代码库并排序可疑位置
- 02按缺陷类型编写测试 Harness
- 03提供 C/C++、Rust、Go 构建流程
- 04运行模糊测试并报告崩溃或覆盖情况
适用场景
- 01为长度参数相关风险选定测试目标
- 02为目标函数编写模糊测试 Harness
- 03对代码库运行模糊测试并整理结果
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ workersio/ skills --skill fuzzer安装后在 Claude Code 中输入/fuzzer确认已加载。
详细介绍
Fuzzer 技能
何时使用
当用户要求对目标进行模糊测试、通过模糊测试查找内存/整数错误、编写模糊测试 harness,或在代码库上运行模糊测试活动时调用。
工作流
步骤 1 — 审查(必须 — 始终首先运行,不得例外)
在编写任何 harness 之前,你必须调用 audit-context-building 技能。
即使你认为自己已经了解代码,也不要跳过此步骤。
目标:在对任何内容进行排序之前,阅读整个代码库——所有源文件。不要在某个目录中发现第一个可疑位置后就停止。覆盖所有模块。
重点查找:
size_t → int或size_t → uint32_t窄化转换- 未检查长度运算(对大小进行加法、乘法)
- 接受攻击者可控
size_t/ 长度参数的公共 API 函数
输出:基于整个代码库、带有 file:line 的可疑位置排序列表。
选择排名第一的候选项作为 harness 目标。
步骤 2 — 编写 Harness
你必须针对审查中排名第 1 的确切 file:line。不要根据自己的判断,改为针对其他函数、代码路径或“更有意思”的区域。目标由审查决定,你负责实现。
- 阅读审查提供的调用路径
- 调用该调用路径中的确切函数
- 根据它识别出的错误类型选择下面的模式
根据步骤 1 中的错误类型选择模式。
算术溢出(size_t→int 累积、大小上的未检查加法):
错误在算术运算中——不在缓冲区内容中。从模糊测试字节中提取一个 uint32_t 声明大小,并直接传入。使用一个 1 字节静态存根作为数据指针。绝不要根据实际传入的缓冲区推导大小。
#include <stddef.h>
#include <stdint.h>
#include <string.h>
static const uint8_t kStub[1] = {0};
/* Required by libAFLDriver.a — must be present or link fails */
int LLVMFuzzerInitialize(int *argc, char ***argv) {
(void)argc; (void)argv;
return 0;
}
void LLVMFuzzerCleanup(void) {}
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
uint8_t n = data[0] % MAX_CALLS;
if (n == 0 || size < 1 + (size_t)n * 4) return 0;
TargetState *s = TargetState_Create();
for (uint8_t i = 0; i < n; i++) {
uint32_t claimed;
memcpy(&claimed, data + 1 + i * 4, 4);
target_fn(s, (size_t)claimed, kStub); /* claimed drives the arithmetic */
}
TargetState_Destroy(s);
return 0;
}
分离输入(API 接受配置/大小参数 + 数据载荷):
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
if (size < N) return 0;
/* bytes [0..N-1] → config / mode / count */
/* bytes [N..] → payload */
target_fn(config, data + N, size - N);
return 0;
}
直接调用(简单的缓冲区 + 长度):
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
if (size < 1) return 0;
target_fn(data, size);
return 0;
}
Rust:
fuzz_target!(|data: &[u8]| { target_function(data); });
Go:
func FuzzTarget(f *testing.F) {
f.Fuzz(func(t *testing.T, data []byte) { target_function(data) })
}
步骤 3 — 构建
构建前,定位 AFL++:
which afl-clang-fast || find /usr/local /opt/homebrew /tmp -name afl-clang-fast 2>/dev/null
如果未找到,请安装:
brew install afl++ # macOS
apt-get install afl++ # Debian/Ubuntu
使用 AFL++ 的 C / C++:
AFL=$(which afl-clang-fast)
AFLDRIVER=$(dirname $(dirname $AFL))/lib/afl/libAFLDriver.a
# Compile target sources into instrumented static library
mkdir -p build
find <src-dir> -name "*.c" | while read f; do
$AFL \
-g -O1 -fsanitize=address,undefined -fno-omit-frame-pointer \
<include-flags> -c "$f" -o "build/$(basename $f .c).o"
done
ar rcs build/libtarget.a build/*.o
# Compile harness + link
$AFL \
-g -O1 -fsanitize=address,undefined -fno-omit-frame-pointer \
harness.c build/libtarget.a $AFLDRIVER \
-o build/fuzzer
Rust:
cargo fuzz build <target_name>
步骤 4 — 运行
使用 AFL++ 的 C / C++:
ASAN_OPTIONS=abort_on_error=1:detect_leaks=0:symbolize=0 \
AFL_SKIP_CPUFREQ=1 AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 \
$(which afl-fuzz) \
-i corpus/ \
-o findings/ \
-- build/fuzzer
Rust:
cargo fuzz run <target_name> corpus/
Go:
go test -fuzz=FuzzTarget -fuzztime=12h ./...
步骤 5 — 报告
当 findings/default/crashes/ 中包含文件时,报告:
CRASH FOUND
Input: findings/default/crashes/id:000000,...
Signal: sig:06 (SIGABRT = sanitizer) or sig:11 (SIGSEGV)
Reproduce (with symbolized output):
UBSAN_OPTIONS=print_stacktrace=1 \
ASAN_OPTIONS=detect_leaks=0:print_stacktrace=1 \
./build/fuzzer findings/default/crashes/id:000000,...
Sanitizer output:
<paste UBSan/ASan stacktrace here>
Root cause: <file>:<line> — <one sentence description>
如果在预算时间内没有崩溃:报告发现的路径以及语料库中的唯一输入。
Harness 规则
| 规则 | 原因 |
|---|---|
| 始终返回 0 | 不要让 harness 本身中止 |
绝不调用 exit() | 会终止模糊测试器进程 |
| 处理所有输入大小 | 模糊测试器会生成空、小型和超大型输入 |
| 保持快速——不要记录日志 | 目标为 100–1000+ 次执行/秒 |
| 相同输入 = 相同输出 | 复现崩溃需要确定性 |
| 每次调用都释放所有资源 | 防止数百万次运行后内存耗尽 |
| 重置全局状态 | 隔离每次迭代 |
工具选择
| 目标 | 模糊测试器 | 备注 |
|---|---|---|
| C / C++ | AFL++(afl-clang-fast) | 覆盖率检测效果最佳 |
| Rust | cargo-fuzz | 底层使用 libFuzzer API |
| Go | go test -fuzz | 原生支持,无需额外工具 |
| 任意二进制文件 | AFL++ 黑盒模式(afl-fuzz @@) | 无需源代码 |
| 自定义 / 研究 | LibAFL | 模块化 Rust 模糊测试库 |