ソースコードのあるプログラムのファズテストを行っています。ファズテストをより効果的にするために、特定のコンパイラオプションを使用してプログラムをコンパイルする必要がありますか?もしそうなら、ファズテストを可能な限り効果的にするために、コンパイラーに渡すコマンドラインフラグの正しいリストは何ですか?
明示的にスタックCookieを有効にする必要がありますか(gcc -fstack-protector)?スタックに割り当てられたバッファーの長さチェック(gcc -D_FORTIFY_SOURCE = 2)? malloc/freeチェック(env MALLOC_CHECK_ = 2)? Glibのデバッグアロケーター(G_SLICE = debug-blocks)?
Mudflap を使用することをお勧めしますか(例:gcc -fmudflap -fmudflapir + MUDFLAP_OPTIONS = '-mode-check -viol-abort -check-initializations -ignore-reads')?
Linux上のgccの回答に特に興味がありますが、他のプラットフォームについてもお気軽に回答してください。
アプリケーションがテストからクラッシュする場合、コンパイラー・オプションはそれを保存しません。 gcc -D_FORTIFY_SOURCE=2 -O2
を使用してアプリケーションをコンパイルすると、通常はプロセスをクラッシュさせない小さなメモリ違反により、プロセスが頻繁に強制終了されます。この良い例は、隣接するヒープオーバーフローを検出する能力が向上することです。
GCC Mudflap は、ダングリングポインター、ダブルフリー、バッファオーバーフロー、およびその他のメモリ破損の可能性のある脆弱性を探すためのより高度なデバッグツールです。このGCCコンパイラオプションは、アプリケーションを非常に遅くするため、本番用ではありません。ただし、アプリケーションのクラッシュを引き起こさない違反であっても、すべてのメモリ違反を記録します。詳細な情報を提供して、どのタイプのメモリ違反を扱っているかを絞り込むのに役立ちます。
ただし、ニワトリまたは卵です。これらの欠陥の1つを見つけたら、このセキュリティシステムを無効にする必要があります。これは簡単な作業ではありません(またはこのセキュリティ対策を使用していないユーザー)。単純な「楽しさと利益のためにスタックを破壊する」スタイルの攻撃を見つけることはできません。最新の手法には、 メモリ破損の脆弱性の連鎖 と、 ROPチェーン を使用してASLRを無効にすることが含まれます。
誰も決定的な答えを提案しなかったので、私は小さな実験を行いました。この実験に基づいて、これまでの私の推奨は次のとおりです。
推奨。ファジングするときは、環境変数LIBC_FATAL_STDERR_=1 MALLOC_CHECK_=3
を設定することを検討してください。この設定は、私の実験では測定可能なパフォーマンスへの影響はありませんでした。私の結果に基づいて、この設定は、検出するバグの数をわずかに増やす可能性があります。
他の設定では、私の実験で検出可能な違いはありませんでした。
オプション。必要に応じて、-fstack-protector
または-fstack-protector-all
、-O2 -D_FORTIFY_SOURCE=2
、および/またはmudflapを使用してコンパイルできます。また、環境変数G_SLICE=debug-blocks
を使用して実行できます。私の実験では、どれも測定可能なパフォーマンスへの影響はありませんでした。ただし、見つかった一連のバグに影響を与えるものはありませんでした。したがって、私の実験には費用はかかりませんでしたが、利益もありませんでした。
実験方法と詳細。各実行で、1つのシードファイルを使用して、5000回の繰り返しでffmpeg
をzzuf
でファジングしました。コンパイラフラグ/環境変数の設定ごとに1回実行されました。ファジングが実行ごとにまったく同じバリアントファイルのセットを生成するようにしたので、唯一の違いはコンパイラフラグ/環境変数でした。パフォーマンスへの影響を測定するために、ファジングが完了するまでのCPU +システム時間を測定しました。バグを検出する能力への影響を測定するために、検出可能なクラッシュをトリガーしたバリアントファイルを記録しました。
パフォーマンスを測定しましたが、パフォーマンスに検出可能な影響を与えるオプションはありませんでした(違いはすべてのケースで1%未満であり、おそらくランダムノイズが原因でした)。
バグ検出能力に関しては、私はMALLOC_CHECK_=3
がわずかに有利でしたが、他のフラグや設定はどれもバグ検出能力に違いをもたらしませんでした:
MALLOC_CHECK_=3
は、どのバリアントファイルがクラッシュを引き起こしたかに影響を与えました。フラグがないと、5000回の反復のうち22回でクラッシュが発生しました。さらに2回反復すると警告メッセージ(*** glibc detected ***
...)が発生しました。これを探すことを知っていれば、バグの検出に使用できるため、そのメッセージのファジングログをgrepできるほど賢い場合は、 5000回の反復のうち24回はバグの兆候を示しますが、特定の警告メッセージのログをgrepすることがわからない場合は、5000回の反復のうち22回だけがバグを示しています。対照的に、MALLOC_CHECK_=3
を有効にした場合、5000回の反復のうち25回がクラッシュを引き起こし、ログをgrepする必要がありませんでした。したがって、MALLOC_CHECK_=3
はどちらも、バグの兆候を明らかにするのに少し効果的であり、ファジングログを特別に後処理する必要性を減らします。
興味深いことに、設定なしでプログラムをクラッシュさせたが、MALLOC_CHECK_=3
でプログラムをクラッシュさせなかったバリアントファイルが1つありました。@ this.joshの仮説を確認すると、一部のケースで追加のチェックによっていくつかのバグを見逃す可能性がありますが、同時に、設定なしでプログラムをクラッシュさせなかった2つのバリアントファイルがありましたが、MALLOC_CHECK_=3
でプログラムをクラッシュさせました。したがって、MALLOC_CHECK_=3
のメリットはコストを上回っています。
MALLOC_CHECK_
を除いて、他の設定は検出可能なクラッシュをトリガーしたバリアントファイルに影響を与えませんでした。ベースラインプログラム(特別なフラグなし)をクラッシュさせるバリアントファイルのセットは、特別なフラグを使用してコンパイルしたときにプログラムをクラッシュさせるバリアントファイルのセットとまったく同じでした。したがって、少なくともこの実験では、これらの他の設定は(パフォーマンスの点では)何の費用もかかりませんでしたが、(バグ検出能力の点では)何も得られませんでした。
私の実験は信頼できるものとはほど遠い。これを正しく行うには、実際には、さまざまなプログラム(1つだけでなく)や、複数の異なるシードファイル(1つだけではない)を試してみる必要があります。したがって、この1つの小さな実験から多くの結論を導き出さないように注意してください。しかし、それでも結果は面白いと思いました。
興味深い質問ですね。収集するのはUNIXのみですが、そうでない場合は、最初に両方の環境でテストすることをお勧めします。 Windowsには、ヒープデバッグ、危険なAPI管理などを行うための非常に優れたツールセットがあります。興味がある場合は、Google App Verifierを使用してください。
ただし、一般的には、本番環境で使用する予定のオプティマイザ設定と同じオプティマイザ設定で、少なくともリリースビルドを試す必要があると思います。テストで設定を行いたいnotアプリ検証やmalloc_checkなどの拡張デバッグチェックによって保存されます。結局のところ、攻撃者は最適化されたリリースビルドコードを標的にします。
他のLinuxコンパイラを試してみて、それらの結果に対してファズすることもできます。
それ以上に、私はあなたと同じようにこれに対する答えを聞くことに興味があります。 :-)