Libc 保护

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

块对齐强制

Malloc 在分配内存时以 8-byte (32-bit) 或 16-byte (64-bit) 分组 进行。这意味着在 32-bit 系统中块的末尾应与 0x8 对齐,在 64-bit 系统中应与 0x0 对齐。该安全特性在从某个 bin 使用指针之前会检查每个块是否在这些特定位置正确对齐

安全优势

在 64-bit 系统中强制块对齐显著提高了 Malloc 的安全性,因为它将伪造块的放置限制为每 16 个地址中的 1 个。这使得利用变得更加困难,尤其是在用户对输入值控制有限的场景中,令攻击更复杂、更难成功。

  • Fastbin Attack on __malloc_hook

Malloc 的新对齐规则也阻止了涉及 __malloc_hook 的经典攻击。以前,攻击者可以操纵块大小来覆盖此函数指针并获得代码执行。现在,严格的对齐要求保证这类操纵不再可行,封堵了一条常见的利用路径并增强整体安全性。

Note: Since glibc 2.34 the legacy hooks (__malloc_hook, __free_hook, etc.) are removed from the exported ABI. Modern exploits now target other writable function pointers (e.g. tcache per-thread struct, vtable-style callbacks) or rely on setcontext, _IO_list_all primitives, etc.

Pointer Mangling on fastbins and tcache

Pointer Mangling 是一种用于保护 fastbin 和 tcache Fd 指针 的安全增强技术。该技术有助于防止某些类型的内存利用手法,尤其是那些不需要 leaked memory 信息或直接相对于已知位置操作内存位置(相对覆盖)的攻击。

该技术的核心是一个混淆公式:

New_Ptr = (L >> 12) XOR P

  • L 是指针的 存储位置 (Storage Location)
  • P 是实际的 fastbin/tcache Fd Pointer

在执行 XOR 操作前将存储位置 (L) 右移 12 位的原因非常关键。此操作解决了内存地址最低 12 位确定性带来的脆弱性,这些位通常由于系统架构约束而可预测。通过右移,这部分可预测位被移出运算,提高了新混淆指针的随机性,从而防止依赖这些位可预测性的利用。

这个混淆指针利用了 ASLR 提供的现有随机性,ASLR 随机化程序使用的地址,使攻击者难以预测进程的内存布局。

Demangling 指针以恢复原始地址涉及使用相同的 XOR 操作。在这里,混淆后的指针被视为公式中的 P,当它与未改变的存储位置 (L) 进行 XOR 时,就会得到原始指针。混淆和解混淆的对称性确保系统可以高效地编码和解码指针而不会带来显著开销,同时大幅提高针对操纵内存指针攻击的安全性。

安全优势

Pointer mangling 的目标是防止堆管理中的部分或全部指针覆盖,这是对安全性的重大增强。该特性对利用技术产生了多方面影响:

  1. 防止按字节的相对覆盖 (Bye Byte Relative Overwrites):此前攻击者可以修改指针的一部分以在不知道精确地址的情况下将堆块重定向到不同位置,这在 leakless House of Roman 利用中有所体现。使用 pointer mangling 后,这类在没有 heap leak 的情况下的相对覆盖现在需要进行暴力破解,从而大大降低了成功的可能性。
  2. 增加对 tcache Bin / Fastbin 攻击的难度:常见通过覆盖 fastbin 或 tcache 条目来覆盖函数指针(如 __malloc_hook)的攻击受到阻碍。例如,攻击可能先泄露 LibC 地址,将一个块 free 到 tcache bin,然后覆盖 Fd 指针使其指向 __malloc_hook 以取得任意代码执行。由于 pointer mangling,这些指针必须被正确混淆,需要 heap leak 才能准确操纵,从而提高了利用门槛。
  3. 在非堆位置创建伪造块也需要 heap leak:在非堆区域(如栈、.bss 段或 PLT/GOT)创建伪造块现在也需要 heap leak,因为需要进行指针混淆。这使得利用这些区域的复杂性增加,类似于操纵 LibC 地址时的要求。
  4. 泄露 heap 地址变得更有挑战:Pointer mangling 限制了 fastbin 和 tcache bins 中 Fd 指针作为 heap 地址泄露来源的可用性。然而,unsorted、small 和 large bins 中的指针仍然未被混淆,因此仍可用于泄露地址。这一变化促使攻击者转向这些 bins 寻找可利用的信息,尽管某些技术仍可能在泄露之前对指针进行解混淆,但会附带更多约束。

