Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 

Repository files navigation

kubelet-pwn

Toolkit para abusar de la API del kubelet en clústeres Kubernetes/k3s cuando un ServiceAccount tiene el permiso RBAC get nodes/proxy.

La idea

get nodes/proxy parece "solo lectura del nodo", pero el kubelet deriva el verbo de autorización del método HTTP:

Petición al kubelet Verbo RBAC ¿Cubierto por get nodes/proxy?
GET /pods, GET /logs/... get
POST /exec/..., POST /run/... create
GET /exec/... (upgrade) get ← ejecución de comandos

Es decir: con solo get nodes/proxy puedes ejecutar comandos en cualquier contenedor del nodo vía GET /exec. Si hay un pod privilegiado que monta el / del host (típico: node-exporter, agentes de logging/monitoring), eso es root en el host.

Detalles de transporte (aprendidos a base de sufrir)

  • El proxy del apiserver (/api/v1/nodes/<n>/proxy/exec/...) descarta la query string en peticiones de upgrade (tryUpgrade no copia RawQuery) → hay que hablar directo con el kubelet (:10250).
  • El kubelet suele rechazar WebSocket para exec pero acepta SPDY/3.1.
  • Parámetros de exec: command, output=1, error=1, input=1 (valores "1"), no stdin/stdout/stderr. El upgrade exige X-Stream-Protocol-Version.

Esta herramienta implementa un cliente SPDY/3.1 mínimo en Python puro (sin dependencias) que hace todo eso.

Uso

El token normalmente es el del ServiceAccount montado en un pod comprometido: /var/run/secrets/kubernetes.io/serviceaccount/token (valor por defecto de --token-file). El kubelet escucha en *:10250, así que --host es la IP del nodo (alcanzable desde cualquier pod o desde el propio host).

# 1. Recon: ver todos los pods del nodo
python3 kubelet_pwn.py pods --host 10.129.60.174 --token-file token

# 2. Encontrar el camino a root (privileged / host mounts) — resuelve el mountPath
python3 kubelet_pwn.py priv --host 10.129.60.174 --token-file token

# 3. Ejecutar en el pod privilegiado que monta el host / en /host/root
python3 kubelet_pwn.py exec --host 10.129.60.174 --token-file token \
    -n monitoring -p prometheus-node-exporter-xxxxx -c node-exporter \
    -- /bin/sh -c 'id; cat /host/root/root/root.txt'

priv ya te imprime el comando exec exacto listo para copiar.

Notas

  • Si el contenedor objetivo no tiene /bin/sh (imágenes distroless), ejecuta un binario suelto: -- /bin/cat /host/root/root/root.txt.
  • --via-apiserver sirve para los recon GET (pods/priv) si no llegas al kubelet directo, pero no funciona para exec (el apiserver pierde la query).
  • Sin dependencias externas: solo Python 3 estándar (zlib, ssl, socket).

Aviso

Solo para pruebas de seguridad autorizadas (CTF, laboratorios, pentest con permiso explícito). El uso contra sistemas sin autorización es ilegal.

Origen

Destilado del privesc de la máquina HTB Fireflow: Langflow RCE → reuso de credencial → MCP JWT alg=none → code-exec en pod → SA con get nodes/proxy → exec SPDY/3.1 en node-exporter privilegiado → root.

About

Kubelet API abuse toolkit: recon + SPDY/3.1 exec abusando del RBAC 'get nodes/proxy' (k8s/k3s). Pure Python, sin deps.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages