unlink
unlink
山林川泽1. 核心原理:glibc 的堆块管理机制
在 glibc 中,空闲堆块通过双向链表组织(fd 和 bk 指针)
1 | struct malloc_chunk { |
当释放堆块时,glibc 会执行 unlink 操作将其从空闲链表移除:
1 | // 简化版 unlink 宏 |
2. 攻击条件
- 堆溢出漏洞:可覆盖相邻堆块的头部数据(
prev_size和size) - 可控内存:能伪造堆块结构(控制
fd和bk指针) - 触发 unlink:需通过
free()或堆合并触发目标堆块的unlink操作
3. 攻击步骤图解
步骤 1:伪造堆块结构
假设存在堆块 A(易溢出)和 B(目标),在 A 中伪造一个空闲堆块:
1 | 伪造的堆块 P |
步骤 2:修改相邻堆块头
通过堆溢出修改 B 的头部:
1 | B->prev_size = 伪造堆块大小 // 使系统认为 P 是空闲块 |
步骤 3:触发 unlink
释放堆块 B 时,glibc 会:
- 检查
B->prev_inuse=0,认为前一块P空闲 - 尝试合并
P和B,触发unlink(P)
步骤 4:unlink 任意地址写
执行 unlink 操作时:
1 | FD = P->fd = target - 0x18 |
最终 *target 被修改为 target - 0x18。
4. 现代 glibc 的防护与绕过
防护机制(Safe-Unlinking)
1 | // glibc 2.3.6+ 的检查 |
绕过方法
构造满足检查的伪造指针
1 | P->fd = target - 0x18 |
5. 实战利用场景
场景:修改 GOT 表执行 shellcode
- 选择目标:
free@got.plt - 构造
target = free@got.plt - 触发
unlink后:*free@got.plt = free@got.plt - 0x18 - 通过堆操作写
free@got.plt区域:
1 | # 此时 free@got.plt 指向自身 -0x18 |