Safe-Linking Bypass (page-aligned leak scenario)

即使启用了 safe-linking(glibc ≥ 2.32),如果你能够泄露被混淆的指针并且被破坏的 chunk 与受害 chunk 位于同一 4KB 页面内,原始指针可以仅通过页面偏移 (page offset) 恢复:

// leaked_fd is the mangled Fd read from the chunk on the same page
uintptr_t l = (uintptr_t)&chunk->fd;           // storage location
uintptr_t original = (leaked_fd ^ (l >> 12));  // demangle

This restores the Fd and permits classic tcache/fastbin poisoning. If the chunks sit on different pages, brute-forcing the 12-bit page offset (0x1000 possibilities) is often feasible when allocation patterns are deterministic or when crashes are acceptable (e.g., CTF-style exploits).

Demangling Pointers with a Heap Leak

Caution

有关该过程的更好解释请 check the original post from here.

Algorithm Overview

用于指针混淆和解混淆的公式为:

New_Ptr = (L >> 12) XOR P

其中 L 是存储位置,P 是 Fd 指针。由于 XOR 的特性(当位与自身异或时输出为 0),当 L 右移 12 位时,它会暴露 P 的最高有效位。

算法中的关键步骤:

  1. 初始泄露最高有效位:通过将右移后的 LP 异或,你实际上可以得到 P 的顶部若干位,因为右移后的 L 对应位为零,保留了 P 的相应位。
  2. 恢复指针位:由于 XOR 可逆,已知结果和其中一个操作数可以计算出另一个操作数。利用这一属性,可以通过已知的位集与混淆指针的部分成功异或,逐步推导出 P 的整个位集。
  3. 迭代解混淆:重复该过程,每次使用上一步新发现的 P 的位来解码混淆指针的下一段,直到恢复出所有位。
  4. 处理确定性位:由于右移,L 的最后 12 位丢失,但这些位是确定性的,可以在后处理阶段重建。

你可以在这里找到该算法的实现: https://github.com/mdulin2/mangle

Pointer Guard

Pointer Guard 是 glibc 中用于保护已存储函数指针(尤其是通过库调用如 atexit() 注册的那些指针)的利用缓解技术。该保护通过将指针与存储在线程数据中的一个秘密(fs:0x30)进行 XOR,并执行位旋转来对指针进行混淆。该机制旨在防止攻击者通过覆盖函数指针来劫持控制流。

Bypassing Pointer Guard with a leak

  1. 理解 Pointer Guard 的操作: 指针的混淆是使用 PTR_MANGLE 宏完成的,该宏将指针与 64-bit 的 secret 进行 XOR,然后对结果执行左旋 0x11 位。恢复原始指针的反向操作由 PTR_DEMANGLE 处理。
  2. 攻击策略: 攻击基于已知明文的方法,攻击者需要同时知道指针的原始值和混淆后的版本以推断用于混淆的 secret。
  3. 利用已知明文:
  • Identifying Fixed Function Pointers: 通过检查 glibc 源码或已初始化的函数指针表(例如 __libc_pthread_functions),攻击者可以找到可预测的函数指针。
  • Computing the Secret: 使用一个已知的函数指针(例如 __pthread_attr_destroy)及其在函数指针表中的混淆版本,可以通过对混淆指针进行反向旋转(右旋)然后与函数地址 XOR 来计算出 secret。
  1. 备用明文: 攻击者也可以尝试使用已知值(如 0 或 -1)对指针进行混淆,查看这些模式是否在内存中产生可识别的痕迹,从而在内存转储中发现这些模式时可能泄露 secret。
  2. 实际应用: 计算出 secret 后,攻击者就可以以受控方式操纵指针,实质上在已知 libc 基址并能读取任意内存位置的多线程应用中绕过 Pointer Guard 保护。

GLIBC Tunables & Recent Loader Bugs

动态 loader 在程序启动前解析 GLIBC_TUNABLES。这里的解析错误会在大多数缓解措施生效之前直接影响 libc。2023 年的 “Looney Tunables” 漏洞(CVE-2023-4911)就是一个例子:过长的 GLIBC_TUNABLES 值溢出 ld.so 内部缓冲区,当与 SUID 二进制结合时,可在许多发行版上实现 特权提升。利用只需构造环境并反复调用目标二进制;pointer guard 或 safe-linking 无法阻止此类攻击,因为损坏发生在 loader 中并在堆设置之前。

References

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