web-dev-qa-db-ja.com

バッファオーバーフローを素人に説明する方法

ときどき(大声で考えて、人々が私を耳にしたとき)、バッファオーバーフローとは何かを説明せざるを得ません。私は本当に良いメタファーを考えることができないので、(脆弱な)プログラムの動作とメモリ割り当てを説明するのに約10分かかり、実際のエクスプロイトについては約2文あります(「バッファオーバーフローによってバッファがいっぱいになるナンセンスで、私が指すようにしたいものを指すようにポインターを上書きします」)。この時までに、ほとんどの人が自殺になっています...バッファオーバーフローを素人に説明する良い方法は何ですか?可能であれば、「オーバーフロー」コンポーネントを含めてください。また、これが攻撃者が望むものを取得できることを意味する理由の少なくとも導入も含めてください。平均的な(そして平均以下の)インテリジェンスの人々は、私が話していることについてのアイデアを得ることができるはずですので、比喩(アナロジー?)の各部分が何を表しているかを説明するために自由に(実際に励まされて)ください。 、超技術的な説明に依存しないでください...

PS、バッファオーバーフローの機能を技術用語で説明する関連質問: バッファオーバーフローとは

52
KnightOfNi

あなたがお金を借りている人々のリストを持っていると想像してください。

Name | Amount owing

また、修正液が組み込まれた奇妙なペンがあるので、特定の場所に何かを書き込んでから、別の場所に何かを書くと、最初に書き込んだ内容が消去されます。これがコンピュータのメモリの仕組みであり、通常の書き込みの仕組みとは少し異なります。

あなたは誰かに$ 5000の車に$ 500の預金を支払うので、あなたは今彼らに$ 4500を借りています。彼らはあなたの名前はジョン・スミスだと言います。金額(4500)と名前(John Smith)をテーブルに書き込みます。テーブルは次のようになります。

John Smith | 4500

後であなたのテーブルはあなたにそれらを返済することを思い出させます。 $ 4500(プラス利息)を支払い、テーブルから消去すると、テーブルは再び空白になります。

次に、誰かから$ 1000のローンを受け取ります。彼らはあなたの名前が「ジョン・スミスxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx9999999999」であることを教えてくれます。金額(1000)と名前(John Smithxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx9999999999)をテーブルに書き込みます。テーブルは次のようになります。

John Smithxxxxxxxxxxxxxxxxxxxxxxx|x99999999990

(1000の最後の0は上書きされませんでした。これは重要ではありません。)

名前を書くとき、「名前」列の最後に達しても止まらず、「未払い額」列に書き続けました!これはバッファオーバーフローです。

後で、テーブルから、John Smithxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxに$ 99999999990を支払う必要があることが通知されます。あなたは彼を再び見つけ、ほぼ1000億ドルを彼に支払います。

110
user253751

あなたが与えられたよりも多くのスペースを使い果たすというアイデア、したがって別のフィールドに波及することは、視覚化するのに十分簡単です。しかし、これがどのようにして悪者が自分のコードを実行することにつながるのかは、おそらくはっきりしていません。

これを十分に理解すれば、これは簡単に説明できます。重要な背景に出会ったことを確認してください。この順序で多かれ少なかれ:

  • 「スタック」は、一時的な情報を格納できる場所です。 「スタックポインタ」は、スタックの終わりがどこにあるかを決定します。関数が実行されると、スタックポインターが移動して、処理するためのメモリが割り当てられます。関数が完了すると、ポインターが見つかった場所に戻ります。

  • スタックは逆方向に大きくなります。したがって、スタック上に100バイトを割り当てるには、スタックポインターを(追加するのではなく)スタックポインターから100subtractします。前の関数のスタックが1000から始まり、100バイトが必要な場合、スタックは900から始まります。

  • つまり、自分が与えたよりも多くのスペースを使用すると、空のスペースに書き続けるだけではなく、実際にoverwriteを開始します。スタック値。

  • 私の関数が開始すると、前の関数によってスタックに残された一番上の値は、戻りアドレスで、関数が完了したときに移動する必要があります。

  • これは、私の関数がスタックをオーバーランした場合、上書きする最初にが戻りアドレスであることを意味します。攻撃者がスタックに何を入れるかについて注意を払っている場合、攻撃者は必要な戻りアドレスを指定できます。

  • 私の関数が存在する場合、その戻りアドレスにあるコードは、次に実行されるコードです。

簡単な例

このテクニックが最初に説明された 楽しみと利益のためのスタックのスマッシング では、最もシンプルで簡単なテクニックが導入されました。関数があなたの名前を読んでから戻ると想像してください。したがって、スタックは次のようになります。

