
AFL/QEMUによるフルシステムエミュレーションでのファジング。
新着: TriforceAFLとTLSFを試してみたい方のために、Richard Johnsonが両方をインストールするDockerfile(さらにLinuxカーネルまでビルドしてくれます)を作成しました。こちらから入手できます https://hub.docker.com/r/moflow/afl-triforce/tags/。
もう1つの新着: afl-tminがフォークサーバーに対応しました!
https://github.com/nccgroup/TriforceAFL Jesse Hertz [email protected] Tim Newsham [email protected]
これはQEMUを使用したフルシステムファジングをサポートするAFLのパッチ版です。 同梱のQEMUは、x86_64のシステムエミュレータを実行する際にブランチの トレースを可能にするよう更新されています。AFLのフォークサーバーを起動し、 ファズ設定を行い、テストケースの開始と終了をマークするための 追加命令が組み込まれています。
注: すべてのAFLツールが新しい変更でテストされたわけではありません。 以下のツールはある程度テストされています:
ビルド方法:
make
カバレッジマップを取得するには:
echo hello > /tmp/hello
./afl-showmap -o coverage.txt -QQ --
./afl-qemu-system-trace -kernel ../bzImage
-initrd ../initramfs.cpio.gz -m 1G -nographic
-append "console=ttyS0" -aflFile /tmp/hello
cat coverage.txt
ファズするには:
egrep ' (panic|log_store)$' ../mykern/kallsyms ffffffff8108e570 t log_store ffffffff8181064b T panic
mkdir inputs
echo hello > inputs/hello
./afl-fuzz -i inputs -o outputs -QQ --
afl-qemu-system-trace -kernel bzImage -initrd root.cpio.gz
-m 1G -nographic -append "console=ttyS0"
-aflPanicAddr ffffffff8181064b -aflDmesgAddr ffffffff8108e570
-aflFile @@
(注: "-Q"オプションを使用する場合とは異なり、"-QQ"オプションを使用する場合は、 afl-qemu-system-traceへの完全なコマンドラインを指定する必要があります)。
この修正版AFLの使用方法の詳細については、 Linuxシステムコールファザーを参照してください: https://github.com/nccgroup/TriforceLinuxSyscallFuzzer.
新しいAFLフラグ: -QQ - ユーザーモード(-Q)ではなくフルシステムエミュレーションでQEMUを使用
新しいQEMUフラグ: -aflFile - ファザーの入力が含まれるファイルの名前 -aflPanicAddr - パニック検出用のカーネルパニックアドレス -aflDmesgAddr - ロギングの検出とログメッセージの傍受のための dmesgログ機能のLinuxカーネルアドレス
新しいQEMU命令: 0f 24 - aflCall edi=1 startForkserver(esi=enableTicks) AFLのフォークサーバーを起動します。この時点以降、各テストは フォークされた別々の子プロセスで実行されます。enableTicksが 非ゼロの場合、QEMUは子プロセスをフォークした後にCPUタイマーを 再度有効にします。それ以外の場合は有効になりません。 edi=2 getWork(esi=ptr, edx=sz) ptr[0..sz]に次の入力テストケースを格納します。実際に 格納されたサイズ(<= sz)を返します。 edi=3 startWork(esi=ptr) AFLにトレースの開始を指示します。引数は、トレースするコードの 開始アドレスと終了アドレスを示す2つのクアドワードを持つ バッファを指します。この範囲外の命令はトレースされません。 edi=4 doneWork(esi=exitCode) AFLにテストケースが完了したことを通知します。パニックが 検出された場合、AFLはテストケースを即座に停止します。 それ以外の場合は、doneWorkが呼び出されるまで実行を続けます。 指定されたexitCodeはAFLに返されます。(コードは、テストケース中に dmesgログが検出された場合、すべての終了コードに値64をOR演算 することができますが、現在は行われていません。)
新しいQEMUブロックドライバ: -drive filename=privmem: このブロックドライバは、ドライブのイメージをコピーオンライトメモリに 保持するため、変更がディスクに永続化されることはありません。 あるテストケースによる変更は、他のテストケースから分離されます。
Written and maintained by Michal Zalewski [email protected]
Copyright 2013, 2014, 2015, 2016 Google Inc. All rights reserved. Released under terms and conditions of Apache License, Version 2.0.
新バージョンや追加情報については、以下を参照してください: http://lcamtuf.coredump.cx/afl/
他のユーザーと情報交換したり、主要な新機能の通知を受け取るには、 [email protected] にメールを送信してください。
** このファイルを読む時間がない場合は、QuickStartGuide.txtを参照してください。 **
ファジングは、実世界のソフトウェアにおけるセキュリティ問題を特定するための、 最も強力で実績のある戦略の1つです。これまでにセキュリティ上重要な ソフトウェアで発見されたリモートコード実行や権限昇格のバグの大半は、 ファジングによるものです。
残念ながら、ファジングは比較的浅いものでもあります。盲目的でランダムな 変異では、テスト対象コードの特定のコードパスに到達する可能性は非常に低く、 一部の脆弱性はこの手法の射程外に取り残されます。
この問題を解決するための試みは数多く行われてきました。初期のアプローチの 1つであるコーパス蒸留は、Tavis Ormandyによって先駆けられました。この方法は、 カバレッジシグナルを利用して、大規模で高品質な候補ファイルのコーパスから 興味深いシードのサブセットを選択し、それを従来の手段でファズします。この アプローチは非常にうまく機能しますが、そのようなコーパスがすぐに利用可能で ある必要があります。さらに、ブロックカバレッジの測定はプログラム状態の 非常に単純な理解しか提供せず、長期的なファジングの方向付けにはあまり 役立ちません。
その他のより高度な研究は、プログラムフロー解析(「コノリック実行」)、 シンボリック実行、静的解析などの技術に焦点を当てています。これらの方法は すべて実験環境では非常に有望ですが、実用においては信頼性とパフォーマンスの 問題に悩まされる傾向があり、現時点では「愚かな」ファジング技術に代わる 実行可能な選択肢を提供していません。
American Fuzzy Lopは、非常にシンプルながら堅牢な計装ガイド式遺伝的 アルゴリズムと組み合わされたブルートフォースファザーです。プログラムの 制御フローに対する微妙で局所的な変化を簡単に検出するために、修正された 形式のエッジカバレッジを使用します。
少し単純化すると、アルゴリズム全体は次のように要約できます:
ユーザーが提供した初期テストケースをキューに読み込む、
キューから次の入力ファイルを取り出す、
プログラムの測定された動作を変えない最小サイズまでテストケースを 削減する、
バランスが取れ、よく研究されたさまざまな従来のファジング戦略を 使用してファイルを繰り返し変異させる、
生成された変異のいずれかが、計装によって記録された新しい状態遷移を もたらした場合、変異した出力をキューの新しいエントリとして追加する。
2に戻る。
発見されたテストケースは、より新しくカバレッジの高い発見によって陳腐化した ものを排除するために定期的に間引かれ、さらにいくつかの計装駆動型の労力 最小化ステップを受けます。
ファジングプロセスの副次的な結果として、このツールは興味深いテストケースの 小さな自己完結型コーパスを作成します。これらは、他の労力やリソースを大量に 消費するテスト体制のシードとして非常に役立ちます。例えば、ブラウザ、 オフィスアプリケーション、グラフィックススイート、またはクローズドソース ツールのストレステストなどです。
このファザーは、盲目的ファジングやカバレッジのみのツールよりもはるかに 優れた即時パフォーマンスを提供するよう徹底的にテストされています。
ソースコードが利用可能な場合、サードパーティコードの標準的なビルドプロセス においてgccやclangのドロップイン置換として機能するコンパニオンツールに よって計装を注入できます。
計装のパフォーマンスへの影響はかなり控えめです。afl-fuzzが実装する他の 最適化と組み合わせることで、ほとんどのプログラムは従来のツールと同程度か、 それ以上の速度でファズできます。
ターゲットプログラムを再コンパイルする正しい方法はビルドプロセスの詳細に よって異なる場合がありますが、ほぼ普遍的なアプローチは次のとおりです:
$ CC=/path/to/afl/afl-gcc ./configure $ make clean all
C++プログラムの場合は、CXX=/path/to/afl/afl-g++も設定する必要があります。
clangラッパー(afl-clangおよびafl-clang++)も同じように使用できます。 clangユーザーは、llvm_mode/README.llvmで説明されているように、より高性能な 計装モードを利用することもできます。
ライブラリをテストする場合、stdinまたはファイルからデータを読み取り、 テスト対象のライブラリに渡す単純なプログラムを見つけるか作成する必要が あります。そのような場合、この実行可能ファイルを計装済みライブラリの静的 バージョンにリンクするか、実行時に正しい.soファイルがロードされるように することが不可欠です(通常はLD_LIBRARY_PATHを設定します)。最も簡単な方法は 静的ビルドで、通常は次のようにして可能です:
$ CC=/path/to/afl/afl-gcc ./configure --disable-shared
'make'を呼び出すときにAFL_HARDEN=1を設定すると、CCラッパーが自動的に コードハードニングオプションを有効にし、単純なメモリバグの検出が 容易になります。
追記: ASANユーザーは、重要な注意事項についてnotes_for_asan.txtファイルを 確認することをお勧めします。
ソースコードが利用できない場合、ファザーはブラックボックスバイナリの 高速なオンザフライ計装の実験的サポートを提供します。これは、あまり知られて いない「ユーザースペースエミュレーション」モードで動作するQEMUの バージョンによって実現されます。
QEMUはAFLとは別のプロジェクトですが、次のようにしてこの機能を簡単に ビルドできます:
$ cd qemu_mode $ ./build_qemu_support.sh
追加の手順と注意事項については、qemu_mode/README.qemuを参照してください。
このモードはコンパイル時計装より約2〜5倍遅く、並列化にはあまり適しておらず、 その他の癖がある場合もあります。
正しく動作するために、ファザーには、対象アプリケーションが通常期待する 入力データの適切な例を含む1つ以上の開始ファイルが必要です。基本的な ルールは2つあります:
ファイルは小さく保ってください。1 kB未満が理想的ですが、厳密に 必要というわけではありません。サイズが重要な理由については、 perf_tips.txtを参照してください。
複数のテストケースは、互いに機能的に異なる場合にのみ使用してください。 画像ライブラリをファズするために50枚の異なるバケーション写真を 使っても意味がありません。
このツールに付属するtestcases/サブディレクトリには、開始ファイルの良い例が 多数あります。
追記: スクリーニング用に大量のデータコーパスが利用可能な場合、afl-cmin ユーティリティを使用して、ターゲットバイナリの異なるコードパスを実行する 機能的に異なるファイルのサブセットを特定するとよいでしょう。
ファジングプロセス自体はafl-fuzzユーティリティによって実行されます。この プログラムには、初期テストケースを含む読み取り専用ディレクトリ、調査結果を 保存するための別の場所、そしてテストするバイナリへのパスが必要です。
stdinから直接入力を受け付けるターゲットバイナリの場合、通常の構文は 次のとおりです:
$ ./afl-fuzz -i testcase_dir -o findings_dir /path/to/program [...params...]
ファイルから入力を受け取るプログラムの場合は、'@@'を使用して、入力ファイル名を 配置するターゲットのコマンドライン上の位置をマークします。ファザーがこれを 置き換えてくれます:
$ ./afl-fuzz -i testcase_dir -o findings_dir /path/to/program @@
-fオプションを使用すると、変異したデータを特定のファイルに書き込むことも できます。これは、プログラムが特定のファイル拡張子などを期待する場合に 便利です。
計装されていないバイナリは、QEMUモード(コマンドラインに-Qを追加)または 従来の盲目的ファザーモード(-nを指定)でファズできます。
-tおよび-mを使用して、実行されるプロセスのデフォルトのタイムアウトと メモリ制限を上書きできます。これらの設定の調整が必要になる可能性のある ターゲットのまれな例としては、コンパイラやビデオデコーダがあります。
ファジングパフォーマンスを最適化するためのヒントは、perf_tips.txtで 説明されています。
afl-fuzzは、一連の決定的なファジングステップを実行することから始まり、 これには数日かかる場合があることに注意してください。zzufやhonggfuzzと 同様に、すぐに簡易的な結果を得たい場合は、コマンドラインに-dオプションを 追加してください。
表示される統計情報の解釈とプロセスの健全性の監視方法については、 status_screen.txtファイルを参照してください。特にUI要素が赤でハイライト されている場合は、必ずこのファイルを確認してください。
ファジングプロセスは、Ctrl-Cを押すまで継続されます。最低でも、ファザーに 1回のキューレングルを完了させる必要があります。これには数時間から1週間程度 かかる場合があります。
出力ディレクトリ内には3つのサブディレクトリが作成され、リアルタイムで 更新されます:
queue/ - 特徴的な実行パスごとのテストケースと、ユーザーが指定した すべての開始ファイル。これはセクション2で言及された合成 コーパスです。
このコーパスを他の目的に使用する前に、afl-cminツールを
使用してより小さなサイズに縮小できます。このツールは、
同等のエッジカバレッジを提供するより小さなファイルの
サブセットを見つけます。
crashes/ - テスト対象プログラムが致命的なシグナル(例: SIGSEGV、SIGILL、 SIGABRT)を受信する原因となる一意のテストケース。エントリは 受信したシグナルごとにグループ化されています。
hangs/ - テスト対象プログラムがタイムアウトする原因となる一意の テストケース。デフォルトの(積極的な)タイムアウト設定が 有効な場合、レイテンシのスパイクやその他の自然現象により、 ややノイズが多くなることがあることに注意してください。
クラッシュとハングは、関連する実行パスが以前に記録された障害では見られなかった 状態遷移を含む場合に「一意」と見なされます。単一のバグに複数の方法で到達 できる場合、プロセスの初期にはカウントがいくらか膨らみますが、これはすぐに 収束するはずです。
クラッシュとハングのファイル名は、親の非障害キューのエントリと関連付けられて います。これはデバッグに役立ちます。
afl-fuzzによって発見されたクラッシュを再現できない場合、最も可能性の高い 原因は、ツールが使用するのと同じメモリ制限を設定していないことです。 試してみてください:
$ LIMIT_MB=50 $ ( ulimit -Sv $[LIMIT_MB << 10]; /path/to/tested_binary ... )
LIMIT_MBをafl-fuzzに渡された-mパラメータに合わせて変更してください。 OpenBSDでは、-Svも-Sdに変更してください。
既存の出力ディレクトリを使用して、中断されたジョブを再開することもできます。 試してみてください:
$ ./afl-fuzz -i- -o existing_output_dir [...etc...]
gnuplotがインストールされている場合、afl-plotを使用してアクティブなファジング タスクのグラフを生成することもできます。どのようなものかの例については、 http://lcamtuf.coredump.cx/afl/plot/ を参照してください。
afl-fuzzの各インスタンスはおおよそ1コアを占有します。つまり、マルチコア システムでは、ハードウェアを完全に活用するために並列化が必要です。複数の コアまたは複数のネットワーク接続されたマシンで共通のターゲットをファズする 方法のヒントについては、parallel_fuzzing.txtを参照してください。
デフォルトでは、afl-fuzzの変異エンジンは、画像、マルチメディア、圧縮データ、 正規表現構文、シェルスクリプトなどのコンパクトなデータ形式向けに最適化されて います。特に冗長で過剰な表現を持つ言語(代表的なものとしてHTML、SQL、 JavaScript)にはやや適していません。
構文を認識するツールを構築する手間を避けるために、afl-fuzzは、対象の データ型に関連する言語キーワード、マジックヘッダー、その他の特別なトークンの オプションのディクショナリをファジングプロセスにシードし、それを使用して その場で基礎となる文法を再構築する方法を提供します:
http://lcamtuf.blogspot.com/2015/01/afl-fuzz-making-up-grammar-with.html
この機能を使用するには、まずtestcases/README.testcasesで説明されている 2つの形式のいずれかでディクショナリを作成し、次にコマンドラインの-x オプションでファザーにそれを指定する必要があります。
基礎となる構文のより構造化された記述を提供する方法はありませんが、ファザーは 計装フィードバックだけに基づいてその一部を把握する可能性があります。これは 実際に機能します。たとえば:
http://lcamtuf.blogspot.com/2015/04/finding-bugs-in-sqlite-easy-way.html
追記: 明示的なディクショナリが指定されていない場合でも、afl-fuzzは決定的な バイトフリップ中に計装を非常に注意深く監視することで、入力コーパス内の既存の 構文トークンを抽出しようとします。これは一部のタイプのパーサーと文法で 機能しますが、-xモードほど優れているわけではありません。
カバレッジベースのクラッシュのグループ化は、通常、手動または非常に単純な GDBやValgrindスクリプトで迅速にトリアージできる小さなデータセットを生成 します。すべてのクラッシュは、キュー内の親の非クラッシュテストケースに 追跡可能であり、障害の診断が容易になります。
とはいえ、多くのデバッグとコード解析作業なしに、一部のファジングクラッシュの 悪用可能性を迅速に評価することが難しい場合があることを認識することが重要です。 この作業を支援するために、afl-fuzzは-Cフラグで有効になる非常にユニークな 「クラッシュ探索」モードをサポートしています。
このモードでは、ファザーは1つ以上のクラッシュするテストケースを入力として 受け取り、フィードバック駆動型のファジング戦略を使用して、プログラムを クラッシュ状態に保ちながら到達可能なすべてのコードパスを非常に迅速に 列挙します。
クラッシュを引き起こさない変異は拒否されます。実行パスに影響を与えない変更も 同様に拒否されます。
出力は小さなファイルのコーパスで、攻撃者が障害アドレスに対してどの程度の 制御を持っているか、あるいは最初の範囲外読み取りを通過してその先に何が あるかを確認できるかどうかを、非常に迅速に調べることができます。
ああ、もう1つ: テストケースの最小化には、afl-tminを試してみてください。 このツールは非常に簡単な方法で操作できます:
$ ./afl-tmin -i test_case -o minimized_result -- /path/to/program [...]
このツールは、クラッシュするテストケースとクラッシュしないテストケースの 両方で動作します。クラッシュモードでは、計装されたバイナリと計装されて いないバイナリの両方を問題なく受け入れます。非クラッシュモードでは、 ミニマイザーは標準のAFL計装に依存して、実行パスを変えずにファイルをより 単純にします。
ミニマイザーは、afl-fuzzと互換性のある方法で-m、-t、-fおよび@@構文を 受け入れます。
AFLへの最近の追加機能のもう1つは、afl-analyzeツールです。これは入力ファイルを 受け取り、バイトを順番に反転させて、テスト対象プログラムの動作を観察します。 次に、どのセクションが重要であると思われるか、どのセクションが重要でないかに 基づいて入力を色分けします。完璧ではありませんが、複雑なファイル形式について の迅速な洞察を提供できることがよくあります。その動作の詳細については、 technical_details.txtの末尾近くを参照してください。
他の多くの計算負荷の高いタスクと同様に、ファジングはハードウェアとOSに 負担をかける可能性があることに留意してください。特に:
CPUは高温になり、適切な冷却が必要になります。ほとんどの場合、冷却が 不十分であるか正常に動作しなくなると、CPU速度は自動的に制限されます。 とはいえ、特にあまり適していないハードウェア(ラップトップ、スマートフォン など)でファジングする場合、何かが故障する可能性がまったくないわけでは ありません。
対象のプログラムが、不安定に数ギガバイトのメモリを消費したり、 ジャンクファイルでディスク容量をいっぱいにしたりする可能性があります。 AFLは基本的なメモリ制限を強制しようとしますが、考えられるすべての 事故を防ぐことはできません。つまり、データ損失の可能性が許容できない リスクであるシステムでファジングを行うべきではありません。- ファジングでは、ファイルシステムへの読み書きが何十億回も発生します。最近の システムでは、これは通常かなりキャッシュされ、「物理的な」I/Oは比較的 控えめになりますが、この状況を変え得る要因は数多くあります。 潜在的な問題を監視するのはあなたの責任です。非常に重いI/Oでは、 多くのHDDやSSDの寿命が縮まる可能性があります。
LinuxでディスクI/Oを監視する良い方法は、'iostat'コマンドです:
$ iostat -d 3 -x -k [...optional disk ID...]
AFLに関する最も重要な注意点のいくつかを以下に示します:
AFLは、最初に生成されたプロセスがシグナル(SIGSEGV、SIGABRTなど)により 終了したことで障害を検出します。これらのシグナルにカスタムハンドラを インストールするプログラムでは、関連コードをコメントアウトする必要が ある場合があります。同様に、ファズ対象が生成した子プロセスでの障害は、 それを捕捉するコードを手動で追加しない限り、検出を逃れる可能性があります。
他のブルートフォースツールと同様に、テスト対象の実際のデータ形式が 暗号化、チェックサム、暗号署名、または圧縮で完全にラップされている場合、 ファザーのカバレッジは限定的になります。
これを回避するには、関連するチェックをコメントアウトできます(参考として experimental/libpng_no_checksum/ を参照)。それが不可能な場合は、 experimental/post_library/ で説明されているように、 ポストプロセッサを作成することもできます。
ASANと64ビットバイナリには、残念ながらいくつかのトレードオフがあります。 これはafl-fuzzの特定の欠陥によるものではありません。ヒントについては notes_for_asan.txt を参照してください。
ネットワークサービス、バックグラウンドデーモン、またはUI操作を必要とする 対話型アプリのファジングは直接サポートされていません。これらをより 従来の方法で動作させるには、簡単なコード変更が必要になる場合があります。 Preenyも比較的簡単な選択肢を提供するかもしれません - 参照: https://github.com/zardus/preeny
ネットワークベースのサービスを変更するための有用なヒントは、次の場所にもあります: https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop
AFLは人間が読める形式のカバレッジデータを出力しません。カバレッジを 監視したい場合は、Michael Rashによるafl-covを使用してください:https://github.com/mrash/afl-cov
この他にも、プラットフォーム固有のヒントについてはINSTALLを参照してください。
afl-fuzzへの改善の多くは、以下からのフィードバック、バグ報告、パッチが なければ実現できなかったでしょう:
Jann Horn Hanno Boeck Felix Groebert Jakub Wilk Richard W. M. Jones Alexander Cherepanov Tom Ritter Hovik Manucharyan Sebastian Roschke Eberhard Mattes Padraig Brady Ben Laurie @dronesec Luca Barbato Tobias Ospelt Thomas Jarosch Martin Carpenter Mudge Zatko Joe Zbiciak Ryan Govostes Michael Rash William Robinet Jonathan Gray Filipe Cabecinhas Nico Weber Jodie Cunningham Andrew Griffiths Parker Thompson Jonathan Neuschfer Tyler Nighswander Ben Nagy Samir Aguiar Aidan Thornton Aleksandar Nikolich Sam Hakim Laszlo Szekeres David A. Wheeler Turo Lamminen Andreas Stieger Richard Godbee Louis Dassy teor2345 Alex Moneger Dmitry Vyukov Keegan McAllister Kostya Serebryany Richo Healey Martijn Bogaard rc0r Jonathan Foote Christian Holler Dominique Pelle Jacek Wielemborek Leo Barnes Jeremy Barnes Jeff Trull Guillaume Endignoux ilovezfs Daniel Godas-Lopez Franjo Ivancic
ありがとうございます!
質問? 懸念事項? バグ報告? 作者には通常、 [email protected] で連絡できます。
プロジェクトにはメーリングリストもあります。参加するには、 [email protected] にメールを送信してください。または、先に アーカイブを閲覧したい場合は、次を試してください:
https://groups.google.com/group/afl-users
追伸:プロジェクトに組み込むためのソースコードをそのまま提出したい場合、 AFLのほとんどの著作権はGoogleが所有していることに注意してください。 あなたは自分の貢献に対する著作権を保持しますが、Googleは先に 簡単なCLAへの同意を求めています:
https://cla.developers.google.com/clas
お手数をおかけして申し訳ありません。もちろん、機能リクエストや バグ報告にはCLAは必要ありません。