mcpField
A
aflpp

aflpp

github.com/trailofbitsテスト・品質7.9k5.2k 回インストール今日更新
リポジトリ

aflpp について

aflpp スキルは、並列キャンペーンや多様な変異戦略を必要とするプロジェクト向けに、AFL++ファザーを解説するガイドです。導入、ビルド、コーパス管理、実行監視、結果分析を扱います。

主な機能

  1. 01LLVM、GCC、LTOのビルドモード
  2. 02libFuzzer形式のハーネス対応
  3. 03並列ファジングキャンペーン
  4. 04コーパスの最小化と辞書による誘導
  5. 05クラッシュ、カバレッジ、実行状況の分析

活用シーン

  1. 01本番コードベースの並列ファジング
  2. 02libFuzzerのカバレッジ停滞後のテスト継続
  3. 03CIでの自動停止条件の設定

インストール

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

$npx skills add https://github.com/trailofbits/skills --skill aflpp

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

同梱ファイルagents/openai.yamlassets/trail-of-bits-mark.svg

詳細

AFL++

AFL++は、安定性を維持しながら、ファジング性能の向上とより高度な機能を提供する、オリジナルのAFLファザーのフォークです。libFuzzerと比べた大きな利点は、複数コアでのファジングキャンペーンの実行を安定してサポートしていることで、大規模なファジングに最適です。

使用する場面

ファザー最適な用途複雑さ
AFL++マルチコアファジング、多様な変異、成熟したプロジェクト中
libFuzzer手早いセットアップ、シングルスレッド、シンプルなハーネス低
LibAFLカスタムファザー、研究、高度なユースケース高

次の場合はAFL++を選択してください:

  • スループットを最大化するために、マルチコアファジングが必要な場合
  • プロジェクトをClangまたはGCCでコンパイルできる場合
  • 多様な変異戦略と成熟したツールを利用したい場合
  • libFuzzerの進捗が頭打ちになり、より多くのカバレッジが必要な場合
  • 並列実行のメリットがある本番コードベースをファジングする場合

クイックスタート

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    // Call your code with fuzzer-provided data
    check_buf((char*)data, size);
    return 0;
}

コンパイルして実行します:

# Setup AFL++ wrapper script first (see Installation)
./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など、多くの依存関係があります。AFL++でファジングを行う場合は、最新のDebianまたはUbuntuディストリビューションの使用をおすすめします。

方法使用する場面対応コンパイラー
Ubuntu/Debianのリポジトリ最近のUbuntu、基本機能のみUbuntu 23.10:Clang 14およびGCC 13
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 .
ソースから

