mcpField
F
fuzzing

fuzzing

github.com/mohitmishra786テスト・品質269632 回インストール18 週間前に更新
リポジトリ

fuzzing について

libFuzzerやAFL++などを使ったカバレッジ誘導型ファジングの設定と実行をエージェントに案内するスキルです。ターゲット作成、サニタイザー、クラッシュ再現、コーパス管理、CIを扱い、堅牢性を検証する開発者向けです。

主な機能

  1. 01libFuzzerとAFL++の設定
  2. 02ファズターゲットの作成とビルド
  3. 03サニタイザー連携
  4. 04クラッシュ再現とコーパス管理
  5. 05CIとOSS-Fuzzの案内
  6. 06構造認識型ファジングとデータフロー追跡

活用シーン

  1. 01パーサーやデシリアライザーのファジング
  2. 02ファザーが検出したクラッシュの再現とデバッグ
  3. 03CIで短時間のファジングを実行
  4. 04テストコーパスの統合や最小化

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/mohitmishra786/low-level-dev-skills --skill fuzzing

インストール後、Claude Code で/fuzzingを入力して読み込まれたか確認します。

同梱ファイルreferences/targets.md

詳細

ファジング

目的

カバレッジガイド付きファズテストの設定と実行について、エージェントをガイドします。サニタイザーとの統合と CI パイプラインの設定を含む、libFuzzer(プロセス内)と AFL++(フォークベース)を扱います。

トリガー

  • 「パーサー/デシリアライザーをファズテストするにはどうすればよいですか?」
  • 「ファズターゲットとは何ですか? どのように記述しますか?」
  • 「libFuzzer を設定するにはどうすればよいですか?」
  • 「プログラムで AFL++ を使うにはどうすればよいですか?」
  • 「CI でファジングを実行するにはどうすればよいですか?」
  • 「ファザーがクラッシュを見つけました。再現するにはどうすればよいですか?」

ワークフロー

1. ファズターゲットを記述する(libFuzzer)

ファズターゲットは、任意のバイト列を受け取り、テスト対象のコードを実行する関数です。

// fuzz_parser.c
#include <stdint.h>
#include <stddef.h>
#include "myparser.h"

// Entry point called by libFuzzer with random data
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    // Must not abort/exit on invalid input (that's expected)
    // Must not read outside [data, data+size)

    MyParser *p = parser_create();
    if (p) {
        parser_feed(p, (const char *)data, size);
        parser_destroy(p);
    }
    return 0;  // Always return 0 (non-zero means discard input)
}

主なルール:

  • abort()、exit() を呼び出したり、呼び出し間で保持されるグローバル状態を使用したりしないでください
  • すべての入力を適切に処理してください(クラッシュはバグが見つかったことを意味します)
  • ターゲットは高速に保ってください。ファザーはこれを何百万回も呼び出します
2. libFuzzer を使ってビルドする
# Clang (libFuzzer is built into Clang)
clang -fsanitize=fuzzer,address -g -O1 \
    fuzz_parser.c myparser.c -o fuzz_parser

# With UBSan too
clang -fsanitize=fuzzer,address,undefined -g -O1 \
    fuzz_parser.c myparser.c -o fuzz_parser

-fsanitize=fuzzer は libFuzzer をリンクし、main() を提供します。ファズターゲットに独自の main() を定義しないでください。

3. libFuzzer を実行する
# Create corpus directory
mkdir -p corpus

