web-dev-qa-db-ja.com

攻撃者が `n`パラメータを` memcpy() `に制御できる場合、なぜ危険なのですか?

私は 論文 を読んでいて、このコードに情報漏えいの脆弱性があることを確認しました。それは次のコードが攻撃者にメモリレイアウト情報を漏らすと言っていました

誰かが私にこれがどのように情報を漏らすか説明してくれませんか?

struct userInfo{
    char username[16];
    void* (*printName)(char*);
} user;
...
user.printName = publicFunction.
...
n = attacker_controllable_value; //20
memcpy(buf, user.username, n);   //get function ptr
SendToServer(buf);

私はmemcpyが例外を与えることがわかりますが、なぜそれが攻撃者(またはそれが返すもの)にメモリアドレスを返す必要があるのですか?

前もって感謝します

13
smttsp

bufのサイズがnによって制御されるか16より大きいと仮定すると、攻撃者はnを任意の数にして、それを使用して任意の量のメモリを読み取ることができます。 memcpyおよびCは、一般に例外をスローしたり、これが発生したりするのを防ぎません。何らかの種類のページ保護に違反したり、無効なアドレスにヒットしたりしない限り、memcpyは要求されたメモリ量をコピーするまで楽しそうに続けます。

私はuserとこの脆弱なコードのブロックがどこかの関数にあると想定しています。これはおそらくそれがスタック上にあることを意味します。すべてのローカル関数変数、戻りアドレス、およびその他の情報はスタックに含まれています。以下の図は、Intel Assemblyを使用するシステムの構造を示しています(ほとんどのプラットフォームで使用されており、コンピューターで使用されていると思います)。

Stack frame

Nを十分大きくしてmemcpyをスタックフレーム内で前進させると、このメソッドを使用して戻りアドレスを取得できます。 userは、この図の「ローカルに宣言された変数」というセクションにあります。 EBPは4バイトの値であるため、それを超えて読み取り、memcpyで次の4バイトをコピーすると、戻りアドレスがコピーされます。

上記はプログラムが実行されているアーキテクチャに依存することに注意してください。このペーパーはiOSに関するものであり、ARMについては何も知らないため、この情報の詳細は多少不正確な場合があります。

25
haze

良い答えはすでにsashaによって与えられています ですが、これを別の角度から見たいと思います。具体的には、memcpyが実際に実行するものdoes(実行されるコードに関して)。

この素朴な実装でのマイナーなバグの可能性を考慮して、C89/C99/POSIX関数の署名とコントラクトを満たすmemcpy()の簡単な実装は、完全に異なるものではないかもしれません。

/* copy n bytes starting at source+0, to target+0 through target+(n-1), all inclusive */
void memcpy (void* target, void* source, size_t n)
{
    for (size_t i = 0; i < n; i++)
    {
        *target++ = *source++;
        /* or possibly the here equivalent: target[i] = source[i]; */
    }
}

現在realの実装では、今日のワイドメモリ(RAM)相互接続バスを利用するために、一度に1バイトよりも大きなチャンクでコピーを実行しますが、原理はまったく同じです。

あなたの質問の目的のために注意すべき重要な部分は、境界チェックがないことですこれは設計によるものです]これがそうである理由には、3つの重要な理由があります。

  1. Cは、オペレーティングシステムのプログラミング言語としてよく使用され、「ポータブルアセンブラ」として設計されました。したがって、多くの古いライブラリ関数(memcpy()が1つです)と一般的な言語に対する一般的なアプローチは、アセンブラーで実行できる場合、Cでも実行できるはずです。アセンブラーではできるがCではできないこと.
  2. メモリの場所へのポインタが与えられた場合、その場所に適切に割り当てられているメモリの量を知る方法はありません。また、ポインタが指すメモリが割り当てられている場合でも、それを知る方法はありません。 (初期のx86システムとDOSの昔、ソフトウェアを高速化するための一般的なトリックは、グラフィックスメモリに直接書き込んでテキストを画面に表示することでした。グラフィックスメモリは、プログラム自体によって割り当てられることはありませんでした。特定のメモリアドレスでアクセス可能であることがわかっています。実際にそれを確認する唯一の方法worksは、メモリの読み取りまたは書き込みを行い、何が起こるかを確認することです。動作、つまり基本的に、C言語標準ではanythingが許可されています)。
  3. 基本的に、配列はポインタに退化します。この場合、インデックス付けされていない配列変数は、配列の先頭へのポインタと同じです。これは厳密にすべての場合に当てはまるわけではありませんが、現時点では十分です。