Ubuntuのバージョン要件と依存関係については、Dockerfileを参照してください。Clangのバージョンを指定するには、LLVM_CONFIGを設定します(例: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 -i \
            --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++

以下の例では、ホストカーネルにアクセスする必要があるシステム設定コマンドを除き、dockerモードを使用します。マシンにインストールされたAFL++に対して実行するには、各コマンドのhostを指定してください。ラッパーはモード引数以降のすべてを1つのシェル文字列にまとめるため、引用符は維持されません。空白を含む引数(-x "my dict.dict"など)は、単語ごとに分割されます。このようなファイルは空白を含まない名前に変更するか、その実行時にラッパーを編集してください。

-tがないのは意図的です。標準入力が端末でない場合(CIジョブや、エージェントまたはスクリプトが操作する場合など)、docker run -tiはthe input device is not a TTYというエラーで中断します。afl-fuzzは端末がないことを検知し、全画面UIの代わりに通常のステータス行を表示します。watchなど、端末を必要とするプログラムは、代わりにラッパーのホスト側で実行する必要があります。$$はラッパーのPIDに展開されるため、並列インスタンスごとに異なるコンテナー名が割り当てられ、単一のafl_fuzzingで名前が衝突することはありません。docker psではCOMMAND列が省略されるため、どの行も同じように見えます。インスタンスを停止する前に、docker ps --no-truncを使用して区別してください。

セキュリティ警告: afl-system-configおよびafl-persistent-configスクリプトにはroot権限が必要で、OSのセキュリティ機能を無効にします。本番システムや開発環境ではファジングを行わないでください。専用のVMを使用してください。

システム設定

再起動のたびに実行すると、1 秒あたりの実行回数が最大 15%増加します。

./afl++ host afl-system-config

afl-system-config は実行対象のカーネルを調整するため、キャンペーンを実行するマシンで実行してください。./afl++ docker afl-system-config を実行すると、ラッパーの --privileged コンテナーを通じて同じ設定を適用できます。AFL++ を Docker のみでインストールしている場合は、この方法を使う必要があります。

パフォーマンスを最大限に高めるには、カーネルのセキュリティ緩和策を無効にします(grub ブートローダーが必要です。Docker ではサポートされていません)。

./afl++ host afl-persistent-config
update-grub
reboot
./afl++ host 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. Validate input size if needed
    if (size < MIN_SIZE || size > MAX_SIZE) return 0;

    // 2. Call target function with fuzz data
    target_function(data, size);

    // 3. Return 0 (non-zero reserved for future use)
    return 0;
}
ハーネスのルール
推奨事項避けるべきこと
実行ごとにグローバル状態をリセットする前回の実行の状態に依存する
エッジケースを適切に処理する無効な入力で終了する
ハーネスの決定性を保つ乱数生成器を使う
確保したメモリを解放するメモリリークを発生させる
入力サイズを検証する上限のない入力を処理する

関連項目: ハーネスの作成方法、複雑な入力を処理するパターン、 高度な手法については、fuzz-harness-writing 技術スキルを参照してください。

コンパイル

AFL++ には、それぞれ異なるトレードオフがある複数のコンパイルモードがあります。

コンパイルモードの選択フロー

コンパイルモードを選択してください。

  • LTO モード(afl-clang-lto):最高のパフォーマンスと計測機能を備えています。まずはこちらをお試しください。
  • LLVM モード(afl-clang-fast):LTO でコンパイルに失敗した場合に切り替えます。
  • GCC プラグイン(afl-gcc-fast):GCC が必要なプロジェクト向けです。
基本的なコンパイル(LLVM モード)
./afl++ docker afl-clang-fast++ -DNO_MAIN=1 -O2 -fsanitize=fuzzer harness.cc main.cc -o fuzz
GCC によるコンパイル
./afl++ docker afl-g++-fast -DNO_MAIN=1 -O2 -fsanitize=fuzzer harness.cc main.cc -o fuzz

重要: GCC のバージョンは、AFL++ の GCC プラグインのコンパイルに使用したバージョンと一致している必要があります。

サニタイザーを使用する場合
./afl++ docker AFL_USE_ASAN=1 afl-clang-fast++ -DNO_MAIN=1 -O2 -fsanitize=fuzzer harness.cc main.cc -o fuzz

関連項目: サニタイザーの詳細な設定、よくある問題、高度なフラグについては、 address-sanitizer および undefined-behavior-sanitizer 技術スキルを参照してください。

ビルドフラグ

-g は不要です。AFL++ コンパイラーによってデフォルトで追加されます。

フラグ用途
-DNO_MAIN=1libFuzzer ハーネスを使用する場合に main 関数を省略する
-O2本番環境向けの最適化レベル(ファジングに推奨)
-fsanitize=fuzzerlibFuzzer 互換モードを有効にし、実行可能ファイルのリンク時にファザーのランタイムを追加する
-fsanitize=fuzzer-no-linkファザーのランタイムをリンクせずに計測する(静的ライブラリとオブジェクトファイル向け)

コーパスの管理

初期コーパスの作成

AFL++ では、空でないシードファイルが少なくとも 1 つ必要です。

mkdir seeds
echo "aaaa" > seeds/minimal_seed

実際のプロジェクトでは、代表的な入力を集めてください。

  • ファジング対象の形式のサンプルファイルをダウンロードする
  • プロジェクトのテストスイートからテストケースを抽出する
  • ファイル形式に適した最小限の有効な入力を使う
