web-dev-qa-db-ja.com

va_randomize_spaceとスタックプロテクターをバイパスする

GCCでコンパイルされたプログラムです-fstack-protectorオプションを使用し、Linux環境でva_randomize_spaceカーネル変数を1に設定して、バッファオーバーフロー攻撃から完全に保護しますか?

そうでない場合、バッファオーバーフロー攻撃を生成する一般的な手法は何ですか?

5
Davide Berra

攻撃はstackオーバーフローではありませんが、bufferオーバーフローです(バッファーはスタック上にある可能性があります)。スタックは、RAMアプリケーションがローカル変数を格納し、関数の呼び出しと戻りを編成するために使用する領域です。スタックオーバーフローは、アプリケーションコードが正常に終了したときの領域です。再帰的すぎるため、スタックスペースが不足します。カーネルはスタックスペースの両端でマップされていないページを保持するため、カーネルによってSIGSEGVに変換されたスタックオーバーフローとスタックアンダーフローのトリガートラップは、問題の無慈悲な終了を意味しますこれはバグですが、セキュリティの脆弱性ではない場合がよくあります。

バッファオーバーフローは、アプリケーションコードがバッファ(RAM内の特定の領域)への書き込みに誘導され、そのバッファに収まるよりも多くのバイト数である場合、したがって、RAMの直後、またはバッファの直前にあったものに「他の場所」のバイトの一部を書き込みます。バッファがスタック上にある場合、バッファに沿っているのは他のローカル変数です。および戻りアドレス。関数に入ると戻りアドレスがスタックスロットに書き込まれます。これは、関数が戻ったときに実行を継続する必要があるアドレスです(つまり、 call opcodeの直後に続く呼び出し元のコードの命令)戻りアドレスを(バッファオーバーフローで)上書きすることにより、攻撃者はコードを別の場所にジャンプさせようとします。

クラシックバッファオーバーフローの時間では、攻撃者は簡単なパスを使用しました。攻撃者が選択したデータによるバッファのオーバーフロー。データ自体には、攻撃者が実行したいコード(たとえば、シェルを起動するコード)が含まれています。オーバーフローは、バッファー内のそのデータを正確に指すように、戻りアドレスを上書きするために使用されます。関数が戻ると、変更された戻りアドレスが続き、攻撃者のコードにジャンプします。

最初の保護手段は、スタック、およびおそらくRAMの残りのほとんどをnon-executableとしてマークすることです。これは データ実行防止 と呼ばれます。これは、CPUがデータバイト(攻撃者から提供されたもの)を実行可能なコードとして解釈しないようにするためです。ハードウェアはこれを区別できます(古い32ビットx86 CPUでは、完全に簡単にすることはできませんでしたが、それでも可能でした)。

反応として、攻撃者は独自のコードチャンクを挿入する代わりに、すでにRAMにあるコードを使用し始めました。標準ライブラリのいくつかの関数にジャンプする(標準ライブラリには多くの関数があり、そのうちのいくつかは攻撃者にとって非常に便利です)。標準ライブラリには、定義上、コードが含まれているため、「実行可能」とマークされ、DEPはそれに対して何も実行できません。

反応として、防御側は Address Space Layout Randomization を考案しました:これがva_randomize_spaceがアクティブになります。これにより、RAMに動的にロードされたライブラリがシャッフルされるため、攻撃者はRAM標準ライブラリの場所を予測できません。ターゲットコードの場所を予測できない場合、攻撃者はそれにジャンプする時間。

反応として、攻撃者はメインの実行可能ファイル自体、または動的リンカーを標的にし始めました。どちらもアドレス空間の固定位置にあります。たまたま、ほとんどのコードチャンクが攻撃者によって悪意のあるスキームを実行するために使用される可能性があります( " Return-Oriented Programming "はそのために作成されました)。その攻撃者と防御者のダンスの次のステップを待っています。

Canaries 変更された戻りアドレスの使用を防止することにより、バッファオーバーフローの従来の悪用を打ち負かそうとします。それがstack-protector GCCのオプションが実行します(他のいくつかのことを実行しますが、それが主な仕事です)特別なランダム化された値(「カナリア」)は、戻りアドレススロットの直前のスタックに書き込まれます。関数が戻るとき、最初に特別な値がまだあることを確認します。おそらく、オーバーフローが戻りアドレスにゆっくり到達した場合は、カナリアを上書きして変更していたでしょう。コードはそれを認識し、アドレススペースを狂ってジャンプするのではなく、アプリケーションを強制終了します。

カナリアは良いものになりますonly唯一の攻撃者のターゲットが現在の関数の戻りアドレスである場合。また、オーバーフローは nderflow ではなく、連続したバイトのシーケンスで構成され、攻撃者が「幸運にならない」と想定しています。


これらすべてのシステムのコアアイデアは次のとおりです。

  • それらはオーバーフローを防止しないです。彼らは、そのようなオーバーフローの結果を問題の少ないものにしようとするだけです。カナリア諸島は、オーバーフローを早期に発見しようとします。 ASLRは、攻撃者のコントロールジャンプを回避するためのスクランブルの詳細です。
  • 攻撃パスに集中します。 DEP、ASLR、カナリア...は一般的な保護システムではなく、実際に見られる特定のエクスプロイトへの対策です。攻撃者を倒す代わりに、彼らは多かれ少なかれ攻撃者をより創造的に訓練します。
  • 攻撃者がCPUを別のコードの場所にジャンプさせようとするとき、それらはコードパス変更のみを扱います。 データ変更については何もしません。スタックのオーバーフローにより、ローカル変数を変更することもできます。アプリケーションコードによっては、プライベートファイルの内容が上記のファイルではなく、別のファイルまたはソケットまたはログに書き込まれるように、ファイル記述子を変更するなど、他のことを行う場合があります。
  • カナリアは、バッファのoverflownderflowではなく)バッファスタック上を悪用することについてのみです。しかし、RAM(--ヒープなど)の他の部分にもバッファがあります。

バッファオーバーフローに対する本当の保護はデータのオーバーフローを許可しないことです。 ASLR、カナリア...は特定の結果に対処しますが、それはモップを使用して洪水に対抗するようなものです。バッファオーバーフローを禁止するには、2つの方法があります。

  1. 非常に優れたプログラマーになり、バグを作らないでください。
  2. すべての配列アクセスに対して明示的な境界チェックを実施するプログラミング言語を使用してください。 C#、Java、Javascript、OCaml、さらにはVisual Basic ...選択肢は大きいです。実際、CおよびC++の非チェック動作は、これらの言語の欠陥です。それは責任を負うことではありません(バウンドチェックの欠如は歴史的にかなり理解可能です; Cは1 MHz範囲未満のマシン用に設計されました)むしろ、ある時点で、フリントストーンの使用をやめ、切り替えることは価値があることを指摘します金属工具に。
10
Thomas Pornin