
静的解析による Fuzzable ターゲット発見の自動化フレームワーク

ソフトウェアのセキュリティ評価を行う脆弱性研究者は、多くの場合、AFL++ や libFuzzer のような強力なツールを用いたカバレッジガイドファジングの機能を活用します。これは、バグハンティングプロセスを自動化し、ターゲット内の悪用可能な状態を迅速に明らかにするために重要です。しかし、大規模で複雑なコードベースやクローズドソースのバイナリに遭遇した場合、研究者は手動で監査やリバースエンジニアリングに多くの時間を費やし、ファジングによる探索が有効な関数を特定する必要があります。
Fuzzable は、C/C++ のソースコードとバイナリの両方と統合し、脆弱性研究者がファジングに適した関数ターゲットを特定できるよう支援するフレームワークです。これは、ソフトウェア内の危険な動作とそれを実行する関数を特定するために、静的解析ベースのいくつかのヒューリスティックを適用することで実現されます。研究者はこのフレームワークを利用して基本的なハーネステンプレートを生成し、それを脆弱性の発見や、Google の oss-fuzz プロジェクトのような継続的ファジングパイプラインの一部として使用することができます。
スタンドアロンツールとして実行できるだけでなく、Fuzzable は Binary Ninja ディスアセンブラのプラグインとしても統合されており、他のディスアセンブリバックエンドのサポートも開発中です。
ツールの詳細な技術仕様(静的解析ヒューリスティックの内容や、このツールがどのように生まれたか)を解説した元のブログ記事はこちらをご覧ください。また、このツールは Black Hat Arsenal USA 2022 でも紹介されました。
一部のバイナリターゲットはサニタイズ(シグネチャマッチングやインライン展開からの関数特定など)が必要な場合があり、そのため fuzzable は主に Binary Ninja をディスアセンブリバックエンドとして使用しています。Binary Ninja はこれらの問題を効果的に解決できるからです。そのため、スタンドアロンツールとしてもプラグインとしても利用できます。
Binary Ninja は誰でも利用できるわけではなく、セキュリティ評価やクラウドでのスケーリングのために活用したいという需要もあるため、angr による フォールバック バックエンドもサポートされています。将来的には他のディスアセンブラ(優先順位:Ghidra)も組み込む予定です。
Binary Ninja Commercial をお持ちの場合は、スタンドアロンヘッドレス使用のために API をインストールしてください:
$ python3 /Applications/Binary\ Ninja.app/Contents/Resources/scripts/install_api.py
pip でインストール:
$ pip install fuzzable
依存関係管理とビルドには poetry を使用しています。手動ビルドを行うには、サードパーティモジュールを含めてリポジトリをクローンしてください:
$ git clone --recursive https://github.com/ex0dus-0x/fuzzable
手動インストール:
$ cd fuzzable/
# poetry を使用しない場合
$ pip install .
# poetry を使用する場合
$ poetry install
# 開発用 virtualenv を作成する場合
$ poetry shell
これでツールを使ってバイナリやソースコードを解析できます!
# 単一の共有オブジェクトライブラリバイナリを解析
$ fuzzable analyze examples/binaries/libbasic.so
# 単一の C ソースファイルを解析
$ fuzzable analyze examples/source/libbasic.c
# 複数の C/C++ ファイルとヘッダを含むワークスペースを解析
$ fuzzable analyze examples/source/source_bundle/
fuzzable は、Binary Ninja のプラグインマーケットプレイスから簡単にインストールできます。Binary Ninja > Manage Plugins に移動し、検索してください。以下は fuzzable プラグインが実行され、ファジングおよびさらなる脆弱性評価のためのターゲットを精度よく特定している例です:

