House of Orange

HackTricksのサポート

基本情報

コード

ゴール

  • malloc_printerr 関数を悪用する

必要条件

  • トップチャンクのサイズを上書きする

  • Libcとヒープのリーク

背景

この例のコメントから必要な背景情報があります:

古いバージョンのlibcでは、malloc_printerr 関数が呼び出されると、_IO_list_all に格納されている _IO_FILE 構造体のリストをイテレートし、その構造体内の命令ポインタを実際に実行していました。 この攻撃では、_IO_list_all に書き込む偽の _IO_FILE 構造体を作成し、malloc_printerr を実行させます。 その後、_IO_FILE 構造体のジャンプテーブルに格納されているアドレスを実行し、コード実行を行います。

攻撃

攻撃は、アンソートされたビン内のトップチャンクを取得することから始まります。これは、malloc を呼び出して、現在のトップチャンクのサイズよりも大きく、mmp_.mmap_threshold(デフォルトは128K)より小さいサイズで呼び出すことで達成されます。トップチャンクのサイズが変更されるときは、トップチャンク + サイズがページアラインされており、かつトップチャンクの prev_inuse ビットが常に設定されていることが重要です。

アンソートされたビン内にトップチャンクを取得するために、トップチャンクを作成するためにチャンクを割り当て、トップチャンクのサイズを変更します(割り当てられたチャンク内でオーバーフローが発生する)。その後、新しいトップチャンクのサイズよりも大きなチャンクを割り当てます。トップチャンクをアンソートされたビンに入れるために free は呼び出されません。

古いトップチャンクは今やアンソートされたビンにあります。それを読み取ることができる場合(オーバーフローを引き起こす脆弱性による可能性があります)、そこからlibcのアドレスをリークし、_IO_list_all のアドレスを取得できます。

アンソートされたビン攻撃は、オーバーフローを悪用して topChunk->bk->fwd = _IO_list_all - 0x10 と書き込むことで実行されます。新しいチャンクが割り当てられると、古いトップチャンクは分割され、アンソートされたビンへのポインタが _IO_list_all に書き込まれます。

次のステップは、古いトップチャンクのサイズを小さなビンに収まるように縮小することです。具体的には、サイズを 0x61 に設定します。これには2つの目的があります:

  1. Small Bin 4への挿入malloc がアンソートされたビンをスキャンしてこのチャンクを見つけると、サイズが小さいためにそれをSmall Bin 4に挿入しようとします。これにより、チャンクはSmall Bin 4リストの先頭に配置され、これは _IO_list_all のチャンクのFDポインタの場所です。アンソートされたビン攻撃を通じて _IO_list_all に近いアドレスを書き込んだためです。

  2. Mallocチェックのトリガー:このチャンクサイズの操作により、malloc が内部チェックを実行します。偽のフォワードチャンクのサイズがゼロであるため、エラーが発生し、malloc_printerr が呼び出されます。

Small Binの操作により、チャンクのフォワードポインタを制御できます。 _IO_list_all との重複を使用して、偽の _IO_FILE 構造体を作成します。この構造体は、libc内の内部チェックをパスする値に設定された _IO_write_base_IO_write_ptr などの重要なフィールドを含むように注意深く作成されています。さらに、偽の構造体内にジャンプテーブルが作成され、命令ポインタが任意のコード(たとえば system 関数)が実行されるアドレスに設定されます。

技術の残りの部分を要約すると:

  • 古いトップチャンクを縮小する:古いトップチャンクのサイズを 0x61 に調整して小さなビンに収めます。

  • 偽の _IO_FILE 構造体を設定する:古いトップチャンクと重なるように偽の _IO_FILE 構造体を設定し、適切にフィールドを設定して実行フローを乗っ取ります。

次のステップは、アンソートされたビンに現在ある古いトップチャンクと重なる偽の _IO_FILE 構造体を作成することです。この構造体の最初のバイトは、実行されるコマンド(たとえば "/bin/sh")へのポインタを慎重に作成されています。

偽の _IO_FILE 構造体内の重要なフィールド、例えば _IO_write_base_IO_write_ptr などは、libc内の内部チェックをパスする値に設定されています。さらに、偽の構造体内にジャンプテーブルが作成され、命令ポインタが任意のコードが実行されるアドレスに設定されます。通常、これは system 関数のアドレスやシェルコマンドを実行できる他の関数のアドレスになります。

攻撃は、malloc の呼び出しが偽の _IO_FILE 構造体を介してコードの実行をトリガーするときに頂点に達します。これにより、任意のコードが実行され、通常はシェルが生成されるか、他の悪意のあるペイロードが実行されます。

攻撃の要約:

  1. トップチャンクを設定する:チャンクを割り当ててトップチャンクのサイズを変更します。

  2. トップチャンクをアンソートされたビンに強制する:より大きなチャンクを割り当てます。

  3. Libcアドレスをリークする:アンソートされたビンから読み取るために脆弱性を使用します。

  4. アンソートされたビン攻撃を実行する:オーバーフローを使用して _IO_list_all に書き込みます。

  5. 古いトップチャンクを縮小する:サイズを小さなビンに収めるように調整します。

  6. 偽の _IO_FILE 構造体を設定する:制御フローを乗っ取るために偽のファイル構造体を作成します。

  7. コード実行をトリガーする:攻撃を実行して任意のコードを実行します。

この手法は、free を直接呼び出すことなく、ヒープ管理メカニズム、libc情報のリーク、およびヒープオーバーフローを悪用してコード実行を達成します。偽の _IO_FILE 構造体を注意深く作成し、適切な位置に配置することで、通常のメモリ割り当て操作中に制御フローを乗っ取ることができます。これにより、任意のコードの実行が可能になり、通常はシェルや他の悪意のある活動が実行されます。

参考

HackTricksのサポート

Last updated