Dirty Pagetable 学习 & 例题
字数 2054 2025-08-22 12:23:30
Dirty Pagetable 攻击技术详解
1. 技术概述
Dirty Pagetable 是一种利用堆漏洞(如 UAF 或 double free)来篡改末级页表中的 PTE(Page Table Entry)条目,从而实现任意物理地址读写的攻击技术。该技术可以绕过多种安全保护机制,包括:
- CFI(控制流完整性)
- KASLR(内核地址空间布局随机化)
- SMAP(Supervisor Mode Access Prevention)
- PAN(Privileged Access Never)
2. 攻击原理
Dirty Pagetable 攻击的核心思想是通过控制页表项来操纵虚拟地址到物理地址的映射关系,从而获得对任意物理内存的读写能力。
2.1 页表基础
在 Linux 系统中,页表用于将虚拟地址转换为物理地址。末级页表中的 PTE 条目包含以下关键信息:
- 物理页帧号
- 访问权限位
- 脏位(Dirty bit)
- 存在位(Present bit)
2.2 攻击流程
- 利用堆漏洞:通过 UAF 或 double free 漏洞控制一个内核对象
- 释放 slab 到伙伴系统:将包含漏洞对象的 slab 释放回伙伴系统
- 用户页表占用:分配用户页表来占用被释放的 slab
- 篡改 PTE:利用漏洞对象的功能修改 PTE 条目
- 实现任意读写:通过修改后的 PTE 访问任意物理内存
3. 详细攻击步骤
3.1 触发 UAF 漏洞
- 释放目标 object 并将 victim slab 释放回伙伴系统
- 释放 UAF object 并将所在 slab 的其他 object 全部释放
- 释放其他 slab,最终将 victim slab 释放进伙伴系统(Cross Cache Attack)
3.2 用户页表占用 victim slab
- 用户页表是直接通过页面分配器分配的
- 分配用户页表来占用 victim slab,需要使用最后一级页表
- 成功占用后,用户页表将位于之前漏洞对象所在的内存区域
3.3 篡改页表条目(PTE)
- 利用漏洞对象本身的功能来篡改 PTE 条目
- 例如,假设有一个系统调用可以修改漏洞对象中的内容
3.4 利用 PTE 修改内核
- 将 PTE 的物理地址设置为内核 text 段的物理地址
- 这样就可以直接 patch 内核代码
- 提权方法:patch
sys_setresuid(),使非特权用户也能调用
setresuid(0, 0, 0);
system("/system/bin/sh");
4. 实例分析:m0leCon Finals 2023-keasy
4.1 漏洞分析
- 存在 file object 的 UAF 漏洞
- 当
copy_to_user传入无效地址时:- 拷贝失败
- 调用
fput()减少文件引用计数 - 计数为0且为匿名文件时,释放文件结构体
- 但 fd 仍然绑定,可操作已释放的 file object
4.2 利用过程
4.2.1 Cross Cache Attack
由于 file object 使用独立的 slab,需要跨缓存攻击:
-
堆喷 file object 并构造 UAF object
for(size_t i = 0; i < SPRAY_FILE_COUNT; i++) { if(i == SPRAY_FILE_COUNT/2) { uaf_fd = spray_fd[fd_sp-1]; uaf_fd++; ioctl(dev_fd, 0, 0xdeadbeef); } spray_fd[fd_sp++] = open("/", O_RDONLY); } -
释放所有 filp object
for(int i = 0; i < SPRAY_FILE_COUNT; i++) { if(spray_fd[i]) close(spray_fd[i]); } -
让 PTE 占用 victim slab
- 使用
mmap分配虚拟地址空间 - 操作虚拟内存触发缺页,分配物理内存
- 末级页表会占用 victim slab
- 使用
4.2.2 寻找 victim pte
- 利用 file object 的
f_count字段(文件引用计数) - 通过
dup(fd)增加引用计数 - 增加 0x1000 可使两个 PTE 条目重叠,指向同一个 page
4.2.3 使用 dma-heap 替换 victim pte
- 使用
/dev/dma_heap/system分配内存struct dma_heap_allocation_data dmas = {0}; dmas.len = 0x1000; dmas.fd_flags = 2; ioctl(dma_fd, DMA_HEAP_IOCTL_ALLOC, &dmas); munmap(hijack_p, 0x1000); char *dma_buf = (char*)mmap(hijack_p, 0x1000, PROT_WRITE|PROT_READ, MAP_POPULATE|MAP_SHARED, dmas.fd, 0); - dma-heap 分配的内存来自
MIGRATE_UNMOVABLE区域,与页表相同
4.2.4 任意物理地址读写
- 使用
dup()增加 dma-buf 地址到 page table 处 - 篡改 PTE 实现任意物理地址访问
- 泄露内核基址:物理地址 0x9c000 处有内核 .text 地址
4.2.5 nsjail 逃逸
- 通过任意写 patch
do_symlinkat系统调用 - 使用 shellcode 完成提权和逃逸
5. 防御措施
针对 Dirty Pagetable 攻击,可以考虑以下防御措施:
- 加强堆漏洞防护:及时修复 UAF、double free 等漏洞
- 页表隔离:将用户页表和内核页表分配到不同的内存区域
- 内存分配策略:限制用户空间对不可移动内存的分配
- 监控页表修改:检测异常的页表修改行为
6. 总结
Dirty Pagetable 是一种高级的内核利用技术,它通过操纵页表项来实现强大的内存读写能力。这种技术展示了现代内核漏洞利用的复杂性,也提醒我们内核安全防护需要多层次、全方位的考虑。理解这种攻击技术有助于我们更好地设计防御方案,保护系统安全。