Stack Pointer                                      Prev. Stack Ptr
+----------------------------------+--------------+................
| Your Name Here                   | Return Addr  |  Old stack ...
+----------------------------------+--------------+................

しかし、悪者は彼の名前をスペースからあふれるほど長くします。それだけでなく、実際の名前を入力する代わりに、いくつかの邪悪なコード、いくつかのパディング、その邪悪なコードのアドレスを入力します。

+----------------------------------+--------------+................
| [ Evil Code ]xxxxxxxxxxxxxxxxxxxxxxEvil Address |  Old stack ...
+----------------------------------+--------------+................
  ▲──────────────────────────────────┘

ここで、前の呼び出し元に戻る代わりに、[Evil Code]に直接ジャンプします。これで、プログラムの代わりに彼のコードを実行しています。そこからはほとんどゲームオーバーです。

軽減とその他のテクニック

スタックスマッシングの効果を減らすために使用される2つの手法は、DEPとASLRです。

DEP(「データ実行防止」)は、スタックを実行不可能としてマークすることで機能します。これは、スタックでのコードの実行が許可されなくなったため、スタックの[Evil Code]が実行されないことを意味します。これを回避するために、攻撃者は自分がやりたいことを少しずつ実行する既存のコードの塊を見つけます。そして、自分の戻りアドレスを単に上書きするのではなく、順番に実行したいすべての関数について、スタック全体に戻りアドレスのチェーンを作成します。彼らはこれを「リターン指向プログラミング」またはROPと呼んでいます。リターンのチェーンは「ROPチェーン」と呼ばれます。これは本当に難しいことです。しかし、役立つツールがあります。

ASLR(「アドレススペースレイアウトのランダム化」)は、すべての興味深い関数の位置をランダム化することによって機能します。現在、ROPチェーンの作成はそれほど簡単ではありません。プログラムが実行されるたびに、すべてのアドレスが異なる場所にあります。そのため、攻撃者がリターンアドレスを自分のEvil Addressで上書きしようとすると、コードは常に異なる場所にあるため、使用する番号がわかりません。

DEPもASLRもそれ自体は多くの保護を提供しませんが、両方を組み合わせて悪用を成功させる非常に困難にします。回避策がいくつか存在することもありますが、どこでも機能する回避策はありません。 DEP + ASLRを回避できる場合は、1回限りの成功です。

16
tylerl

他の答えはまだかなり技術的なので、私はこれを提供しています。

幼稚園のクラスがあるとします。各生徒が靴を入れるカビーホールがあります。各カビーホールには靴が1つずつあります。したがって、生徒ごとに2つのカビーホールを用意します。

各生徒には、隣接する2つのカビーホールが割り当てられます。次に、教師は生徒に無作為に電話をして、割り当てられたカビーの穴に靴を入れます。

先生がBad Billyを呼び出すと、Bad BillyはStupid Sallyビリーズカビーの穴は数字5および6およびSally'sは数値7および8Billyは彼のショーを5および6そして、彼の定義された制限をオーバーフローし、ぬるぬるしたヒキガエルをSally'scubby number 7

教師は隣接する順番でカビーホールを使用するために定義された制限に保護を適用していないため、Billyは彼の制限をオーバーフローし、Sally'sストレージ。これで、サリーが靴を取りに行くと、代わりにぬるぬるしたヒキガエルyuckを受け取ります!


+-------------------+--------------------+-------------------+--------------------+
|      CUBBY 5      |       CUBBY 6      |      CUBBY 7      |       CUBBY 8      |
+-------------------+--------------------+-------------------+--------------------+
|                   |                    |                   |                    |
| Billy's Left Shoe | Billy's Right Shoe | Sally's Left Shoe | Sally's Right Shoe |
+-------------------+--------------------+-------------------+--------------------+

Billy2つだけを入力する必要があると定義されている3つの項目を入力します。これは、高レベルでスタックオーバーフローが機能する方法です。誰かがストレージをいじっています。それらが許可されておらず、そのストレージが読み取られたとき、それは期待したものではありません。

+-------------------+--------------------+------------+--------------------+
|      CUBBY 5      |       CUBBY 6      |   CUBBY 7  |       CUBBY 8      |
+-------------------+--------------------+------------+--------------------+
|                   |                    |            |                    |
| Billy's Left Shoe | Billy's Right Shoe | Slimy Toad | Sally's Right Shoe |
+-------------------+--------------------+------------+--------------------+

