libafl
LibAFLは、カスタムファザーを構築するためのモジュール型ファジングライブラリです。高度なファジングが必要な場面や、カスタムミューテーター・非標準のファジングターゲットを扱う際に活用できます。
description の原文を見る
> LibAFL is a modular fuzzing library for building custom fuzzers. Use for advanced fuzzing needs, custom mutators, or non-standard fuzzing targets.
SKILL.md 本文
LibAFL
LibAFL は、AFL++ のような AFL ベースのファザーから機能を実装したモジュラーファジングライブラリです。従来のファザーと異なり、LibAFL は Rust ライブラリとしてすべての機能をモジュール化・カスタマイズ可能な形で提供します。libFuzzer の drop-in 代替品として使用することも、ゼロからカスタムファザーを構築するためのライブラリとしても使用できます。
使用時機
| ファザー | 最適な用途 | 複雑性 |
|---|---|---|
| libFuzzer | 迅速なセットアップ、シングルスレッド | 低 |
| AFL++ | マルチコア、汎用 | 中 |
| LibAFL | カスタムファザー、高度な機能、研究 | 高 |
LibAFL を選択する場合:
- カスタム突然変異戦略またはフィードバック機構が必要
- 標準的なファザーがあなたのターゲットアーキテクチャをサポートしていない
- 新しいファジング技術を実装したい
- ファジングコンポーネントの細かい制御が必要
- ファジング研究を実施している
クイックスタート
LibAFL は最小限のセットアップで libFuzzer の drop-in 代替品として使用できます:
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
// ファザーが提供するデータで自分のコードを呼び出す
my_function(data, size);
return 0;
}
LibAFL の libFuzzer 互換レイヤーをビルドします:
git clone https://github.com/AFLplusplus/LibAFL
cd LibAFL/libafl_libfuzzer_runtime
./build.sh
コンパイルして実行:
clang++ -DNO_MAIN -g -O2 -fsanitize=fuzzer-no-link libFuzzer.a harness.cc main.cc -o fuzz
./fuzz corpus/
インストール
前提条件
- Clang/LLVM 15-18
- Rust (rustup 経由)
- 追加のシステム依存関係
Linux/macOS
Clang をインストール:
apt install clang
または apt.llvm.org 経由で特定バージョンをインストール:
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 15
Rust 用に環境を設定:
export RUSTFLAGS="-C linker=/usr/bin/clang-15"
export CC="clang-15"
export CXX="clang++-15"
Rust をインストール:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
追加の依存関係をインストール:
apt install libssl-dev pkg-config
libFuzzer 互換モードの場合、nightly Rust をインストール:
rustup toolchain install nightly --component llvm-tools
検証
インストールを検証するため LibAFL をビルド:
cd LibAFL/libafl_libfuzzer_runtime
./build.sh
# libFuzzer.a を生成するはず
ハーネスの作成
LibAFL ハーネスは、drop-in 代替モードを使用する場合、libFuzzer と同じパターンに従います:
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
// ファジングターゲットコードをここに記述
return 0;
}
Rust ライブラリとして LibAFL を使用してカスタムファザーを構築する場合、ハーネスロジックはファザーに直接統合されます。完全なパターンについては、以下の「カスタムファザーの作成」セクションを参照してください。
参照: 詳細なハーネス作成技法については、harness-writing 技術スキルを参照してください。
使用モード
LibAFL は 2 つの主要な使用モードをサポートしています:
1. libFuzzer Drop-in 代替品
既存のハーネスで libFuzzer の代替品として LibAFL を使用します。
コンパイル:
clang++ -DNO_MAIN -g -O2 -fsanitize=fuzzer-no-link libFuzzer.a harness.cc main.cc -o fuzz
実行:
./fuzz corpus/
長期キャンペーン推奨:
./fuzz -fork=1 -ignore_crashes=1 corpus/
2. Rust ライブラリとしてのカスタムファザー
LibAFL コンポーネントを使用して完全にカスタマイズされたファザーを構築します。
プロジェクト作成:
cargo init --lib my_fuzzer
cd my_fuzzer
cargo add libafl@0.13 libafl_targets@0.13 libafl_bolts@0.13 libafl_cc@0.13 \
--features "libafl_targets@0.13/libfuzzer,libafl_targets@0.13/sancov_pcguard_hitcounts"
Cargo.toml を設定:
[lib]
crate-type = ["staticlib"]
カスタムファザーの作成
参照: 詳細なハーネス作成技法、複雑な入力処理パターン、 および高度な戦略については、fuzz-harness-writing 技術スキルを参照してください。
ファザーコンポーネント
LibAFL ファザーはモジュラーコンポーネントで構成されています:
- Observers - 実行フィードバックを収集 (カバレッジ、タイミング)
- Feedback - 入力が興味深いかどうかを判定
- Objective - ファジング目標を定義 (クラッシュ、タイムアウト)
- State - コーパスとメタデータを保持
- Mutators - 新しい入力を生成
- Scheduler - 変異する入力を選択
- Executor - ターゲットを入力で実行
基本的なファザー構造
use libafl::prelude::*;
use libafl_bolts::prelude::*;
use libafl_targets::{libfuzzer_test_one_input, std_edges_map_observer};
#[no_mangle]
pub extern "C" fn libafl_main() {
let mut run_client = |state: Option<_>, mut restarting_mgr, _core_id| {
// 1. Observer をセットアップ
let edges_observer = HitcountsMapObserver::new(
unsafe { std_edges_map_observer("edges") }
).track_indices();
let time_observer = TimeObserver::new("time");
// 2. Feedback を定義
let mut feedback = feedback_or!(
MaxMapFeedback::new(&edges_observer),
TimeFeedback::new(&time_observer)
);
// 3. Objective を定義
let mut objective = feedback_or_fast!(
CrashFeedback::new(),
TimeoutFeedback::new()
);
// 4. State を作成または復元
let mut state = state.unwrap_or_else(|| {
StdState::new(
StdRand::new(),
InMemoryCorpus::new(),
OnDiskCorpus::new(&output_dir).unwrap(),
&mut feedback,
&mut objective,
).unwrap()
});
// 5. Mutator をセットアップ
let mutator = StdScheduledMutator::new(havoc_mutations());
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
// 6. Scheduler をセットアップ
let scheduler = IndexesLenTimeMinimizerScheduler::new(
&edges_observer,
QueueScheduler::new()
);
// 7. Fuzzer を作成
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
// 8. ハーネスを定義
let mut harness = |input: &BytesInput| {
let buf = input.target_bytes().as_slice();
libfuzzer_test_one_input(buf);
ExitKind::Ok
};
// 9. Executor をセットアップ
let mut executor = InProcessExecutor::with_timeout(
&mut harness,
tuple_list!(edges_observer, time_observer),
&mut fuzzer,
&mut state,
&mut restarting_mgr,
timeout,
)?;
// 10. 初期入力を読み込む
if state.must_load_initial_inputs() {
state.load_initial_inputs(
&mut fuzzer,
&mut executor,
&mut restarting_mgr,
&input_dir
)?;
}
// 11. ファジングを開始
fuzzer.fuzz_loop(&mut stages, &mut executor, &mut state, &mut restarting_mgr)?;
Ok(())
};
// ファザーを起動
Launcher::builder()
.run_client(&mut run_client)
.cores(&cores)
.build()
.launch()
.unwrap();
}
コンパイル
詳細モード
すべてのインストルメンテーションフラグを手動で指定:
clang++-15 -DNO_MAIN -g -O2 \
-fsanitize-coverage=trace-pc-guard \
-fsanitize=address \
-Wl,--whole-archive target/release/libmy_fuzzer.a -Wl,--no-whole-archive \
main.cc harness.cc -o fuzz
コンパイララッパー (推奨)
インストルメンテーションを自動的に処理する LibAFL コンパイララッパーを作成します。
src/bin/libafl_cc.rs を作成:
use libafl_cc::{ClangWrapper, CompilerWrapper, Configuration, ToolWrapper};
pub fn main() {
let args: Vec<String> = env::args().collect();
let mut cc = ClangWrapper::new();
cc.cpp(is_cpp)
.parse_args(&args)
.link_staticlib(&dir, "my_fuzzer")
.add_args(&Configuration::GenerateCoverageMap.to_flags().unwrap())
.add_args(&Configuration::AddressSanitizer.to_flags().unwrap())
.run()
.unwrap();
}
コンパイルして使用:
cargo build --release
target/release/libafl_cxx -DNO_MAIN -g -O2 main.cc harness.cc -o fuzz
参照: 詳細なサニタイザー設定、一般的な問題、高度なフラグについては、 address-sanitizer および undefined-behavior-sanitizer 技術スキルを参照してください。
キャンペーンの実行
基本的な実行
./fuzz --cores 0 --input corpus/
マルチコアファジング
./fuzz --cores 0,8-15 --input corpus/
これは 9 つのクライアントを実行します: コア 0 に 1 つ、コア 8-15 に 8 つ。
オプション付き
./fuzz --cores 0-7 --input corpus/ --output crashes/ --timeout 1000
Text User Interface (TUI)
グラフィカル統計ビューを有効化:
./fuzz -tui=1 corpus/
出力の解釈
| 出力 | 意味 |
|---|---|
corpus: N | 見つかった興味深いテストケースの数 |
objectives: N | 見つかったクラッシュ/タイムアウトの数 |
executions: N | ターゲット呼び出しの総数 |
exec/sec: N | 現在の実行スループット |
edges: X% | コードカバレッジ率 |
clients: N | 並列ファジングプロセスの数 |
ファザーは 2 つの主要なイベントタイプを出力します:
- UserStats - 現在の統計を持つ定期的なハートビート
- Testcase - 見つかった新しい興味深い入力
高度な使用方法
ヒントとトリック
| ヒント | 利点 |
|---|---|
-fork=1 -ignore_crashes=1 を使用 | 最初のクラッシュ後もファジングを続行 |
InMemoryOnDiskCorpus を使用 | 再起動時にコーパスを永続化 |
TUI を -tui=1 で有効化 | 進行状況をより良く可視化 |
| 特定の LLVM バージョンを使用 | 互換性の問題を回避 |
RUSTFLAGS を正しく設定 | リンクエラーを防止 |
クラッシュ重複排除
同じバグから生じた重複クラッシュの保存を避けます:
バックトレース observer を追加:
let backtrace_observer = BacktraceObserver::owned(
"BacktraceObserver",
libafl::observers::HarnessType::InProcess
);
Executor を更新:
let mut executor = InProcessExecutor::with_timeout(
&mut harness,
tuple_list!(edges_observer, time_observer, backtrace_observer),
&mut fuzzer,
&mut state,
&mut restarting_mgr,
timeout,
)?;
ハッシュフィードバック付きで Objective を更新:
let mut objective = feedback_and!(
feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()),
NewHashFeedback::new(&backtrace_observer)
);
これにより、ユニークなバックトレースを持つクラッシュのみが保存されます。
辞書ファジング
辞書を使用してファジングを特定のトークンに向かわせます:
ファイルからトークンを追加:
let mut tokens = Tokens::new();
if let Some(tokenfile) = &tokenfile {
tokens.add_from_file(tokenfile)?;
}
state.add_metadata(tokens);
Mutator を更新:
let mutator = StdScheduledMutator::new(
havoc_mutations().merge(tokens_mutations())
);
ハードコードされたトークンの例 (PNG):
state.add_metadata(Tokens::from([
vec![137, 80, 78, 71, 13, 10, 26, 10], // PNG ヘッダー
"IHDR".as_bytes().to_vec(),
"IDAT".as_bytes().to_vec(),
"PLTE".as_bytes().to_vec(),
"IEND".as_bytes().to_vec(),
]));
参照: 詳細な辞書作成戦略とフォーマット固有の辞書については、 fuzzing-dictionaries 技術スキルを参照してください。
オートトークン
プログラムからマジック値とチェックサムを自動抽出:
コンパイララッパーで有効化:
cc.add_pass(LLVMPasses::AutoTokens)
ファザーでオートトークンを読み込み:
tokens += libafl_targets::autotokens()?;
トークンセクションを検証:
echo "p (uint8_t *)__token_start" | gdb fuzz
パフォーマンスチューニング
| 設定 | 影響 |
|---|---|
| マルチコアファジング | コア数に対する線形高速化 |
InMemoryCorpus | 高速だが永続化されない |
InMemoryOnDiskCorpus | 速度と永続化のバランス |
| サニタイザー | 2-5 倍の低下、バグ発見に不可欠 |
最適化レベル -O2 | 速度とカバレッジのバランス |
ファザーのデバッグ
単一プロセスモードでファザーを実行してデバッグを容易に:
// ランチャーを直接呼び出しに置き換え
run_client(None, SimpleEventManager::new(monitor), 0).unwrap();
// コメントアウト:
// Launcher::builder()
// .run_client(&mut run_client)
// ...
// .launch()
その後 GDB でデバッグ:
gdb --args ./fuzz --cores 0 --input corpus/
実例
例: libpng
LibAFL を使用して libpng をファジング:
1. ソースコードを取得:
curl -L -O https://downloads.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz
tar xf libpng-1.6.37.tar.xz
cd libpng-1.6.37/
apt install zlib1g-dev
2. コンパイララッパーを設定:
export FUZZER_CARGO_DIR="/path/to/libafl/project"
export CC=$FUZZER_CARGO_DIR/target/release/libafl_cc
export CXX=$FUZZER_CARGO_DIR/target/release/libafl_cxx
3. スタティックライブラリをビルド:
./configure --enable-shared=no
make
4. ハーネスを取得:
curl -O https://raw.githubusercontent.com/glennrp/libpng/f8e5fa92b0e37ab597616f554bee254157998227/contrib/oss-fuzz/libpng_read_fuzzer.cc
5. ファザーをリンク:
$CXX libpng_read_fuzzer.cc .libs/libpng16.a -lz -o fuzz
6. シードを準備:
mkdir seeds/
curl -o seeds/input.png https://raw.githubusercontent.com/glennrp/libpng/acfd50ae0ba3198ad734e5d4dec2b05341e50924/contrib/pngsuite/iftp1n3p08.png
7. 辞書を取得 (オプション):
curl -O https://raw.githubusercontent.com/glennrp/libpng/2fff013a6935967960a5ae626fc21432807933dd/contrib/oss-fuzz/png.dict
8. ファジングを開始:
./fuzz --input seeds/ --cores 0 -x png.dict
例: CMake プロジェクト
LibAFL を CMake ビルドシステムと統合:
CMakeLists.txt:
project(BuggyProgram)
cmake_minimum_required(VERSION 3.0)
add_executable(buggy_program main.cc)
add_executable(fuzz main.cc harness.cc)
target_compile_definitions(fuzz PRIVATE NO_MAIN=1)
target_compile_options(fuzz PRIVATE -g -O2)
インストルメント化されていないバイナリをビルド:
cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ .
cmake --build . --target buggy_program
ファザーをビルド:
export FUZZER_CARGO_DIR="/path/to/libafl/project"
cmake -DCMAKE_C_COMPILER=$FUZZER_CARGO_DIR/target/release/libafl_cc \
-DCMAKE_CXX_COMPILER=$FUZZER_CARGO_DIR/target/release/libafl_cxx .
cmake --build . --target fuzz
ファジングを実行:
./fuzz --input seeds/ --cores 0
トラブルシューティング
| 問題 | 原因 | 解決策 |
|---|---|---|
| カバレッジが増加しない | インストルメンテーション失敗 | コンパイララッパーが使用されたか確認、-fsanitize-coverage をチェック |
| ファザーが起動しない | 空のコーパスで興味深い入力がない | コードパスをトリガーするシード入力を提供 |
libafl_main でのリンカエラー | ランタイムがリンクされていない | -Wl,--whole-archive または -u libafl_main を使用 |
| LLVM バージョン不一致 | LibAFL は LLVM 15-18 を必要とする | 互換 LLVM バージョンをインストール、環境変数を設定 |
| Rust コンパイル失敗 | 古い Rust または Cargo | rustup update で Rust を更新 |
| ファジングが遅い | サニタイザーが有効 | 2-5 倍の低下は予想、バグ発見に必要 |
| 環境変数干渉 | CC, CXX, RUSTFLAGS が設定されている | LibAFL プロジェクトのビルド後に設定解除 |
| デバッガーをアタッチできない | マルチプロセスファジング | シングルプロセスモードで実行 (デバッグセクション参照) |
関連スキル
技術スキル
| スキル | ユースケース |
|---|---|
| fuzz-harness-writing | 効果的なハーネス作成の詳細なガイダンス |
| address-sanitizer | ファジング中のメモリエラー検出 |
| undefined-behavior-sanitizer | 未定義動作の検出 |
| coverage-analysis | コードカバレッジの測定と改善 |
| fuzzing-corpus | シードコーパスの構築と管理 |
| fuzzing-dictionaries | フォーマット認識ファジングの辞書作成 |
関連ファザー
| スキル | 検討時期 |
|---|---|
| libfuzzer | よりシンプルなセットアップ、LibAFL の高度な機能不要 |
| aflpp | カスタムファザー開発なしでマルチコアファジング |
| cargo-fuzz | Rust プロジェクトのファジング、セットアップが少ない |
リソース
公式ドキュメント
- LibAFL Book - 包括的なドキュメント付きの公式ハンドブック
- LibAFL GitHub - ソースコードと例
- LibAFL API Documentation - Rust API リファレンス
例とチュートリアル
- LibAFL Examples - ファザー例の集合
- cargo-fuzz with LibAFL - cargo-fuzz バックエンドとして LibAFL を使用
- Testing Handbook LibAFL Examples - このハンドブックの完全に動作する例
ライセンス: CC-BY-SA-4.0(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- trailofbits
- リポジトリ
- trailofbits/skills
- ライセンス
- CC-BY-SA-4.0
- 最終更新
- 不明
Source: https://github.com/trailofbits/skills / ライセンス: CC-BY-SA-4.0
関連スキル
superfluid
Superfluidプロトコルおよびそのエコシステムに関するナレッジベースです。Superfluidについて情報を検索する際は、ウェブ検索の前にこちらを参照してください。対応キーワード:Superfluid、CFA、GDA、Super App、Super Token、stream、flow rate、real-time balance、pool(member/distributor)、IDA、sentinels、liquidation、TOGA、@sfpro/sdk、semantic money、yellowpaper、whitepaper
civ-finish-quotes
実質的なタスクが真に完了した際に、文明風の儀式的な引用句を追加します。ユーザーやエージェントが機能追加、リファクタリング、分析、設計ドキュメント、プロセス改善、レポート、執筆タスクといった実際の成果物を完成させるときに、明示的な依頼がなくても使用します。短い返信や小さな修正、未完成の作業には適用しません。
nookplot
Base(Ethereum L2)上のAIエージェント向け分散型調整ネットワークです。エージェントがオンチェーンアイデンティティを登録する、コンテンツを公開する、他のエージェントにメッセージを送る、マーケットプレイスで専門家を雇う、バウンティを投稿・請求する、レピュテーションを構築する、共有プロジェクトで協業する、リサーチチャレンジを解くことでNOOKをマイニングする、キュレーションされたナレッジを備えたスタンドアロンオンチェーンエージェントをデプロイする、またはアグリーメントとリワードで収益を得る場合に利用できます。エージェントネットワーク、エージェント調整、分散型エージェント、NOOKトークン、マイニングチャレンジ、ナレッジバンドル、エージェントレピュテーション、エージェントマーケットプレイス、ERC-2771メタトランザクション、Prepare-Sign-Relay、AgentFactory、またはNookplotが言及された場合にトリガーされます。
web3-polymarket
Polygon上でのPolymarket予測市場取引統合です。認証機能(L1 EIP-712、L2 HMAC-SHA256、ビルダーヘッダー)、注文発注(GTC/GTD/FOK/FAK、バッチ、ポストオンリー、ハートビート)、市場データ(Gamma API、Data API、オーダーブック、サブグラフ)、WebSocketストリーミング(市場・ユーザー・スポーツチャネル)、CTF操作(分割、統合、償却、ネガティブリスク)、ブリッジ機能(入金、出金、マルチチェーン)、およびガスレスリレイトランザクションに対応しています。AIエージェント、自動マーケットメーカー、予測市場UI、またはPolygraph上のPolymarketと統合するアプリケーション構築時に活用できます。
ethskills
Ethereum、EVM、またはブロックチェーン関連のリクエストに対応します。スマートコントラクト、dApps、ウォレット、DeFiプロトコルの構築、監査、デプロイ、インタラクションに適用されます。Solidityの開発、コントラクトアドレス、トークン規格(ERC-20、ERC-721、ERC-4626など)、Layer 2ネットワーク(Base、Arbitrum、Optimism、zkSync、Polygon)、Uniswap、Aave、Curveなどのプロトコルとの統合をカバーします。ガスコスト、コントラクトのデシマル設定、オラクルセキュリティ、リエントランシー、MEV、ブリッジング、ウォレット管理、オンチェーンデータの取得、本番環境へのデプロイ、プロトコル進化(EIPライフサイクル、フォーク追跡、今後の変更予定)といったトピックを含みます。
xxyy-trade
このスキルは、ユーザーが「トークン購入」「トークン売却」「トークンスワップ」「暗号資産取引」「取引ステータス確認」「トランザクション照会」「トークンスキャン」「フィード」「チェーン監視」「トークン照会」「トークン詳細」「トークン安全性確認」「ウォレット一覧表示」「マイウォレット」「AIスキャン」「自動スキャン」「ツイートスキャン」「オンボーディング」「IP確認」「IPホワイトリスト」「トークン発行」「自動売却」「損切り」「利益確定」「トレーリングストップ」「保有者」「トップホルダー」「KOLホルダー」などをリクエストした場合、またはSolana/ETH/BSC/BaseチェーンでXXYYを経由した取引について言及した場合に使用します。XXYY Open APIを通じてオンチェーン取引とデータ照会を実現します。