コーパスの最小化

キャンペーン後、コーパスを最小化して、カバレッジが重複するものを取り除きます。

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

関連項目: コーパスの作成方法、辞書、シードの選択については、 fuzzing-corpus 技術スキルを参照してください。

キャンペーンの実行

基本的な実行
./afl++ docker afl-fuzz -i seeds -o out -- ./fuzz
環境変数の設定
./afl++ docker AFL_FAST_CAL=1 afl-fuzz -i seeds -o out -- ./fuzz
出力の解釈

AFL++ はどちらのモードでも以下の統計情報を表示しますが、読み取り方はモードによって異なります。ラッパーの docker run -i はコンテナーに TTY を割り当てないため、afl-fuzz は全画面 UI を表示せず、代わりにログへプレーンなステータス行を書き込みます。以下の項目はログと state/<instance>/fuzzer_stats に表示されます。対話型 UI を使うには、ターミナルで host モードを実行するか、ラッパーに -t を追加して、手動で確認しながら実行してください。

出力意味
execs/sec実行速度。高いほど良好です
cycles done完了したキューの巡回回数
corpus countキュー内の一意なテストケースの数
saved crashes検出された一意なクラッシュの数
stability安定しているエッジの割合(100%に近い値が理想です)
出力ディレクトリの構造
out/default/
├── cmdline          # How was the SUT invoked?
├── crashes/         # Inputs that crash the SUT
│   └── id:000000,sig:06,src:000002,time:286,execs:13105,op:havoc,rep:4
├── hangs/           # Inputs that hang the SUT
├── queue/           # Test cases reproducing final fuzzer state
│   ├── id:000000,time:0,execs:0,orig:minimal_seed
│   └── id:000001,src:000000,time:0,execs:8,op:havoc,rep:6,+cov
├── fuzzer_stats     # Campaign statistics
└── plot_data        # Data for plotting
結果の分析

キャンペーンの統計情報をリアルタイムで表示します。

./afl++ docker afl-whatsup out

カバレッジプロットを作成します。aflplusplus イメージには gnuplot-nox がすでに含まれています。ホストモードでは、まず apt install gnuplot で gnuplot をインストールしてください。

./afl++ docker afl-plot out/default out_graph/
テストケースの再実行

out/default/crashes/ 内のファイル名を 1 つ指定します。

./afl++ docker ./fuzz out/default/crashes/id:000000,sig:06,src:000002,time:286,execs:13105,op:havoc,rep:4
ファザーのオプション
オプション用途
-G 4000テスト入力の最大長(デフォルト:1048576 バイト)
-t 1000各テストケースのタイムアウト(ミリ秒、デフォルト:1000ms)
-m 1000メモリ制限(メガバイト、デフォルト:0 = 無制限)
-x ./dict.dictミューテーションを誘導する辞書ファイルを使用します

重要な環境変数

AFL++ には多数の環境変数がありますが、そのほとんどは特殊な用途向けです。実際に重要なのは以下の変数です。

必ず設定する変数
# Every campaign should use tmpfs — SSDs will thank you, and it's faster
AFL_TMPDIR=/dev/shm

AFL_TMPDIR の設定は、デメリットなしでパフォーマンスを向上させます。設定しないと SSD が消耗し、ファジングも遅くなります。

低速なターゲット
# Speeds up calibration ~2.5x — use when targets are slow (e.g., >10 ms/exec)
AFL_FAST_CAL=1

AFL_FAST_CAL は精度をほとんど損なわずにキャリブレーション時間を短縮します。キャリブレーションに時間がかかる低速なターゲットで特に推奨されます。

マルチコアキャンペーン
# On the primary (-M) instance only — needed for afl-cmin, not for fuzzing itself
AFL_FINAL_SYNC=1

# On all instances — cache test cases in memory (default: 50 MB, good range: 50-250 MB)
AFL_TESTCACHE_SIZE=100

