mcpField
F
fuzzer

fuzzer

github.com/workersio测试与质量20879 次安装23 周前更新
代码仓库

关于 fuzzer

面向代码审计与测试的模糊测试 Skill,指导 Agent 从全代码库审计中选定目标,再编写、构建并运行模糊测试。涵盖 C/C++、Rust、Go 及无源码二进制的工具选择与结果报告。

主要功能

  1. 01先审计完整代码库并排序可疑位置
  2. 02按缺陷类型编写测试 Harness
  3. 03提供 C/C++、Rust、Go 构建流程
  4. 04运行模糊测试并报告崩溃或覆盖情况

适用场景

  1. 01为长度参数相关风险选定测试目标
  2. 02为目标函数编写模糊测试 Harness
  3. 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)覆盖率检测效果最佳
Rustcargo-fuzz底层使用 libFuzzer API
Gogo test -fuzz原生支持,无需额外工具
任意二进制文件AFL++ 黑盒模式(afl-fuzz @@)无需源代码
自定义 / 研究LibAFL模块化 Rust 模糊测试库

评论

支持 Markdown