fuzzing-dictionary について
fuzzing-dictionary は、ファザーをより深いコードパスへ導くトークン辞書の作成方法を説明する技術ガイドです。辞書形式や生成方法、複数のファザーでの利用手順を扱います。
主な機能
- 01キーワードとマジック値の登録
- 02テキストと16進エスケープ形式
- 03ヘッダーやバイナリからの抽出
- 04libFuzzer、AFL++、cargo-fuzzでの利用
- 05辞書の調整と問題の診断
活用シーン
- 01JSON、XML、設定ファイルパーサーの調査
- 02HTTP、DNSなどのプロトコル実装のテスト
- 03PNGやPDF処理系の深いロジックへの到達
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ trailofbits/ skills --skill fuzzing-dictionaryインストール後、Claude Code で/fuzzing-dictionaryを入力して読み込まれたか確認します。
同梱ファイルagents/openai.yamlassets/trail-of-bits-mark.svg
詳細
ファジング辞書
ファジング辞書は、ファザーを興味深い入力へと導く、ドメイン固有のトークンを提供します。純粋にランダムな変異を行う代わりに、ファザーは既知のキーワード、マジックナンバー、プロトコルコマンド、形式固有の文字列を取り込みます。これらは、パーサー、プロトコルハンドラー、ファイル形式プロセッサーのより深いコードパスに到達しやすくなります。
概要
辞書は、ターゲットにとって意味のあるトークンを表す、引用符で囲まれた文字列を含むテキストファイルです。ファザーが初期の検証チェックを回避し、ブラインドな変異だけでは到達しにくいコードパスを探索するのに役立ちます。
主な概念
| 概念 | 説明 |
|---|---|
| 辞書エントリ | 引用符で囲まれた文字列(例:"keyword")またはキーと値のペア(例:kw="value") |
| 16 進エスケープ | 印字できない文字のバイト列(例:"\xF7\xF8") |
| トークンの挿入 | ファザーが生成された入力に辞書エントリを挿入します |
| ファザー間で共通の形式 | 辞書ファイルは libFuzzer、AFL++、cargo-fuzz で使用できます |
適用するタイミング
次の場合にこの手法を適用します:
- パーサー(JSON、XML、設定ファイル)をファジングする場合
- プロトコル実装(HTTP、DNS、独自プロトコル)をファジングする場合
- ファイル形式ハンドラー(PNG、PDF、メディアコーデック)をファジングする場合
- 深いロジックに到達する前にカバレッジが頭打ちになる場合
- ターゲットコードが特定のキーワードやマジック値をチェックする場合
次の場合はこの手法をスキップします:
- 形式に関する想定のない純粋なアルゴリズムをファジングする場合
- ターゲットにキーワードベースの解析がない場合
- コーパスですでに高いカバレッジを達成している場合
クイックリファレンス
| タスク | コマンド/パターン |
|---|---|
| libFuzzer で使用 | ./fuzz -dict=./dictionary.dict ... |
| AFL++ で使用 | afl-fuzz -x ./dictionary.dict ... |
| cargo-fuzz で使用 | cargo fuzz run fuzz_target -- -dict=./dictionary.dict |
| ヘッダーファイルから抽出 | grep -o '".*"' header.h > header.dict |
| バイナリから生成 | strings ./binary | sed 's/^/"&/; s/$/&"/' > strings.dict |
手順
ステップ 1:辞書ファイルを作成する
各行に引用符で囲まれた文字列を記述したテキストファイルを作成します。ドキュメントにはコメント(#)を使用します。
辞書形式の例:
# Lines starting with '#' and empty lines are ignored.
# Adds "blah" (w/o quotes) to the dictionary.
kw1="blah"
# Use \\ for backslash and \" for quotes.
kw2="\"ac\\dc\""
# Use \xAB for hex values
kw3="\xF7\xF8"
# the name of the keyword followed by '=' may be omitted:
"foo\x0Abar"
ステップ 2:辞書の内容を生成する
利用できるものに応じて、生成方法を選択します。
LLM から生成する場合: ChatGPT または Claude に次のようにプロンプトを入力します:
A dictionary can be used to guide the fuzzer. Write me a dictionary file for fuzzing a <PNG parser>. Each line should be a quoted string or key-value pair like kw="value". Include magic bytes, chunk types, and common header values. Use hex escapes like "\xF7\xF8" for binary values.
ヘッダーファイルから生成する場合:
grep -o '".*"' header.h > header.dict
man ページから生成する場合(CLI ツール向け):
man curl | grep -oP '^\s*(--|-)\K\S+' | sed 's/[,.]$//' | sed 's/^/"&/; s/$/&"/' | sort -u > man.dict
バイナリ内の文字列から生成する場合:
strings ./binary | sed 's/^/"&/; s/$/&"/' > strings.dict
ステップ 3:辞書をファザーに渡す
ファザーに適したフラグを使用します(上記のクイックリファレンスを参照)。
よくあるパターン
パターン:プロトコルキーワード
用途: HTTP または独自プロトコルハンドラーのファジング
辞書の内容:
# HTTP methods
"GET"
"POST"
"PUT"
"DELETE"
"HEAD"
# Headers
"Content-Type"
"Authorization"
"Host"
# Protocol markers
"HTTP/1.1"
"HTTP/2.0"
パターン:マジックバイトとファイル形式のヘッダー
用途: 画像パーサー、メディアデコーダー、アーカイブハンドラーのファジング
辞書の内容:
# PNG magic bytes and chunks
png_magic="\x89PNG\r\n\x1a\n"
ihdr="IHDR"
plte="PLTE"
idat="IDAT"
iend="IEND"
# JPEG markers
jpeg_soi="\xFF\xD8"
jpeg_eoi="\xFF\xD9"
パターン:設定ファイルのキーワード
用途: 設定ファイルパーサー(YAML、TOML、INI)のファジング
辞書の内容:
# Common config keywords
"true"
"false"
"null"
"version"
"enabled"
"disabled"
# Section headers
"[general]"
"[network]"
"[security]"
高度な使い方
ヒントとコツ
| ヒント | 効果 |
|---|---|
| 複数の生成方法を組み合わせる | LLM が生成したキーワードとバイナリ内の文字列を組み合わせることで、広範囲をカバーできます |
| 境界値を含める | "0"、"-1"、"2147483647" はエッジケースを引き起こします |
| 形式の区切り文字を追加する | :、=、{、} は、ファザーが有効な構造を組み立てるのに役立ちます |
| 辞書の対象を絞る | 数千件よりも 50~200 件の方が高い効果を得られます |
| 辞書の有効性をテストする | 辞書ありとなしで実行し、カバレッジを比較します |
自動生成される辞書(AFL++)
afl-clang-lto コンパイラーを使用すると、AFL++ はバイナリ内の文字列比較から辞書エントリを自動的に抽出します。これは AUTODICTIONARY 機能によってコンパイル時に行われます。
自動辞書を有効にする:
export AFL_LLVM_DICT2FILE=auto.dict
afl-clang-lto++ target.cc -o target
# Dictionary saved to auto.dict
afl-fuzz -x auto.dict -i in -o out -- ./target
複数の辞書を組み合わせる
複数の辞書ファイルに対応しているファザーもあります:
# AFL++ with multiple dictionaries
afl-fuzz -x keywords.dict -x formats.dict -i in -o out -- ./target
アンチパターン
| アンチパターン | 問題 | 正しい方法 |
|---|---|---|
| 完全な文章を含める | ファザーに必要なのは文章ではなく、個別のトークンです | 個々のキーワードに分割します |
| エントリーを重複させる | ミューテーションの予算を無駄にします | sort -u で重複を削除します |
| 辞書が大きすぎる | ファザーの速度が低下し、有用なトークンが埋もれます | 重要度の高い50~200個に絞ります |
| 16進エスケープがない | 印字できないバイトが文字化けします | バイナリ値には \xXX を使用します |
| コメントがない | 保守や監査が難しくなります | # コメントでセクションを説明します |
ツール別のガイダンス
libFuzzer
clang++ -fsanitize=fuzzer,address harness.cc -o fuzz
./fuzz -dict=./dictionary.dict corpus/
統合のヒント:
- ミューテーション中に辞書トークンが挿入または置換されます
- 入力サイズを制御するには、
-max_lenと組み合わせます - 辞書の有効性を示す指標を確認するには、
-print_final_stats=1を使用します -max_lenより長い辞書エントリーは無視されます
AFL++
afl-fuzz -x ./dictionary.dict -i input/ -o output/ -- ./target @@
統合のヒント:
- AFL++ は、複数の辞書を使用するために複数の
-xフラグをサポートしています - 自動生成された辞書には、
afl-clang-ltoとともにAFL_LLVM_DICT2FILEを使用します - 辞書の有効性はファザーの統計 UI に表示されます
- トークンは決定論的ステージとハボックステージで使用されます
cargo-fuzz(Rust)
cargo fuzz run fuzz_target -- -dict=./dictionary.dict
統合のヒント:
- cargo-fuzz は libFuzzer バックエンドを使用するため、libFuzzer の辞書フラグをすべて利用できます
- ハーネスと同じ
fuzz/ディレクトリに辞書ファイルを配置します - ハーネスのディレクトリから次のように指定します:
cargo fuzz run target -- -dict=../dictionary.dict
go-fuzz(Go)
go-fuzz には組み込みの辞書サポートがありませんが、辞書のエントリーを使ってコーパスに手動でシードを追加できます:
# Convert dictionary to corpus files
grep -o '".*"' dict.txt | while read line; do
echo -n "$line" | base64 > corpus/$(echo "$line" | md5sum | cut -d' ' -f1)
done
go-fuzz -bin=./target-fuzz.zip -workdir=.
トラブルシューティング
| 問題 | 原因 | 解決策 |
|---|---|---|
| 辞書ファイルが読み込まれない | パスが間違っているか、形式エラーがある | ファザーの出力で辞書の解析エラーを確認し、ファイル形式を検証します |
| カバレッジが改善しない | 辞書トークンが対象に関連していない | 対象コードを分析して実際のキーワードを確認し、別の生成方法を試します |
| 辞書ファイルの構文エラー | 引用符のエスケープ漏れ、または無効なエスケープ | バックスラッシュには \\、引用符には \" を使用し、テスト実行で検証します |
| ファザーが長いエントリーを無視する | エントリーが -max_len を超えている | エントリーを最大入力長未満にするか、-max_len を増やします |
| エントリーが多すぎてファザーが遅くなる | 辞書が大きすぎる | 重要度の高い50~200個に絞ります |
関連スキル
この手法を使うツール
| スキル | 適用方法 |
|---|---|
| libfuzzer | -dict= フラグによるネイティブの辞書サポート |
| aflpp | -x フラグによるネイティブの辞書サポート。AUTODICTIONARIES による自動生成 |
| cargo-fuzz | libFuzzer バックエンドを使用し、-dict= のサポートを継承 |
関連する手法
| スキル | 関連性 |
|---|---|
| fuzzing-corpus | 辞書はコーパスを補完します。コーパスが構造を提供し、辞書がキーワードを提供します |
| coverage-analysis | カバレッジデータを使用して、辞書の有効性を検証します |
| harness-writing | ハーネスの構造によって、どの辞書トークンが有用かが決まります |
リソース
主な外部リソース
AFL++ 辞書 一般的な形式(HTML、XML、JSON、SQL など)向けの事前構築済み辞書です。形式固有のファジングを始める際に役立ちます。
libFuzzer 辞書のドキュメント 辞書の形式と使い方に関する libFuzzer の公式ドキュメントです。トークンの挿入方法とパフォーマンスへの影響について説明しています。
追加の例
OSS-Fuzz の辞書
Google の継続的ファジングサービスで使用されている、実際の辞書です。プロジェクトのディレクトリで *.dict ファイルを検索すると、実運用の例を確認できます。