GNU obstack function-pointer hijack

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をサポートする

概要

GNU obstack はアロケータの状態を埋め込み、以下の2つの間接呼び出し先を持ちます:

  • chunkfun (オフセット +0x38) — シグネチャ void *(*chunkfun)(void *, size_t)
  • freefun (オフセット +0x40) — シグネチャ void (*freefun)(void *, void *)
  • extra_arguse_extra_arg フラグは _obstack_newchunkchunkfun(new_size) を呼ぶか chunkfun(extra_arg, new_size) を呼ぶかを選択します

もし攻撃者がアプリケーション所有の struct obstack * やそのフィールドを破壊できれば、obstack が次に成長する(next_free == chunk_limit のとき)と chunkfun を通した間接呼び出しが発生し、コード実行のプリミティブが得られます。

プリミティブ: size_t のズレ → 0 バイト割当 → ポインタ OOB 書き込み

一般的なバグパターンは、論理長を 64-bit の size_t に保存しているのに、sizeof(ptr) * count の計算に 32ビットレジスタ を使っていることです。

  • 例: elements = obstack_alloc(obs, sizeof(void *) * size);size << 3 のために SHL EAX,0x3 としてコンパイルされます。
  • size = 0x20000000sizeof(void *) = 8 の場合、32ビットで乗算がラップして 0x0 になり、ポインタ配列は 0 バイト となりますが、記録される size0x20000000 のままです。
  • 続く elements[curr++] = ptr; の書き込みは、隣接するヒープオブジェクトへ 8 バイトの OOB ポインタ書き込み を行い、制御されたクロスオブジェクト上書きプリミティブを与えます。

Leaking libc via obstack.chunkfun

  1. 2つのヒープオブジェクトを隣接させる(例えば、別々の obstack で作った2つのスタック)。
  2. オブジェクト A からのポインタ配列の OOB 書き込みを使い、オブジェクト B の elements ポインタを上書きして、B からの pop/読み出しがオブジェクト A の obstack 内部のアドレスを参照するようにする。
  3. オフセット 0x38 にある chunkfun(デフォルトでは malloc)を読み出して libc の関数ポインタを漏らし、libc_base = leak - malloc_offset を計算して他のシンボル(例: system, "/bin/sh")を導出する。

Hijacking chunkfun with a fake obstack

被害者が保持している struct obstack * を上書きして、obstack ヘッダを模した攻撃者制御のデータを指すようにします。必要最小限のフィールド:

  • 次回 push 時に _obstack_newchunk を強制するために next_free == chunk_limit
  • chunkfun = system_addr
  • extra_arg = binsh_addr, use_extra_arg = 1 で2引数呼び出し形を選択

その後、被害者の obstack 上で割り当てをトリガーすると、間接呼び出しを通じて system("/bin/sh") が実行されます。

Example fake obstack layout (glibc 2.42 offsets):

fake  = b""
fake += p64(0x1000)          # chunk_size
fake += p64(heap_leak)       # chunk
fake += p64(heap_leak)       # object_base
fake += p64(heap_leak)       # next_free == chunk_limit
fake += p64(heap_leak)       # chunk_limit
fake += p64(0xF)             # alignment_mask
fake += p64(0)               # temp
fake += p64(system_addr)     # chunkfun
fake += p64(0)               # freefun
fake += p64(binsh_addr)      # extra_arg
fake += p64(1)               # use_extra_arg flag set

攻撃手順

  1. Trigger size wrap — 巨大な論理長を持つ0バイトのポインタ配列を作成する。
  2. Groom adjacency — OOB ポインタ書き込みが obstack ポインタを含む隣接オブジェクトに届くように整える。
  3. Leak libc — 隣接する obstack の chunkfun に対象ポインタを向け、関数ポインタを読み取ることで行う。
  4. Forge obstack — 制御された chunkfun/extra_arg を持つ obstack データを偽造し、_obstack_newchunk が偽造ヘッダ内に到達するよう強制して、攻撃者が選んだ関数ポインタ呼び出しを引き起こす。

参考

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をサポートする