web-dev-qa-db-ja.com

ヒープオーバーフローを使用して任意のデータを書き込む

私はヒープオーバーフロー攻撃の基本を学ぼうとしています。私は主に、攻撃の基礎としてチャンクメタデータの破損または変更を使用することに関心がありますが、他の提案も受け入れています。このエクスプロイトの目標は、printf()関数ポインターをchallenge()関数ポインターのポインターで上書きすることであることを知っていますが、その書き込みを実現する方法がわからないようです。 。 glibc 2.11.2からmallocを使用している、悪用したい次のコードがあります。

void challenge()
{
        puts("you win\n");
}

int main(int argc, char **argv)
{
        char *inputA, *inputB, *inputC;

        inputA = malloc(32);
        inputB = malloc(32);
        inputC = malloc(32);

        strcpy(inputA, argv[1]);
        strcpy(inputB, argv[2]);
        strcpy(inputC, argv[3]);

        free(inputC);
        free(inputB);
        free(inputA);

        printf("execute challenge to win\n");
}

明らかに、割り当てられたチャンクのメタデータの実際の上書きを実現することは簡単です。ただし、標準的な手法を使用してこのコードを悪用する方法を見つけることができませんでした。私は以下の手法を読み、実装しようとしました。

  • 論文:w00w00 on ヒープオーバーフロー
    • 論文は非常に明確ですが、unlink手法はしばらくの間廃止されています。
  • Malloc Maleficarum.txt
    • このホワイトペーパーでは、w00w00の時代からのエクスプロイト手法を拡張し、新しいバージョンのglibcについて説明します。ただし、このホワイトペーパーで詳しく説明されている5つの手法を考えると、上記のコードがこれらの手法の前提条件のいずれにも一致することはわかりません。
  • ヒープを壊して理解する(pdf)
    • Pdfは、ヒープがどのように機能するかについてかなり良いレビューを提供しますが、ダブルフリーテクニックに焦点を当てています。

私はもともと、inputCのチャンクのサイズ値を操作してこのコードを悪用しようとしたため、inputCチャンクの先頭を指すようになりました。それがうまくいかなかったとき、私はinputBのチャンクをさらに指し示してみました。そのとき、新しいglibcがサイズ値のサニティチェックを実行することに気付きました。

割り当てられたチャンクのメタデータを任意の値に編集し、GOTの値を上書きしたり、他の任意のアドレスに書き込んだりする機能があると仮定して、ユーザーが無料を利用するエクスプロイトを作成するにはどうすればよいですか?

注:「任意のアドレス」を書き込む場合、メモリページは読み取り専用または保護されている可能性があることを理解しています。つまり、書き込み可能と想定できるアドレスを意味します。

22
amccormack

注:これは純粋に学術的な回答であり、悪意のある目的で使用することを意図したものではないことをお答えする前に申し上げます。 OPが行っている演習を認識しています。これらはオープンソースであり、承認されていない状況でこれらの手法を使用するようにユーザーを促すことを目的としたものではありません。

以下でテクニックの詳細を説明しますが、私の概要は短いものになるので、参考のためにVudo mallocトリック(上記のリンクの1つで参照されています)を見てみましょう: http:// www .phrack.com/issues.html?issue = 57&id = 8

これは、mallocがメモリのブロックの作成、リストからのメモリのプルなどをどのように処理するかを詳しく説明しています。特に、リンク解除攻撃はこの攻撃にとって重要です(注:この特定の理由により、glibcがサイズのサニティチェックを実行するようになったのは正しいですが、この演習では古いlibcを使用する必要があります...レガシーブロ)。

論文から、割り当てられたブロックと空きブロックは同じデータ構造を使用しますが、データの処理は異なります。ここを参照してください:

chunk -> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         | prev_size: size of the previous chunk, in bytes (used   |
         | by dlmalloc only if this previous chunk is free)        |
         +---------------------------------------------------------+
         | size: size of the chunk (the number of bytes between    |
         | "chunk" and "nextchunk") and 2 bits status information  |
  mem -> +---------------------------------------------------------+
         | fd: not used by dlmalloc because "chunk" is allocated   |
         | (user data therefore starts here)                       |
         + - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
         | bk: not used by dlmalloc because "chunk" is allocated   |
         | (there may be user data here)                           |
         + - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
         |                                                         |
         |                                                         |
         | user data (may be 0 bytes long)                         |
         |                                                         |
         |                                                         |
 next -> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         | prev_size: not used by dlmalloc because "chunk" is      |
         | allocated (may hold user data, to decrease wastage)     |
         +---------------------------------------------------------+

割り当てられたブロックはfdまたはbkポインターを使用しませんが、空きブロックは使用します。これは後で重要になります。 Doug Leaのmallocの「ブロック」が二重にリンクされたリストに編成されていることを理解するには、十分なプログラミングを知っている必要があります。空きブロック用のリストと割り当てられたブロック用のリストがあります(技術的にはサイズに応じて無料のリストがいくつかありますが、コードが同じサイズのブロックを割り当てるため、ここでは関係ありません)。したがって、特定のブロックを解放するときは、リストをそのまま維持するためにポインターを修正する必要があります。

例えば以下のリストからブロックyを解放するとします。

x <-> y <-> z

上の図では、bkとfdのスポットに、リストに沿って反復するために必要なポインターが含まれていることに注意してください。 mallocが呼び出すリストからブロックpを削除する場合、特に、リストを修正するためのマクロを呼び出します。

#define unlink( y, BK, FD ) {            
    BK = P->bk;                          
    FD = P->fd;                          
    FD->bk = BK;                         
    BK->fd = FD;                         
}

マクロ自体を理解するのは難しいことではありませんが、古いバージョンのlibcで注意すべき重要な点は、サイズや書き込まれるポインターに対してサニティチェックを実行しないことです。あなたの場合の意味は、アドレスのランダム化を一切行わなくても、ヒープのステータスを予測可能かつ確実に判断し、特定の方法でヒープをオーバーフローさせることで(ここではstrncopyを介して)任意のポインタを選択したアドレスにリダイレクトできることです。 。

攻撃を機能させるために必要なことがいくつかあります。

  • ブロックのfdポインターは、上書きするアドレスからマイナス12バイトを指しています。オフセットは、mallocがリストを変更するときにアライメントをクリーンアップすることと関係があります
  • ブロックのbkポインターがシェルコードを指しています
  • サイズは-4である必要があります。これにより、いくつかのことが達成されます。つまり、ブロック内のステータスビットが設定されます。

したがって、特定の例でオフセットを試してみる必要がありますが、ここでstrcpyを使用して渡そうとしている一般的な悪意のある形式は、次の形式です。

|正当なバッファを埋めるためのがらくた| -4 | -4 |上書きするアドレス-12(0x0C)|代わりに呼び出したいアドレス

負の数はprev_sizeフィールドを-4に設定することに注意してください。これにより、フリールーティングはprev_sizeチャンクが実際に制御/破損している現在のチャンクで開始すると信じます。

そして、はい、この攻撃が現在のバージョンのglibcで機能しないことを言及せずに、適切な説明を完了することはできません。サイズにはサニティチェックが行われており、リンク解除方法は機能しません。これをアドレスランダム化などの緩和策と組み合わせると、この攻撃はレガシーシステム以外では実行できなくなります。しかし、ここで説明する方法は、私がその挑戦をした方法です;)

11
Fewmitz

MallocMalleficarumで説明されているテクニックのほとんどが保護されていることに注意してください。 glibcは、2倍の無料シナリオを大幅に改善しました。

Malloc Malleficarumの手法に関する知識を向上させたい場合は、MallocDes-MalleficarumとHouseof Lore:Reloadedを読んでください。これらのテキストはphrackで見つけることができます。

Malloc Des-Malleficarum

私もそれに取り組んでいます、そして、例えば、テキストで説明されているように、少なくとも、HouseofMindはもはや利用可能ではないとあなたに言うことができます。コードに追加された新しい制限をバイパスすることは可能かもしれませんが。コードを実行する最も簡単な方法は、.dtorsアドレスを上書きすることです。したがって、プログラムが終了すると、コードは常に実行されます。

Glibcコードをダウンロードして、mallocなどの評論家ゾーンを調べると、前述のドキュメントに記載されていないコードチェックが見つかります。これらのチェックは、ダブルフリーパーティーを停止するために含まれていました。

一方、youtube(BlackHat 2007)で見つけることができるJustin N. Ferguson(ヒープを壊して理解する)のプレゼンテーションは、すべてのヒープメカニズムを理解するのに最適ですが、示されている手法は次のとおりです。信頼できるとはほど遠いですが、少なくとも、彼はヒープの活用に新しい分野を開きます。

ヒープを壊して理解する

とにかく、私も取り組んでいるので、私に連絡したい場合は、私たちの進歩を共有することができます。あなたはnewlogとしてoverflowedminds.netドメインで私に連絡することができます(自分でメールアドレスを作成してください^^)。

3
newlog