fuzzable には解析をより適切に調整するためのさまざまなオプションがあります。今後の計画や機能リクエストに応じて、さらに多くのオプションがサポートされる予定です。
ファジング可能性を判断するために、fuzzable はいくつかのヒューリスティックを使用して、動的解析に最も適したターゲットを特定します。これらのヒューリスティックは scikit-criteria ライブラリを用いて異なる重み付けがされており、このライブラリは 多基準意思決定分析 を使用して最適な候補を決定します。これらのメトリクスとその重みは次のとおりです:
前述のとおり、これらのメトリクスがなぜ、どのように利用されるかについての詳細は、技術ブログ記事をご覧ください。
多くのメトリクスは、Vincenzo Iozzo 氏による 0-knowledge ファジングのオリジナル研究に大きく触発されています。
解析するすべてのターゲットは多様であり、fuzzable はプログラムターゲットのすべてのエッジケース動作を考慮することはできません。そのため、解析中にこれらの重みを適切に 調整 して、異なる結果が自分のユースケースにより適しているかどうかを確認することが重要になる場合があります。CLI で重みを調整するには、--score-weights 引数を指定します:
$ fuzzable analyze <TARGET> --score-weights=0.2,0.2,0.2,0.2,0.2
デフォルトでは、fuzzable は以下の基準に基づいて関数ターゲットをフィルタリングします:
static であり、ヘッダを介して公開されない関数。fuzzable によって除外された呼び出しを確認するには、--list_ignored フラグを設定します:
$ fuzzable analyze --list-ignored <TARGET>
Binary Ninja では、Settings > Fuzzable > List Ignored Calls でこの設定をオンにできます。
fuzzable が誤って解析すべき重要な呼び出しを除外した場合は、--include-* 引数を使用してそれらを実行に含めることをお勧めします:
# 除外されたすべての非トップレベル呼び出しを含める
$ fuzzable analyze --include-nontop <TARGET>
# 除外された特定のシンボルを含める
$ fuzzable analyze --include-sym <SYM> <TARGET>
Binary Ninja では、Settings > Fuzzable > Include non-top level calls と Symbols to Exclude でサポートされています。
ファジングに最適な候補が見つかったら、fuzzable は、ファイルベースのファザー(例:AFL++、Honggfuzz)またはインメモリファザー(libFuzzer)で使用するために、ほぼそのままインストルメントしてコンパイルできるファジングハーネスの生成を支援します。CLI で行う方法は次のとおりです:
# 候補からハーネスを生成
$ fuzzable create-harness target --symbol-name=some_unsafe_call
# ハーネスに必要最小限の修正を加える
$ vim target_some_unsafe_call_harness.cpp
# 生成されたハーネスのコメントに指定されている AFL-QEMU のコンパイル例
$ clang target_some_unsafe_call_harness.cpp -no-pie -o target_some_unsafe_call_harness -ldl
# 基本シードを作成。理想的にはより整形式の入力であるべき
$ mkdir in/
$ echo "seed" >> in/seed
# ブラックボックスファジングを開始
$ afl-fuzz -Q -m none -i in/ -o out/ -- ./target_some_unsafe_call_harness
このターゲットがソースコードベースの場合、汎用ソーステンプレート が使用されます。
ターゲットがバイナリの場合は、汎用ブラックボックステンプレート が使用され、AFL-QEMU のようなファジングエミュレーションモードで使用するのに適しています。シンボルが直接エクスポートされていない場合は、LIEF を使用して dlopen できるように、バイナリのコピーが共有オブジェクトとして作成されます。
現時点では、この機能はかなり初歩的で、適切なパラメータが設定された独立した C++ ハーネスを作成するだけで、ランタイム動作(構造体のインスタンス化や解放など)に必要なコードは自動生成されません。ただし、fuzzable 用に作成されたテンプレートは、それでも素早く実行を開始できるはずです。以下は、今後実装したい意欲的な機能の一部です:
fuzzable は様々な形式でのレポート生成をサポートしています。現在サポートされている形式は、JSON、CSV、Markdown です。これは、自動化の一部として出力をシリアライズ可能な形式で取り込みたい場合に便利です。
CLI では、適切な拡張子を持つファイル名を --export 引数に渡すだけです:
$ fuzzable analyze --export=report.json <TARGET>
Binary Ninja では、Plugins > Fuzzable > Export Fuzzability Report > ... に移動し、エクスポートする形式と書き込み先のパスを選択します。
このツールは継続的に開発されており、外部のメンテナからの支援は大歓迎です!
Fuzzable は MIT ライセンス の下でライセンスされています。
| ヒューリスティック | 説明 | 重み |
|---|
| ファジングフレンドリ名 | シンボル名がファイル/バッファ入力を取り込む動作を示す | 0.3 |
| リスクのあるシンク | 危険な呼び出し(例:memcpy)に流れ込む引数 | 0.3 |
| 自然ループ | 支配境界で検出されたループの数 | 0.05 |
| サイクロマティック複雑度 | エッジ+ノードに基づく関数ターゲットの複雑さ | 0.05 |
| カバレッジ深度 | ターゲットが到達する呼び出し先の数 | 0.3 |