# Seed with known-good inputs (greatly accelerates coverage)
cp tests/inputs/* corpus/

# Run the fuzzer
./fuzz_parser corpus/ -max_len=65536 -timeout=10

# Run for a time limit
./fuzz_parser corpus/ -max_total_time=3600

# Run with specific number of jobs (parallel)
./fuzz_parser corpus/ -jobs=4 -workers=4

# Minimise a corpus (remove redundant inputs)
./fuzz_parser -merge=1 corpus_min/ corpus/

一般的なフラグ:

フラグデフォルト効果
-max_len=N4096最大入力サイズ(バイト単位)
-timeout=N12001 回の実行に N 秒を超えた場合に停止
-max_total_time=N0(無期限)ファジングの合計時間
-runs=N-1(無制限)実行回数の合計
-dict=fileなし興味深いトークンの辞書
-jobs=N1並列ジョブ数(各ジョブは独自のログを書き込みます)
-merge=1オフマージモード:コーパスを最小化
4. クラッシュを再現する

libFuzzer は、クラッシュ入力を crash-<hash>、oom-<hash>、timeout-<hash> という名前のファイルに書き込みます。

# Reproduce
./fuzz_parser crash-abc123

# Debug with GDB
gdb ./fuzz_parser
(gdb) run crash-abc123
5. AFL++ の設定

AFL++ はフォークベースのファザーで、ファズ用のエントリポイントがあるプログラムに限らず、任意のプログラムで動作します。

# Install
apt install afl++     # or build from source

# Instrument the target
CC=afl-clang-fast CXX=afl-clang-fast++ \
  cmake -S . -B build-afl -DCMAKE_BUILD_TYPE=Debug
cmake --build build-afl

# Or compile directly
afl-clang-fast -g -O1 -o prog_afl main.c myparser.c

# Create input corpus
mkdir -p afl-input afl-output
echo "hello" > afl-input/seed1

# Run
afl-fuzz -i afl-input -o afl-output -- ./prog_afl @@
# @@ is replaced with the input file path
# For stdin-based programs: remove @@
afl-fuzz -i afl-input -o afl-output -- ./prog_afl
6. 永続モードで AFL++ を使う(高速化)

永続モードでは入力ごとの fork() を回避できるため、ライブラリのファジングが大幅に高速になります。

// In your harness:
#include "myparser.h"

int main(int argc, char **argv) {
    while (__AFL_LOOP(1000)) {
        // Read input
        unsigned char *buf = NULL;
        ssize_t len = read(0, &buf, MAX_SIZE);  // or use afl_custom_mutator
        parser_feed((char*)buf, len);
        free(buf);
    }
    return 0;
}
7. コーパスの管理
# AFL++ corpus minimisation
afl-cmin -i afl-output/default/queue -o corpus_min -- ./prog_afl @@

# Merge libFuzzer corpora from multiple runs
./fuzz_parser -merge=1 merged_corpus/ run1_corpus/ run2_corpus/

# Show coverage (libFuzzer)
./fuzz_parser corpus/ -runs=0 -print_coverage=1
8. CI との統合
# GitHub Actions example
- name: Build fuzz targets
  run: |
    clang -fsanitize=fuzzer,address,undefined -g -O1 \
      fuzz_parser.c myparser.c -o fuzz_parser

- name: Short fuzz run (regression check)
  run: |
    ./fuzz_parser corpus/ -max_total_time=60 -error_exitcode=1
    # Also run known crash inputs if any:
    ls known_crashes/ 2>/dev/null | xargs -I{} ./fuzz_parser known_crashes/{}

長時間のファジングには、OSS-Fuzz または ClusterFuzz のインフラストラクチャを使用してください。

9. 構造を認識したファジング(libFuzzer)
// Custom mutator hook — preserve format invariants
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
                               size_t MaxSize, unsigned int Seed) {
    // Delegate to default mutator then fix up structure
    Size = LLVMFuzzerMutate(Data, Size, MaxSize);
    if (Size >= 4)
        fix_checksum(Data, Size);
    return Size;
}

// Register custom crossover for structured inputs
extern "C" size_t LLVMFuzzerCustomCrossOver(
    const uint8_t *Data1, size_t Size1,
    const uint8_t *Data2, size_t Size2,
    uint8_t *Out, size_t MaxOutSize, unsigned int Seed);

単純なビット反転では、深いコードパスに到達する前にチェックサムやヘッダーが壊れてしまう場合に使用します。

10. Atheris(Python のファジング)
import atheris
import sys

with atheris.instrument_imports():
    import myparser

def TestOneInput(data: bytes) -> None:
    fdp = atheris.FuzzedDataProvider(data)
    try:
        myparser.parse(fdp.ConsumeString(sys.maxsize))
    except myparser.ParseError:
        pass

if __name__ == "__main__":
    atheris.Setup(sys.argv, TestOneInput)
    atheris.Fuzz()
pip install atheris
python fuzz_myparser.py corpus/ -max_total_time=300
11. データフローのトレース
# Track tainted bytes through execution (LLVM dataflow sanitizer + libFuzzer)
clang -fsanitize=fuzzer,dataflow -g -O1 fuzz.c target.c -o fuzz
LIBFUZZER_DATAFLOW_TRACE=1 ./fuzz corpus/

入力バイトがどの分岐に影響したかを示すトレースを生成し、辞書や構造を認識したミューテーターの作成に役立てます。

12. OSS-Fuzz との統合
OSS-Fuzz workflow
├── Add project/ in google/oss-fuzz repo (Dockerfile + build.sh)
├── Fuzz targets linked with -fsanitize=fuzzer,address
├── ClusterFuzz runs continuously on GCE
└── Crash reproducers uploaded to issue tracker
# project/Dockerfile (minimal)
FROM gcr.io/oss-fuzz-base/base-builder
RUN git clone --depth 1 https://github.com/you/yourproject
WORKDIR yourproject
COPY build.sh $SRC/
# Local OSS-Fuzz repro
python infra/helper.py build_image yourproject
python infra/helper.py build_fuzzers yourproject
python infra/helper.py run_fuzzer yourproject fuzz_target
13. Zig のファズテスト
# Zig 0.11+ built-in fuzzing
zig build test --fuzz

# fuzz target in build.zig
# .root_module.fuzz_tests = &.{
#     .{ .name = "parser", .path = "src/fuzz/parser.zig" },
# };

Zig のファジングは、ネイティブターゲット向けの zig test およびサニタイザービルドと統合されています。

14. 辞書ファイル

辞書には、ミューテーションを誘導するための興味深いトークンが含まれます。

# parser.dict
kw1="<"
kw2=">"
kw3="</"
kw4='="'
kw5="\x00"
kw6="\xff\xfe"
./fuzz_parser corpus/ -dict=parser.dict

参考資料

ファズターゲットのテンプレート、コーパスのシード例、OSS-Fuzz の統合ガイダンスについては、references/targets.md を参照してください。

関連スキル

  • ASan/UBSan をファズビルドに追加するには、skills/runtimes/sanitizers を使用してください
  • Clang 固有の libFuzzer フラグについては、skills/compilers/clang を使用してください
  • ファザーが見つけたクラッシュ入力のデバッグには、skills/debuggers/gdb を使用してください
  • Zig の build test --fuzz ワークフローには、skills/zig/zig-testing を使用してください
  • syzkaller によるカーネルファジングには、skills/security/kernel-security を使用してください

コメント