(1)から、必要なメモリをどこからでもどこへでもコピーできるはずです。メモリ保護は他の誰かの問題です。具体的には、最近ではOSと [〜#〜] mmu [〜#〜] の責任です(これらの日は一般にCPUの一部です)。 OS自体の関連部分はおそらくCで書かれています...

(2)からわかるように、memcpy()とそのフレンドは、コピーするデータの量を正確に通知する必要があり、ターゲット(またはターゲットポインターが指すアドレスにある他のバッファー)のバッファーが信頼できるものである必要があります。そのデータを保持するのに十分な大きさ。メモリ割り当てはプログラマの問題です。

(3)から、どれだけの量のデータをコピーしても安全かはわかりません。メモリ割り当て(ソースと宛先の両方)が十分であることを確認することはプログラマの問題です。

攻撃者がmemcpy()を使用してコピーするバイト数を制御できる場合、(2)と(3)が分類されます。ターゲットバッファが小さすぎる場合、後続のバッファは上書きされます。運がよければ、メモリアクセス違反が発生しますが、C言語またはその標準ライブラリは、その発生を保証しません。 (メモリの内容をコピーするように要求しましたが、それを実行するか、試行して終了しますが、何がコピーされるかintendedがわかりません。)より小さいソース配列を渡す場合memcpy()にコピーするように要求するバイト数よりも、memcpy()がそうであることを検出する確実な方法はありません。ソース配列の末尾を超えて、ソースの場所とターゲットの場所への書き込みは機能します。

攻撃者がサンプルコードでnを制御できるようにすることで、nがコピーのソース側の配列の最大サイズよりも大きくなるため、上記の点が原因でmemcpy()は長さを超えて喜んでコピーを続けます目的のソース配列の。 これは基本的に ハートブリード 一言で言えば攻撃です。

これが、コードがデータをリークする理由です。正確にどのデータがリークされるかは、nの値とコンパイラーの配置方法の両方に依存します機械語コードとメモリ内のデータを出力します。 sashaの回答の図は概要を示しており、すべてのアーキテクチャは似ていますが異なります。

変数bufがどのように宣言され、割り当てられ、メモリに配置されるかに応じて、またstack smashing attack プログラムの適切な動作に必要なデータが上書きされ、そこにあるものを上書きしたデータが後で参照されます。ありふれたケースでは、これはクラッシュまたはデバッグ不可能のバグにつながります。深刻な標的型のケースでは、完全に攻撃者の制御下で任意のコードが実行される可能性があります。

15
a CVn

私は別の答えを投稿しています。なぜなら、ここでの2つの答えはどちらも正しいですが、私の意見の質問の重要なポイントを逃しているためです。問題は、メモリレイアウトに関する情報漏えいについてです。

提示されたmemcpyは常に正しいサイズの出力バッファーを持っている可能性があるため、攻撃者がサイズを制御しても、この時点でスタックが破壊されるリスクはない可能性があります。情報漏えい(Linuxiosで既に言及されているように、ハートブリードのように)は、どの情報が漏えいするかに応じて、潜在的な問題です。この例では、publicFunctionのアドレスをリークしています。これはアドレス空間レイアウトのランダム化を無効にするため、これは実際の問題です。 ASLRは、たとえば ASLRとDEPはどのように機能しますか? のトピックです。 publicFunctionのアドレスを公開するとすぐに、同じモジュール(DLLまたはEXEファイル)内の他のすべての関数のアドレスが公開され、return-to-libcまたはreturn-oriented-programmingで使用できます攻撃。ただし、これらの攻撃には、ここに示したものとは別の穴が必要です。

5
Michael Karcher