Linux内核通用堆喷射技术详解
字数 1206 2025-08-20 18:18:17
Linux内核通用堆喷射技术详解
1. 堆喷射技术概述
堆喷射技术是一种利用内核内存分配机制来精确控制特定内存区域内容的方法,主要用于利用内核中的UAF(Use-After-Free)和堆溢出等漏洞。
1.1 理想堆喷射技术的条件
- 对象大小由用户控制:即使对于非常小的对象(如kmalloc-8)也没有限制
- 对象内容由用户控制:在对象的开头部分没有不受控制的头部
- 目标对象应持久存在于内核中:对复杂的UAF和竞争条件漏洞利用特别有用
2. 现有堆喷射技术的局限性
2.1 msgsnd()喷射技术
#define BUFF_SIZE 96-48
struct {
long mtype;
char mtext[BUFF_SIZE];
} msg;
memset(msg.mtext, 0x42, BUFF_SIZE-1);
msg.mtext[BUFF_SIZE] = 0;
msg.mtype = 1;
int msqid = msgget(IPC_PRIVATE, 0644 | IPC_CREAT);
msgsnd(msqid, &msg, sizeof(msg.mtext), 0);
问题:
- 存在48字节的不可控头部(struct msg_msg)
- 不适用于需要控制前48字节的目标对象
- 仅满足持久性条件(对象会保留在内核中直到进程终止或调用msgrcv)
2.2 其他喷射技术(add_key, sendmsg等)
同样存在对象大小限制或无法控制对象头部的问题。
3. 通用堆喷射技术实现
3.1 技术核心:userfaultfd + setxattr
userfaultfd:
- 允许在用户空间处理页面错误
- 可以延迟内存分配操作,控制内核执行流程
setxattr()系统调用路径:
static long setxattr(struct dentry *d, const char __user *name,
const void __user *value, size_t size, int flags)
{
int error;
void *kvalue = NULL;
void *vvalue = NULL; /* If non-NULL, we used vmalloc() */
char kname[XATTR_NAME_MAX + 1];
if (flags & ~(XATTR_CREATE|XATTR_REPLACE))
return -EINVAL;
error = strncpy_from_user(kname, name, sizeof(kname));
if (error == 0 || error == sizeof(kname))
error = -ERANGE;
if (error < 0)
return error;
if (size) {
if (size > XATTR_SIZE_MAX)
return -E2BIG;
kvalue = kmalloc(size, GFP_KERNEL | __GFP_NOWARN); // [5] 分配
if (!kvalue) {
vvalue = vmalloc(size);
if (!vvalue)
return -ENOMEM;
kvalue = vvalue;
}
if (copy_from_user(kvalue, value, size)) { // [6] 复制
error = -EFAULT;
goto out;
}
if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
(strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
posix_acl_fix_xattr_from_user(kvalue, size);
}
error = vfs_setxattr(d, kname, kvalue, size, flags);
out:
if (vvalue)
vfree(vvalue);
else
kfree(kvalue); // [7] 释放
return error;
}
优势:
- 对象大小完全由用户控制(通过size参数)
- 对象内容完全由用户控制(通过value参数)
- 结合userfaultfd可实现对象持久化
3.2 实现步骤
-
分配两个相邻内存页面:
- 将目标对象放在页面边界
- 前8字节(如函数指针)放在第一页
- 其余字节放在第二页
-
设置userfaultfd:
- 在第二页上设置页面错误处理程序
- 第一页的PF仍由内核处理
-
触发喷射:
- 当setxattr()执行到copy_from_user时:
- 函数指针(8字节)被复制到kvalue
- 复制剩余字节时会触发用户空间PF处理
- 让处理线程休眠,保持对象在内核中
- 当setxattr()执行到copy_from_user时:
4. 实际应用案例
-
DCCP UAF漏洞利用:
- 目标对象大小:16字节
- 前8字节为函数指针
-
IrDA子系统0day漏洞:
- 目标对象大小:56字节
- 前16字节为目标指针
5. 技术优势与局限
优势:
- 完全控制对象大小和内容
- 适用于非常小的对象(kmalloc-8/16)
- 可精确控制对象头部内容
- 对象可持久存在于内核中
局限:
- 主用户空间执行路径会被挂起
- 可通过fork或创建第二个线程解决(子进程用于堆喷射,父进程触发UAF)
6. 其他可能的执行路径
虽然本文重点介绍了setxattr路径,但内核中还存在其他满足条件1和2的执行路径,都可以与userfaultfd结合使用实现通用堆喷射。
7. 总结
这种userfaultfd+setxattr的组合技术提供了一种通用的内核堆喷射方法,特别适合利用需要精确控制小对象或对象头部的内核漏洞。通过精心控制页面错误处理,可以实现对内核内存布局的精确操控,为复杂的内核漏洞利用提供了可靠的基础。