教師がもっと注意を払い、各生徒が予想される量のストレージのみを使用するようにした場合、バッファオーバーフローは防止できたはずです。

3
Eric G

類推を使わずにこれを試します。

コンピュータは基本的にすべてのメモリであり、それは重要な部分です。メモリの内容は、コンピュータに何をすべきかを指示する命令と、命令が使用し、使用または変更できるデータです。多くの場合、可変長のデータを格納する必要があります。たとえば、プログラムが、非常に短い([email protected])または非常に長い([email protected])のメールアドレスを追跡する必要がある場合です。一部のプログラムは、データレコードの最大長を適切に追跡しません。たとえば、プログラムが最大100文字のメールアドレスで設計されていて、誰かが100文字を超えるメールアドレスをプログラムに与えた場合、プログラムは、アドレスの残りの部分をメモリの最後まで書き込み続けます。 -割り当てられたスペース。覚えておくべき重要な部分は、メモリがすべてであり、プログラム自体がデータレコードと並んでメモリにあるということです。

このプログラムがどのように機能するかを正確に知っている人は、非常に注意深く作成された非常に長く、末尾に特殊文字が含まれる電子メールアドレスを与えることができます。プログラムがメールアドレスをメモリに保存すると、プログラムが他の部分があると思ったメモリの一部にそれらの特殊文字を盲目的に書き込み、それからそれらの部分を実行すると、代わりに何でも実行するという考えですコンピューターコードで翻訳された特殊文字をプログラムします。このようにして、プログラムに与えたデータを注意深く作成するだけで、誰かがコンピュータに必要なものを実行させることが可能になります。

3
Wedge

私はいつもそれをバケツを破裂させるように説明しています。バケットは外部からコンテンツを保護するために存在しますが、コンテンツを使用してバケットの外部に到達するため、他の方法ではアクセスできないはずのシステムの領域にアクセスします。

1
David

良い質問。これは、最も技術的に正確ではない類推ですが、アイデアは理解できるはずです。

バインダー(メモリ)と3つの穴の開いたクック(プロセッサー、つまりCPU)で3穴パンチ紙にレシピ本を描いてください。

  • バインダーからページを追加または削除できます(メモリ内のプログラムとデータをロードまたはアンロード)
  • コックは彼らがいるページのすべての指示に従います
  • クックは最初(ブートローダー)から始まり、指示が「本を閉じる」まで続きます
    • 別のページに移動するように指示されている場合でも(394ページに移動)

したがって、通常は、1ページ目に「200ページ(ワッフル)に向ける」と書いて、バインダーを開き、200ページでワッフルを入れます。次に、クックを開始します-クックはワッフルを作る必要があります!

しかし、待ってください...攻撃者がいます!彼らはあなたのワッフルレシピのマージン(バッファーの外)にメモを書きました-そして、コックはそれらが明らかに手書きであるにもかかわらず、それらの指示を実行します。

クックは、元のシートに印刷された内容(通常のバッファースペース)だけを実行するように指示されたことはありません。クックはその後(バッファーの後のメモリ内で)何かを実行します。

おそらく、コックがワッフルに酢を追加します(ファイルを破損します)。おそらくコックはページ394に変わり、生の卵をそのままにしておき、腐敗してカビが生えるまで使用しません(アンチウイルスをオフにします)。おそらく、コックがキッチンのすべてのものを捨てる(すべてのファイルを削除する)か、キッチンのドアをロックしてあなたを締め出す(ランサムウェア)か、ウィンドウを開く(トロイの木馬/バックドアをインストールする)ことで、攻撃者は窓。

1

これどう?

コンピュータのデータは、音楽カセットのトラックのように、数字の長いリストとして保存されます。最初から最後まで再生される音楽とは異なり、コンピューターは1つのトラックから別のトラックにジャンプする必要があるため、各トラックの開始位置を伝える「トラックリスト」が必要です。

各曲の長さがわかっているため、トラックリストは音楽にとっては簡単です。コンピューターを使用する場合、たとえばインターネットからデータを取得する場合など、保存する必要があるデータの量はまだわからない場合があります。使用しているトラックがいっぱいになった場合は、未使用の別のトラックに切り替える必要があります。そうしないと、たとえば、一定量以上のデータが提供されることはないと誤って想定した場合、テープを使いすぎて次のトラックを「テープオーバー」する可能性があります。プログラムが次のトラックを読み取ろうとすると、以前にあったものではなく、データの一部が返されます。

上書きされたデータが実行する一連の命令であった可能性があるため、これは危険な場合があります。その場合、コンピュータはインターネットから直接ダウンロードされた命令を実行します!

0
Warbo