其他
glibc/ptmalloc2 堆漏洞利用时按版本选择…
在针对 ptmalloc2/glibc 堆漏洞(UAF、double free、overflow、off-by-one/null)时,按 glibc 版本选择 tcache/fastbin/unsortedbin 攻击,做 heap/libc 泄漏并转为任意写或代码执行。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 35/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 38/100 ×0.15
适用场景
glibc/ptmalloc2 堆漏洞利特定
解决思路
- 按 glibc 版本约束选择攻击手法,并显式检查 glibc ≥2.32 引入的 safe-linking (PROTECT_PTR),避免混淆版本约束或遗漏指针编码。
- 若溢出发生在栈而不是堆,转向 stack-overflow-and-rop。
- 若需要通过格式化字符串泄漏 heap/libc 地址,转向 format-string-exploitation。
- 若要把堆任意写转化为代码执行,转向 arbitrary-write-to-rce。
- 若需要绕过 ASLR/RELRO 以有效使用堆写,转向 binary-protection-bypass。
- 使用 HOUSE_OF_TECHNIQUES.md 查阅 House of Force/Spirit/Orange/Einherjar/Roman/Pig/Banana/Cat/Apple 与 tcache 攻击。
- 使用 IO_FILE_EXPLOITATION.md 查阅 _IO_FILE vtable 劫持、FSOP、stdout/stdin 滥用、exit 流程利用。
- 按 64 位 malloc_chunk 布局定位字段:0x00 prev_size(前一块空闲时有效),0x08 size|A|M|P(P=PREV_INUSE,M=IS_MMAPPED,A=NON_MAIN_ARENA),0x10 fd(空闲时指向下一个空闲块),0x18 bk(空闲时指向前一个空闲块),0x20 fd_nextsize(仅 large),0x28 bk_nextsize(仅 large)。
- 根据 bin 类型选择操作:tcache 每线程 ≤0x410(每种大小最多 7 项),单链表 next 指针,LIFO。
- 根据 bin 类型选择操作:fastbin ≤0x80(默认),单链表 fd,LIFO。
- 根据 bin 类型选择操作:unsortedbin 任意释放大小,双向循环链表,FIFO。
- 根据 bin 类型选择操作:smallbin <0x400,双向循环链表,FIFO。
- 根据 bin 类型选择操作:largebin ≥0x400,双向链表并按大小排序。
- 记住关键全局结构:main_arena 在 libc .data 段,含 bin heads、top chunk、system_mem。
- 记住关键全局结构:mp_ 在 libc .data,含 malloc 参数(tcache 设置、mmap threshold)。
- 记住关键全局结构:tcache_perthread_struct 在堆(首次分配),含每线程 tcache bins 与 counts。
- 泄漏 libc base:释放一个大于 tcache 范围的 chunk(或填满 tcache)进入 unsortedbin,读取 fd/bk → main_arena + 0x60(或视版本 +0x70)→ libc base。
- 泄漏 libc base:将 chunk 从 unsortedbin 移入 smallbin 后,读取 smallbin fd/bk,同 unsortedbin 泄漏方式。
- 泄漏 libc base:写 _IO_2_1_stdout_,破坏 _IO_write_base 泄漏 libc 数据(见 IO_FILE)。
- 泄漏 heap base:释放两个 tcache chunk,读取第一个 chunk 的 fd;fd → heap 地址(≥2.32 时经过 XOR 混淆)。
- 泄漏 heap base:释放两个 fastbin chunk,读取 fd → heap 地址。
- 泄漏 heap base:利用 UAF 读取已释放 chunk,直接读取 fd/bk。
- Safe-Linking(glibc ≥2.32)解码:PROTECT_PTR 公式 fd_stored = (chunk_addr >> 12) ^ real_fd。
- Safe-Linking 解码:real_fd = fd_stored ^ (chunk_addr >> 12);编码:fd_stored = (chunk_addr >> 12) ^ target_addr。
- 使用 Python deobfuscate(stored_fd, chunk_addr): return stored_fd ^ (chunk_addr >> 12)。
- 使用 Python obfuscate(target, chunk_addr): return (chunk_addr >> 12) ^ target。
- glibc <2.26(无 tcache):Fastbin dup——double free → 任意分配。
- glibc <2.26:Unsortedbin attack——破坏 unsortedbin bk → 将 main_arena 地址写到目标(用于 __malloc_hook 附近覆写)。
- glibc <2.26:Unlink attack——堆溢出写入 prev_size + fd/bk → 任意写(需要已知 heap 指针)。
- glibc <2.26:House of Force——覆写 top chunk size → 任意分配。
- glibc <2.26:House of Spirit——写入 fake chunk header → 在 fake chunk 处进行 fastbin 分配。
- glibc <2.26:Off-by-one null——空字节溢出到下一 chunk size → 重叠 chunk。
- glibc 2.26–2.28(有 tcache,无 key):Tcache poisoning——覆写 tcache fd → 任意分配,无 size 检查。
- glibc 2.26–2.28:Tcache dup——double free 进入 tcache(尚无 double-free 检测)。
- glibc 2.26–2.28:此前攻击仍可用,但 chunk 会先进入 tcache。
- glibc 2.29–2.31(引入 tcache key):Tcache dup——第二次 free 前破坏 key 字段(位于 chunk+0x18)。
- glibc 2.29–2.31:House of Botcake——double free:一个放入 unsortedbin,一个放入 tcache → 重叠。
- glibc 2.29–2.31:Tcache stashing unlink——滥用 smallbin→tcache 填充获得任意 chunk。
- glibc 2.32–2.33(safe-linking / PROTECT_PTR):Tcache poisoning——用 (chunk_addr >> 12) ^ target 编码目标。
- glibc 2.32–2.33:需要 heap leak——需要 heap 地址来解码/编码 safe-linked 指针。
- glibc 2.32–2.33:Fastbin dup——同样需要编码。
- glibc ≥2.34(hooks 移除):__malloc_hook 已移除,不能覆写 hook 来用 one_gadget。
- glibc ≥2.34:__free_hook 已移除,不能覆写 hook。
- glibc ≥2.34:__realloc_hook 已移除,不能用 realloc trick 满足 one_gadget 约束。
- glibc ≥2.34 后目标:参见 arbitrary-write-to-rce 中的 _IO_FILE、exit_funcs、TLS_dtor_list、_dl_fini。
- UAF:free 后访问 chunk;读时泄漏 fd/bk,写时破坏 fd 以进行 tcache poisoning。
- Double Free:对同一 chunk 调用 free() 两次;使用 tcache dup(绕过 key)或 fastbin dup。
- Heap Overflow:越过 chunk 边界写入;破坏下一 chunk 元数据(size、fd、bk)。
- Off-by-one:一字节溢出;空字节 → 缩小下一 chunk size → 重叠 chunk。
- Off-by-null:特指 0x00 溢出;清除 PREV_INUSE → 触发向后合并。
- Uninitialized read:未清零就读取堆内存;从回收 chunk 泄漏 fd/bk。
- 使用 pwndbg 检查堆:运行 pwndbg> heap 显示所有 chunk。
- 使用 pwndbg:运行 pwndbg> bins 显示所有 bin 内容。
- 使用 pwndbg:运行 pwndbg> tcachebins 查看 tcache 状态。
- 使用 pwndbg:运行 pwndbg> fastbins 查看 fastbin 状态。
- 使用 pwndbg:运行 pwndbg> unsortedbin 查看 unsortedbin 内容。
- 使用 pwndbg:运行 pwndbg> vis_heap_chunks 可视化堆布局。
- 使用 pwndbg:运行 pwndbg> find_fake_fast &__malloc_hook 查找附近 fake fastbin chunk。
- 获取 how2heap 参考实现:git clone https://github.com/shellphish/how2heap。
- 安装 heapinspect:pip install heapinspect。
- 运行 heapinspect:heapinspect <pid>。
- 使用 pwntools:from pwn import *;libc = ELF('./libc.so.6')。
- 使用 pwntools 打印 libc 符号:print(hex(libc.symbols['__malloc_hook']));print(hex(libc.symbols['__free_hook']))。
- 决策树入口:已识别堆漏洞后,先判断可用原语。
- 若原语是 UAF(读+写):若能读已释放 chunk,则用 unsortedbin 泄漏 libc 或用 tcache fd 泄漏 heap。
- 若原语是 UAF:若能写已释放 chunk,则使用 tcache poisoning / fastbin dup。
- 若原语是 Double free:glibc <2.29 → 直接 tcache dup。
- 若原语是 Double free:glibc 2.29–2.31 → 先破坏 tcache key,或用 House of Botcake。
- 若原语是 Double free:glibc ≥2.32 → 需要 heap leak 来做 safe-linking 编码。
- 若原语是 Heap overflow(可控大小):覆写下一 chunk size → 重叠 chunk → UAF。
- 若原语是 Heap overflow:直接覆写 fd → 任意分配。
- 若原语是 Off-by-one / off-by-null:空字节写入 size → House of Einherjar(向后合并)。
- 若原语是 Off-by-one / off-by-null:一字节写入 size → 缩小 chunk,制造重叠。
- 若原语是任意写(来自重叠或 poisoned allocation):glibc <2.34 → __malloc_hook / __free_hook → one_gadget。
- 若原语是任意写:glibc ≥2.34 → _IO_FILE vtable、exit_funcs、TLS_dtor_list。
- 若原语是任意写:Partial RELRO → GOT overwrite。
- 若需要 libc leak:释放 chunk 进入 unsortedbin(size >0x410 或填满 7 个 tcache)。
- 若需要 libc leak:读取 fd/bk → main_arena 偏移 → libc base。
- 若需要 libc leak:备选是 stdout FILE 部分覆写进行泄漏。
- 若需要 heap leak(glibc ≥2.32):从已释放 chunk 读取 tcache fd。
- 若需要 heap leak:解码 real_addr = stored_fd ^ (chunk_addr >> 12)。
适用边界 · 注意事项
- 当漏洞在栈而不是堆时,不适用;改用 stack-overflow-and-rop。
- 当目标不是 ptmalloc2/glibc 堆(例如其他分配器或非 glibc 环境)时,不适用。
- 当目标 glibc ≥2.34 且只依赖 __malloc_hook/__free_hook/__realloc_hook 时,不适用;需转向 _IO_FILE、exit_funcs、TLS_dtor_list、_dl_fini 等。