AFL_FINAL_SYNC を設定すると、停止時にプライマリーインスタンスがすべてのセカンダリーから最終インポートを行います。これはファジング処理自体には影響しません。後でコーパスの最小化に afl-cmin を実行する際にのみ重要で、プライマリーのキューに結合後のコーパス全体が含まれるようになります。AFL_TESTCACHE_SIZE はテストケースをメモリにキャッシュしてディスク I/O を削減します。デフォルトは 50 MB で、ほとんどのキャンペーンでは 50~250 MB の値が適しています。

CI/自動ファジング
# Fail fast if fuzzing isn't finding anything
AFL_EXIT_ON_TIME=3600  # 1 hour with no new paths = stop

# Or run until "done" (all queue entries processed)
AFL_EXIT_WHEN_DONE=1

# Headless environments
AFL_NO_UI=1

CI で制限なくファジングを行うとリソースを浪費します。時間制限を設定するか、終了条件を使用してください。

使用を避ける変数
変数避ける理由
AFL_NO_ARITHバイナリ形式ではカバレッジが低下する可能性がありますが、テキストベースのターゲットでは役立つ場合があります
AFL_SHUFFLE_QUEUE特殊な構成向けで、通常は有害です
AFL_DISABLE_TRIMトリミングは有効です。理由なく無効にしないでください

マルチコアファジング

AFL++ は、次の 2 つの大きな利点により、マルチコアファジングに優れています。

  1. 1 秒あたりの実行回数が増加します(物理コア数に比例して拡張します)
  2. 非対称なファジングが可能です(例:ASan を使用するジョブを 1 つ、サニタイザーなしのジョブを残りに割り当てる)
キャンペーンの開始

プライマリーファザーを起動します(バックグラウンドで実行)。

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

セカンダリーファザーを起動します(コア数に合わせて起動します)。

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

</dev/null は必須であり、装飾ではありません。docker run -i はクライアントが自身の標準入力を読み取る状態を維持します。バックグラウンド化されたプロセスがターミナルを読み取ると SIGTTIN が送信され、デフォルトの動作でプロセスが停止します。そのため、リダイレクトがないと、これらのジョブは jobs で Stopped と表示され、ファジングを開始しません。

マルチコアキャンペーンの監視

実行中のジョブをすべて一覧表示します。

jobs

統計情報をリアルタイムで表示します。watch の実行にはターミナルが必要ですが、docker run -i ではターミナルが提供されないため、コンテナ内で watch を実行するのではなく、呼び出し全体をラップしてください。実行のたびにコンテナが起動するため、間隔は 1 秒ではなく 5 秒です。

watch -n5 --color ./afl++ docker afl-whatsup state/
すべてのファザーの停止
kill $(jobs -p)

カバレッジ分析

AFL++ はエッジ計測によってカバレッジを自動的に追跡します。カバレッジ情報は fuzzer_stats と plot_data に保存されます。

カバレッジの測定

afl-plot を使用して、時間の経過に伴うカバレッジを可視化します。

./afl++ docker afl-plot out/default out_graph/
カバレッジの改善
  • フォーマットを考慮したファジングには辞書を使用します
  • キャンペーンを長時間実行します(cycles_wo_finds は頭打ちの状態を示します)
  • マルチコアファジングで別のミューテーション戦略を試します
  • カバレッジの不足箇所を分析し、対象を絞ったシード入力を追加します

関連項目: カバレッジ分析の手法、カバレッジの不足箇所の特定、体系的なカバレッジ改善について詳しくは、coverage-analysis 技術スキルを参照してください。

CMPLOG

CMPLOG/RedQueen は、あらゆるファザーで利用できるパス制約解決メカニズムの中で最も優れています。 有効にするには、ファズターゲットを CMPLOG 用にインストルメントする必要があります。 ファズターゲットをビルドする前に、環境変数を設定します。

./afl++ docker AFL_LLVM_CMPLOG=1 make

ハーネスのコンパイルとリンクに特別な操作は必要ありません。

