ヒープオーバーフロー

Reading time: 11 minutes

tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする

基本情報

ヒープオーバーフローはスタックオーバーフローのようなもので、ヒープ内で発生します。基本的には、ヒープ内にデータを格納するためのスペースが予約されており、格納されたデータが予約されたスペースよりも大きいことを意味します。

スタックオーバーフローでは、命令ポインタやスタックフレームのようなレジスタがスタックから復元されることがわかっており、これを悪用することが可能です。ヒープオーバーフローの場合、デフォルトではヒープチャンクに機密情報が格納されていませんが、機密情報やポインタが含まれる可能性があるため、この脆弱性の重大性は上書きされる可能性のあるデータと、攻撃者がこれをどのように悪用できるかに依存します

tip

オーバーフローオフセットを見つけるためには、スタックオーバーフローと同じパターンを使用できます。

スタックオーバーフローとヒープオーバーフロー

スタックオーバーフローでは、脆弱性がトリガーされる瞬間にスタックに存在するデータの配置がかなり信頼できます。これは、スタックが線形であり、常に衝突するメモリ内で増加し、プログラムの実行中の特定の場所でスタックメモリは通常同様の種類のデータを格納し、各関数によって使用されるスタック部分の末尾にいくつかのポインタがあるためです。

しかし、ヒープオーバーフローの場合、使用されるメモリは線形ではなく、割り当てられたチャンクは通常メモリの別々の位置にあります(隣接していない)し、サイズによって割り当てを分けるためのビンやゾーンがあるため、以前に解放されたメモリが新しいチャンクを割り当てる前に使用されます。したがって、ヒープオーバーフローに対して脆弱なオブジェクトと衝突するオブジェクトを知るのは複雑です。そのため、ヒープオーバーフローが見つかった場合、オーバーフローされるオブジェクトの隣に目的のオブジェクトを配置するための信頼できる方法を見つける必要があります

このために使用される技術の一つがヒープグルーミングで、例えばこの投稿で説明されています。この投稿では、iOSカーネルでゾーンがメモリを使い果たすと、カーネルページによって拡張され、このページが期待されるサイズのチャンクに分割され、順番に使用されることが説明されています(iOSバージョン9.2まで、その後はこれらのチャンクがランダム化された方法で使用され、攻撃の悪用を困難にします)。

したがって、ヒープオーバーフローが発生している前の投稿では、オーバーフローされたオブジェクトが被害者のオブジェクトと衝突するようにするために、複数のスレッドによって複数のkallocが強制され、すべての空きチャンクが埋められ、新しいページが作成されることを試みます

特定のサイズのオブジェクトでこの埋め込みを強制するために、iOSマッチポートに関連するアウトオブライン割り当てが理想的な候補です。メッセージのサイズを調整することで、kalloc割り当てのサイズを正確に指定でき、対応するマッチポートが破棄されると、対応する割り当ては即座にkfreeに戻されます。

その後、これらのプレースホルダーのいくつかを解放できます。kalloc.4096のフリーリストは、後入れ先出しの順序で要素を解放します。これは基本的に、いくつかのプレースホルダーが解放され、エクスプロイトがオーバーフローに脆弱なオブジェクトを割り当てようとする際に、被害者オブジェクトがそのオブジェクトの後に続く可能性が高いことを意味します。

例 libc

このページでは、次のチャンクのprev in useビットとprevサイズの位置を上書きすることで、使用中のチャンクを統合(未使用だと思わせる)し、再度割り当てることができる基本的なヒープオーバーフローのエミュレーションを見つけることができます。

protostar heap 0の別の例では、ヒープオーバーフローを悪用して勝者関数を呼び出し、フラグを取得する非常に基本的なCTFの例が示されています。

protostar heap 1の例では、バッファオーバーフローを悪用することで、近くのチャンクにアドレスを上書きすることができ、ユーザーからの任意のデータが書き込まれることがわかります。

例 ARM64

ページhttps://8ksec.io/arm64-reversing-and-exploitation-part-1-arm-instruction-set-simple-heap-overflow/では、実行されるコマンドがオーバーフローしたチャンクの次のチャンクに格納されるヒープオーバーフローの例を見つけることができます。したがって、次のような簡単なエクスプロイトで上書きすることで、実行されるコマンドを変更することが可能です。

bash
python3 -c 'print("/"*0x400+"/bin/ls\x00")' > hax.txt

他の例

  • Auth-or-out. Hack The Box
  • 整数オーバーフローの脆弱性を利用してヒープオーバーフローを引き起こします。
  • オーバーフローしたチャンクのstruct内の関数へのポインタを破損させ、systemのような関数を設定してコード実行を得ます。

実世界の例: CVE-2025-40597 – __sprintf_chkの誤用

SonicWall SMA100ファームウェア10.2.1.15では、リバースプロキシモジュールmod_httprp.so0x80バイトのヒープチャンクを割り当て、その後__sprintf_chkを使用していくつかの文字列を連結します。

c
char *buf = calloc(0x80, 1);
/* … */
__sprintf_chk(buf,               /* destination (0x80-byte chunk) */
-1,                /* <-- size argument   !!! */
0,                 /* flags */
"%s%s%s%s",      /* format */
"/", "https://", path, host);

__sprintf_chk_FORTIFY_SOURCE の一部です。正の size パラメータを受け取ると、結果の文字列が宛先バッファに収まるかどうかを検証します。-1 (0xFFFFFFFFFFFFFFFF) を渡すことで、開発者は実質的に 境界チェックを無効化 し、強化された呼び出しを古典的で安全でない sprintf に戻しました。

したがって、過度に長い Host: ヘッダーを提供することで、攻撃者は 0x80バイトのチャンクをオーバーフローさせ、次のヒープチャンクのメタデータを上書きする ことができます(アロケータに応じて tcache / fast-bin / small-bin)。クラッシュは次のコマンドで再現できます:

python
import requests, warnings
warnings.filterwarnings('ignore')
requests.get(
'https://TARGET/__api__/',
headers={'Host': 'A'*750},
verify=False
)

実際のエクスプロイトには、制御可能なオブジェクトを脆弱なチャンクのすぐ後ろに配置するためのヒープグルーミングが必要ですが、根本的な原因は2つの重要なポイントを強調しています:

  1. _FORTIFY_SOURCEは万能ではない – 誤用は保護を無効にする可能性があります。
  2. 常に正しいバッファサイズ_chkファミリーに渡すこと(または、さらに良いことに、snprintfを使用すること)。

参考文献

tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする