一个概念验证,演示默认、非特权 Kubernetes Pod 如何通过共享容器镜像层利用 Dirty Frag Linux 内核页缓存损坏漏洞,在 Amazon EKS 上实现节点级代码执行。
核心攻击原语是:任何与攻击者控制的容器共享镜像层的特权 DaemonSet 都可以被武器化用于容器逃逸。本 PoC 以 kube-proxy 作为具体示例,但该技术可推广到集群中的任何特权工作负载。
已在 Amazon EKS(内核 6.12.80)上验证 — 非特权 Pod 通过特权 kube-proxy DaemonSet 向主机文件系统写入 [*] success:

免责声明: 本仓库仅用于教育和防御目的。请仅在您拥有或获得明确授权测试的系统上使用。
Dirty Frag (CVE-2026-43284) 是 Linux 内核 xfrm/ESP 接收路径中的页缓存损坏漏洞。在受影响的路径中,esp_input() 可能对没有 frag_list 的非线性 skb 跳过 skb_cow_data(),从而允许 crypto_authenc_esn_decrypt() 将通过 splice() 到达的页缓存页面中存储 4 字节攻击者控制的数据。
磁盘上的文件不会被修改。被损坏的字节存在于内核页缓存中,后续读取同一缓存文件页面的读者会观察到这些字节。
有关原始漏洞的完整详情,请参阅 V4bel/dirtyfrag。
该攻击利用了 Kubernetes 集群中常见的三个特性:
privileged: true、hostNetwork: true、广泛 capabilities 等)的 DaemonSet,这些 DaemonSet 会定期执行其镜像中的二进制文件。当这些条件同时满足时,非特权 Pod 可以损坏共享镜像层中的二进制文件,同一节点上的特权 DaemonSet 将不知情地以其提升的权限执行被损坏的二进制文件 — 从而实现完整的节点级代码执行。
漏洞目标不仅限于 kube-proxy。 任何容器镜像与攻击者控制的镜像共享层的特权 DaemonSet(监控代理、CNI 插件、日志收集器、安全代理等)都是可行的目标。
本项目受 Copy Fail Kubernetes PoC 中记录的 Kubernetes 利用模型启发,但使用了不同的内核原语。
攻击链包含三个阶段:页缓存损坏、跨容器传播和特权执行。
PoC 二进制文件在非特权容器中执行以下序列:
unshare(CLONE_NEWUSER | CLONE_NEWNET) 进入新的用户和网络命名空间。splice() 和精心构造的 ESP 输入触发易受攻击的内核路径。不需要对目标文件的写权限。磁盘上的文件不变 — 只有内存中的页缓存被损坏。
容器运行时通过内核页缓存提供 overlay 较低层的读取。如果 PoC 容器和 kube-proxy 共享相同的较低层文件,则两者观察到相同的缓存页面。
本仓库中的 EKS 镜像基于以下构建:
public.ecr.aws/eks-distro-build-tooling/eks-distro-minimal-base-iptables:2026-03-11-1773190710.2023
选择该基础镜像是为了匹配验证环境中使用的 EKS kube-proxy 用户空间工具链层。
当 kube-proxy 下次执行被修补的 iptables 系列二进制文件时,内核会加载被损坏的缓存页面。PoC 负载挂载主机根设备并将标记文件写入 /root/res。
预期的标记内容为:
[*] success
┌──────────────────────────────┐ ┌────────────────────────┐ ┌──────────────────────────┐
│ PoC Pod │ │ 内核页缓存 │ │ kube-proxy DaemonSet │
│ 非特权容器 │ │ │ │ 特权容器 │
│ │ │ │ │ │
│ 1. unshare 用户+网络命名空间│ │ │ │ │
│ 2. 安装 xfrm SA │ │ │ │ │
│ 3. 通过 ESP 路径 splice │────▶│ 共享层二进制文件 │────▶│ 执行被修补的二进制文件 │
│ 目标二进制文件 │ │ 页缓存被修补 │ │ 负载以节点级权限运行 │
│ │ │ │ │ │
└──────────────────────────────┘ └────────────────────────┘ └──────────────────────────┘
我已在 GKE 和 ACK 集群上进行了测试。全部失败。
Dirty Frag 原语需要创建用户命名空间(CLONE_NEWUSER)才能在新的网络命名空间内获得 CAP_NET_ADMIN。ACK 和 GKE 都通过不同的机制在节点级别阻止了这一点:
user.max_user_namespaces=0)完全阻止了非特权用户命名空间的创建。--seccomp-default 标志启用)阻止了 unshare 系统调用,无论命名空间限制如何。这是与 Copy Fail (CVE-2026-31431) 的关键区别,后者不需要用户命名空间,并成功利用了所有三个平台。
提供的 EKS 变体在存在以下二进制文件时对其进行修补:
/usr/sbin/xtables-legacy-multi
/usr/sbin/xtables-nft-multi
这些二进制文件由 kube-proxy 使用的 iptables 工具链调用。确切的触发时机取决于节点和服务协调活动。在验证环境中,负载由正常的 kube-proxy 协调触发。
重要注意事项:
ipset。默认模式(iptables)不使用 ipset。xtables-legacy-multi、xtables-nft-multi)以覆盖不同的代理模式,但它们是否被调用取决于集群配置。如果您的集群中 kube-proxy 不是特权的,攻击原理仍然成立 — 您只需要识别一个不同的、与您可以构建的基础镜像共享镜像层的特权 DaemonSet。
.
├── exploit/
│ └── dirtyfrag.c # xfrm/ESP 页缓存写入器
├── payload/
│ ├── payload-eks.c # 在主机上写入 /root/res 的 nolibc 负载
│ └── nolibc/ # Linux nolibc 头文件
├── deploy/
│ └── poc-eks.yaml # 非特权 EKS Deployment 清单
├── scripts/
│ ├── setup-eks.sh # 在 EKS 节点上复制、构建和导入镜像
│ ├── run-poc.sh # 部署并检查标记
│ └── cleanup.sh # 移除 Pod、标记、缓存页面和本地镜像
├── Dockerfile.eks # 基于 eks-distro-minimal-base-iptables 的 EKS 镜像
├── Makefile # payload、exploit、Docker 和 nerdctl 构建目标
└── .github/workflows/
└── docker-publish.yml # GHCR 发布工作流
# 构建 payload + exploit 二进制文件
make build-eks CC=x86_64-linux-gnu-gcc
# 构建 Docker 镜像
make docker-build-eks
# 部署(非特权 Pod)
kubectl apply -f deploy/poc-eks.yaml
# 检查日志
kubectl logs deployment/dirtyfrag-poc-eks
# 在节点上验证逃逸
ssh ec2-user@<node-ip> "sudo cat /root/res"
# 预期输出: [*] success
GitHub Actions 工作流(.github/workflows/docker-publish.yml)在推送到 main 或创建标签时将镜像发布到 GHCR。将 deploy/poc-eks.yaml 中的 <owner> 替换为拥有 fork 的 GitHub 用户或组织。
kubectl delete -f deploy/poc-eks.yaml --ignore-not-found
ssh ec2-user@<node-ip> "sudo rm -f /root/res"
kubectl delete pod -n kube-system -l k8s-app=kube-proxy --force
f4c50a4034e6)之前的所有版本。f4c50a4034e6 或供应商反向移植。esp4 和 esp6。user.max_user_namespaces=0 可防止此 PoC 在新的网络命名空间中获得 CAP_NET_ADMIN(这已是 ACK 上的默认设置)。privileged: true 和广泛的主机访问。示例模块阻止:
printf 'install esp4 /bin/false\ninstall esp6 /bin/false\n' | sudo tee /etc/modprobe.d/dirtyfrag.conf
sudo rmmod esp4 esp6 2>/dev/null || true
漏洞利用代码改编自 V4bel/dirtyfrag,遵循 MIT 许可证。
负载代码源自 tgies/copy-fail-c,采用 LGPL-2.1-or-later OR MIT 双重许可。
nolibc 头文件来自 Linux 内核自测基础设施。
| 属性 | Copy Fail | Dirty Frag |
|---|
| CVE | CVE-2026-31431 | CVE-2026-43284 |
| 内核路径 | AF_ALG + splice() | xfrm/ESP + splice() |
| 命名空间要求 | 不需要 | 需要用户命名空间 |
| 使用的主要能力 | 初始容器中无 | 新网络命名空间内的 CAP_NET_ADMIN |
| 相关模块 | algif_aead | esp4 |
| 实际区别 | 如果 AF_ALG 向量被阻止则失效 | 当 AF_ALG 不可用但 ESP/用户命名空间启用时仍然有效 |
| 属性 | 值 |
|---|
| 平台 | Amazon Elastic Kubernetes Service (EKS) |
| 节点内核 | 6.12.80-106.156.amzn2023.x86_64 |
| 补丁状态 | 修复前内核,缺少 f4c50a4034e6 |
esp4 模块 | 已加载 |
| 用户命名空间 | 已启用(user.max_user_namespaces=15030) |
| SELinux | 宽容模式 |
| Seccomp | 测试 Pod 上下文中不受限制 |
| 目标 DaemonSet | kube-proxy |
| 目标权限 | privileged: true、hostNetwork: true |
| 代理模式 | iptables |
| 标记路径 | /root/res |
| 平台 | 结果 | 原因 |
|---|
| 阿里云 ACK | 失败 | 默认节点镜像上 user.max_user_namespaces 设置为 0,因此非特权用户无法使用 CLONE_NEWUSER unshare。 |
| Google GKE | 失败 | user.max_user_namespaces 为 15426,但 kubelet 启用了 --seccomp-default。默认 seccomp 策略禁用了 unshare 系统调用。 |