CMPLOG でインストルメントしたファズターゲットを使用してファザーインスタンスを実行するには、コマンドライン引数に -c0 を追加します。

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

サニタイザーの統合

サニタイザーは、すぐにはクラッシュを引き起こさないメモリ破損バグを見つけるために不可欠です。

AddressSanitizer(ASan)
./afl++ docker AFL_USE_ASAN=1 afl-clang-fast++ -DNO_MAIN=1 -O2 -fsanitize=fuzzer harness.cc main.cc -o fuzz

注: 20TB の仮想メモリを予約するため、ASan ではメモリ制限(-m)はサポートされていません。

UndefinedBehaviorSanitizer(UBSan)
./afl++ docker AFL_USE_UBSAN=1 afl-clang-fast++ -DNO_MAIN=1 -O2 -fsanitize=fuzzer,undefined harness.cc main.cc -o fuzz
サニタイザーに関する一般的な問題
問題解決策
ASan によってファジングが遅くなるマルチコア構成では ASan のジョブを 1 つだけ使用する
スタックの枯渇ASAN_OPTIONS=stack_size=... でスタックを増やす
GCC のバージョン不一致システムの GCC が AFL++ プラグインのバージョンと一致していることを確認する

関連項目: サニタイザーの設定とトラブルシューティングの詳細については、 address-sanitizer 技術スキルを参照してください。

高度な使い方

ヒントとコツ
ヒント効果
可能であれば LLVMFuzzerTestOneInput ハーネスを使用するファジングキャンペーンの安定性が 85% 以上なら、これが最も効率的なファジング方式です。そうでない場合は、標準入力またはファイル入力によるファジングを試してください
辞書を使用するファザーが形式固有のキーワードやマジックバイトを検出しやすくなります
現実的なタイムアウトを設定するシステム負荷による誤検出を防ぎます
入力サイズを制限する入力が大きくても、探索範囲が広がるとは限りません
安定性を監視する安定性が低い場合、動作が非決定的であることを示しています
標準入力によるファジング

AFL++ では、libFuzzer ハーネスなしで標準入力から読み込むプログラムをファジングできます。

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

これは永続モードより遅いですが、ハーネスコードは必要ありません。

ファイル入力によるファジング

ファイルを読み込むプログラムには、プレースホルダー @@ を使用します。

./afl++ docker afl-clang-fast++ -O2 main_file.c -o fuzz_file
./afl++ 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>\n", 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++ docker afl-clang-fast++ -O2 main_arg.c -o fuzz_arg
./afl++ docker afl-fuzz -i seeds -o out -- ./fuzz_arg
パフォーマンスの調整
設定影響
CPU コア数物理コア数に比例してスケーリングします
永続モードフォークサーバーより 10~20 倍高速です
-G 入力サイズ制限小さいほど高速になりますが、バグを見逃す可能性があります
ASan の割合ASan のジョブ 1 つにつき、ASan なしのジョブを 4~8 つ実行します

トラブルシューティング

問題原因解決策
実行数/秒が低い(1k 未満)永続モードを使用していないLLVMFuzzerTestOneInput 形式のハーネスを作成する
安定性が低い(85% 未満)非決定的なコード標準入力またはファイル入力でプログラムをファジングするか、そのようなハーネスを作成する
GCC プラグインのエラーGCC のバージョン不一致システムの GCC が AFL++ のビルドと一致していることを確認し、gcc-$GCC_VERSION-plugin-dev をインストールする
クラッシュが見つからないサニタイザーが必要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 リポジトリ 包括的なドキュメント、サンプル、課題トラッカーを掲載した公式リポジトリです。

ファジングの詳細 AFL++ チームによる高度なドキュメントで、計装モード、最適化手法、高度なユースケースを解説しています。

AFL++ の内部構造 AFL++ の内部構造、変異戦略、カバレッジ追跡の仕組みを詳しく解説しています。

AFL++:ファジング研究の段階的な成果を組み合わせる AFL++ のアーキテクチャと、元の AFL と比べたパフォーマンス向上について説明した研究論文です。

動画リソース

コメント