Abusing Roles/ClusterRoles in Kubernetes
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Aquí puedes encontrar algunas configuraciones de Roles y ClusterRoles potencialmente peligrosas.
Recuerda que puedes obtener todos los recursos soportados con kubectl api-resources
Se refiere al arte de obtener acceso a un principal diferente dentro del clúster con diferentes privilegios (dentro del clúster de kubernetes o a nubes externas) que los que ya tienes. En Kubernetes, hay básicamente 4 técnicas principales para escalar privilegios:
Poder suplantar a otros usuarios/grupos/SAs con mejores privilegios dentro del clúster de kubernetes o a nubes externas
Poder crear/parchear/ejecutar pods donde puedes encontrar o adjuntar SAs con mejores privilegios dentro del clúster de kubernetes o a nubes externas
Poder leer secretos ya que los tokens de SAs se almacenan como secretos
Poder escapar al nodo desde un contenedor, donde puedes robar todos los secretos de los contenedores que se ejecutan en el nodo, las credenciales del nodo y los permisos del nodo dentro de la nube en la que se está ejecutando (si los hay)
Una quinta técnica que merece mención es la capacidad de ejecutar port-forward en un pod, ya que podrías acceder a recursos interesantes dentro de ese pod.
El wildcard (*) otorga permiso sobre cualquier recurso con cualquier verbo. Es utilizado por administradores. Dentro de un ClusterRole, esto significa que un atacante podría abusar de cualquier namespace en el clúster.
En RBAC, ciertos permisos representan riesgos significativos:
create
: Concede la capacidad de crear cualquier recurso de clúster, arriesgando la escalada de privilegios.
list
: Permite listar todos los recursos, potencialmente filtrando datos sensibles.
get
: Permite acceder a secretos de cuentas de servicio, representando una amenaza a la seguridad.
Un atacante con los permisos para crear un pod, podría adjuntar una Cuenta de Servicio privilegiada al pod y robar el token para hacerse pasar por la Cuenta de Servicio. Efectivamente, escalando privilegios a ella.
Ejemplo de un pod que robará el token de la cuenta de servicio bootstrap-signer
y lo enviará al atacante:
Lo siguiente indica todos los privilegios que un contenedor puede tener:
Acceso privilegiado (deshabilitando protecciones y configurando capacidades)
Deshabilitar namespaces hostIPC y hostPid que pueden ayudar a escalar privilegios
Deshabilitar el namespace hostNetwork, dando acceso para robar privilegios de nube de nodos y mejor acceso a redes
Montar hosts / dentro del contenedor
Crea el pod con:
Una línea de este tweet y con algunas adiciones:
Ahora que puedes escapar al nodo, consulta las técnicas de post-explotación en:
Probablemente quieras ser más sigiloso, en las siguientes páginas puedes ver a qué podrías acceder si creas un pod habilitando solo algunos de los privilegios mencionados en la plantilla anterior:
Privileged + hostPID
Privileged only
hostPath
hostPID
hostNetwork
hostIPC
Puedes encontrar ejemplos de cómo crear/abusar de las configuraciones de pods privilegiados anteriores en https://github.com/BishopFox/badPods
Si puedes crear un pod (y opcionalmente una cuenta de servicio) podrías obtener privilegios en el entorno de la nube al asignar roles de nube a un pod o a una cuenta de servicio y luego acceder a él. Además, si puedes crear un pod con el espacio de nombres de red del host, puedes robar el rol de IAM de la instancia del nodo.
Para más información, consulta:
Pod Escape PrivilegesEs posible abusar de estos permisos para crear un nuevo pod y establecer privilegios como en el ejemplo anterior.
El siguiente yaml crea un daemonset y exfiltra el token de la SA dentro del pod:
pods/exec
es un recurso en kubernetes utilizado para ejecutar comandos en una shell dentro de un pod. Esto permite ejecutar comandos dentro de los contenedores o obtener una shell dentro.
Por lo tanto, es posible entrar en un pod y robar el token del SA, o entrar en un pod privilegiado, escapar al nodo y robar todos los tokens de los pods en el nodo y (ab)usar el nodo:
Este permiso permite redirigir un puerto local a un puerto en el pod especificado. Esto está destinado a poder depurar aplicaciones que se ejecutan dentro de un pod fácilmente, pero un atacante podría abusar de ello para obtener acceso a aplicaciones interesantes (como bases de datos) o vulnerables (¿webs?) dentro de un pod:
Como se indica en esta investigación, si puedes acceder o crear un pod con el directorio /var/log/
de los hosts montado en él, puedes escapar del contenedor.
Esto se debe básicamente a que cuando el Kube-API intenta obtener los logs de un contenedor (usando kubectl logs <pod>
), solicita el archivo 0.log
del pod utilizando el endpoint /logs/
del servicio Kubelet.
El servicio Kubelet expone el endpoint /logs/
, que básicamente expone el sistema de archivos /var/log
del contenedor.
Por lo tanto, un atacante con acceso para escribir en la carpeta /var/log/ del contenedor podría abusar de este comportamiento de 2 maneras:
Modificando el archivo 0.log
de su contenedor (generalmente ubicado en /var/logs/pods/namespace_pod_uid/container/0.log
) para que sea un symlink que apunte a /etc/shadow
por ejemplo. Luego, podrás exfiltrar el archivo shadow de los hosts haciendo:
Si el atacante controla cualquier principal con los permisos para leer nodes/log
, puede simplemente crear un symlink en /host-mounted/var/log/sym
a /
y al acceder a https://<gateway>:10250/logs/sym/
listará el sistema de archivos raíz del host (cambiar el symlink puede proporcionar acceso a archivos).
Un laboratorio y un exploit automatizado se pueden encontrar en https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts
Si tienes la suerte de que la capacidad altamente privilegiada CAP_SYS_ADMIN
esté disponible, puedes simplemente volver a montar la carpeta como rw:
Como se indica en esta investigación, es posible eludir la protección:
Que estaba destinado a prevenir escapes como los anteriores al, en lugar de usar un hostPath mount, usar un PersistentVolume y un PersistentVolumeClaim para montar una carpeta de hosts en el contenedor con acceso de escritura:
Con un privilegio de suplantación de usuario, un atacante podría suplantar una cuenta privilegiada.
Simplemente usa el parámetro --as=<username>
en el comando kubectl
para suplantar a un usuario, o --as-group=<group>
para suplantar a un grupo:
O utiliza la API REST:
El permiso para listar secretos podría permitir a un atacante leer realmente los secretos accediendo al punto final de la API REST:
Mientras que un atacante en posesión de un token con permisos de lectura requiere el nombre exacto del secreto para usarlo, a diferencia del privilegio más amplio de listar secretos, aún existen vulnerabilidades. Las cuentas de servicio predeterminadas en el sistema pueden ser enumeradas, cada una asociada con un secreto. Estos secretos tienen una estructura de nombre: un prefijo estático seguido de un token alfanumérico aleatorio de cinco caracteres (excluyendo ciertos caracteres) de acuerdo con el código fuente.
El token se genera a partir de un conjunto limitado de 27 caracteres (bcdfghjklmnpqrstvwxz2456789
), en lugar del rango alfanumérico completo. Esta limitación reduce el total de combinaciones posibles a 14,348,907 (27^5). En consecuencia, un atacante podría ejecutar razonablemente un ataque de fuerza bruta para deducir el token en cuestión de horas, lo que podría llevar a una escalada de privilegios al acceder a cuentas de servicio sensibles.
Si tienes los verbos create
en el recurso certificatesigningrequests
(o al menos en certificatesigningrequests/nodeClient
). Puedes crear un nuevo CeSR de un nuevo nodo.
De acuerdo con la documentación, es posible aprobar automáticamente estas solicitudes, así que en ese caso no necesitas permisos adicionales. Si no, necesitarías poder aprobar la solicitud, lo que significa actualizar en certificatesigningrequests/approval
y approve
en signers
con resourceName <signerNameDomain>/<signerNamePath>
o <signerNameDomain>/*
Un ejemplo de un rol con todos los permisos requeridos es:
Así que, con el nuevo CSR de nodo aprobado, puedes abuse los permisos especiales de los nodos para steal secrets y escalate privileges.
En esta publicación y esta otra, la configuración de GKE K8s TLS Bootstrap está configurada con automatic signing y se abuse para generar credenciales de un nuevo nodo K8s y luego abuse esas credenciales para escalar privilegios robando secretos. Si tienes los privilegios mencionados podrías hacer lo mismo. Ten en cuenta que el primer ejemplo elude el error que impide que un nuevo nodo acceda a secretos dentro de contenedores porque un nodo solo puede acceder a los secretos de los contenedores montados en él.
La forma de eludir esto es simplemente crear credenciales de nodo para el nombre del nodo donde el contenedor con los secretos interesantes está montado (pero solo verifica cómo hacerlo en la primera publicación):
Los principales que pueden modificar configmaps
en el espacio de nombres kube-system en clústeres EKS (necesitan estar en AWS) pueden obtener privilegios de administrador del clúster al sobrescribir el configmap aws-auth.
Los verbos necesarios son update
y patch
, o create
si el configmap no fue creado:
Puedes usar aws-auth
para persistencia dando acceso a usuarios de otras cuentas.
Sin embargo, aws --profile other_account eks update-kubeconfig --name <cluster-name>
no funciona desde una cuenta diferente. Pero en realidad aws --profile other_account eks get-token --cluster-name arn:aws:eks:us-east-1:123456789098:cluster/Testing
funciona si pones el ARN del clúster en lugar de solo el nombre.
Para hacer que kubectl
funcione, solo asegúrate de configurar el kubeconfig de la víctima y en los argumentos de ejecución de aws agrega --profile other_account_role
para que kubectl use el perfil de la otra cuenta para obtener el token y contactar a AWS.
Hay 2 formas de asignar permisos de K8s a los principales de GCP. En cualquier caso, el principal también necesita el permiso container.clusters.get
para poder obtener credenciales para acceder al clúster, o necesitarás generar tu propio archivo de configuración de kubectl (sigue el siguiente enlace).
Al hablar con el punto final de la API de K8s, el token de autenticación de GCP será enviado. Luego, GCP, a través del punto final de la API de K8s, primero verificará si el principal (por correo electrónico) tiene algún acceso dentro del clúster, luego verificará si tiene algún acceso a través de GCP IAM. Si cualquiera de esos es verdadero, se le responderá. Si no, se dará un error sugiriendo otorgar permisos a través de GCP IAM.
Entonces, el primer método es usar GCP IAM, los permisos de K8s tienen sus permisos equivalentes de GCP IAM, y si el principal los tiene, podrá usarlos.
GCP - Container PrivescEl segundo método es asignar permisos de K8s dentro del clúster identificando al usuario por su correo electrónico (incluidas las cuentas de servicio de GCP).
Principales que pueden crear TokenRequests (serviceaccounts/token
) al hablar con el punto final de la API de K8s SAs (info de aquí).
Principales que pueden update
o patch
pods/ephemeralcontainers
pueden obtener ejecución de código en otros pods, y potencialmente salir a su nodo agregando un contenedor efímero con un securityContext privilegiado.
Principales con cualquiera de los verbos create
, update
o patch
sobre validatingwebhookconfigurations
o mutatingwebhookconfigurations
podrían ser capaces de crear uno de esos webhookconfigurations para poder escalar privilegios.
Para un mutatingwebhookconfigurations
ejemplo revisa esta sección de esta publicación.
Como puedes leer en la siguiente sección: Prevención de Escalación de Privilegios Incorporada, un principal no puede actualizar ni crear roles o clusterroles sin tener él mismo esos nuevos permisos. Excepto si tiene el verbo escalate
sobre roles
o clusterroles
.
Entonces puede actualizar/crear nuevos roles, clusterroles con mejores permisos que los que tiene.
Principales con acceso al subrecurso nodes/proxy
pueden ejecutar código en pods a través de la API de Kubelet (según esto). Más información sobre la autenticación de Kubelet en esta página:
Tienes un ejemplo de cómo obtener RCE hablando autorizado a una API de Kubelet aquí.
Principales que pueden eliminar pods (delete
verbo sobre pods
recurso), o desalojar pods (create
verbo sobre pods/eviction
recurso), o cambiar el estado de los pods (acceso a pods/status
) y pueden hacer que otros nodos no sean programables (acceso a nodes/status
) o eliminar nodos (delete
verbo sobre nodes
recurso) y tienen control sobre un pod, podrían robar pods de otros nodos para que sean ejecutados en el nodo comprometido y el atacante puede robar los tokens de esos pods.
Los principales que pueden modificar services/status
pueden establecer el campo status.loadBalancer.ingress.ip
para explotar el CVE-2020-8554 sin corregir y lanzar ataques MiTM contra el clúster. La mayoría de las mitigaciones para CVE-2020-8554 solo previenen servicios ExternalIP (según esto).
Los principales con permisos de update
o patch
sobre nodes/status
o pods/status
, podrían modificar etiquetas para afectar las restricciones de programación impuestas.
Kubernetes tiene un mecanismo incorporado para prevenir la escalación de privilegios.
Este sistema asegura que los usuarios no pueden elevar sus privilegios modificando roles o vinculaciones de roles. La aplicación de esta regla ocurre a nivel de API, proporcionando una salvaguarda incluso cuando el autorizador RBAC está inactivo.
La regla estipula que un usuario solo puede crear o actualizar un rol si posee todos los permisos que comprende el rol. Además, el alcance de los permisos existentes del usuario debe alinearse con el del rol que intenta crear o modificar: ya sea a nivel de clúster para ClusterRoles o confinado al mismo espacio de nombres (o a nivel de clúster) para Roles.
Hay una excepción a la regla anterior. Si un principal tiene el verbo escalate
sobre roles
o clusterroles
, puede aumentar los privilegios de roles y clusterroles incluso sin tener los permisos él mismo.
Aparentemente, esta técnica funcionaba antes, pero según mis pruebas, ya no está funcionando por la misma razón explicada en la sección anterior. No puedes crear/modificar un rolebinding para darte a ti mismo o a una SA diferente algunos privilegios si no los tienes ya.
El privilegio de crear Rolebindings permite a un usuario vincular roles a una cuenta de servicio. Este privilegio puede llevar potencialmente a la escalación de privilegios porque permite al usuario vincular privilegios de administrador a una cuenta de servicio comprometida.
Por defecto, no hay ninguna encriptación en la comunicación entre pods. Autenticación mutua, bidireccional, pod a pod.
Crea tu .yaml
Edita tu .yaml y añade las líneas sin comentar:
Ver los registros del proxy:
Más información en: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
Un controlador de admisión intercepta las solicitudes al servidor API de Kubernetes antes de la persistencia del objeto, pero después de que la solicitud ha sido autenticada y autorizada.
Si un atacante logra inyectar un Controlador de Admisión de Mutación, podrá modificar solicitudes ya autenticadas. Esto podría permitir un posible privesc y, más comúnmente, persistir en el clúster.
Ejemplo de https://blog.rewanthtammana.com/creating-malicious-admission-controllers:
Verifica el estado para ver si está listo:
Luego despliega un nuevo pod:
Cuando puedes ver el error ErrImagePull
, verifica el nombre de la imagen con cualquiera de las consultas:
Como se puede ver en la imagen anterior, intentamos ejecutar la imagen nginx
, pero la imagen final ejecutada es rewanthtammana/malicious-image
. ¿Qué acaba de pasar!?
El script ./deploy.sh
establece un controlador de admisión de webhook mutante, que modifica las solicitudes a la API de Kubernetes según lo especificado en sus líneas de configuración, influyendo en los resultados observados:
El fragmento anterior reemplaza la primera imagen del contenedor en cada pod con rewanthtammana/malicious-image
.
Pods y Cuentas de Servicio: Por defecto, los pods montan un token de cuenta de servicio. Para mejorar la seguridad, Kubernetes permite deshabilitar esta función de automontaje.
Cómo Aplicar: Establecer automountServiceAccountToken: false
en la configuración de cuentas de servicio o pods a partir de la versión 1.6 de Kubernetes.
Inclusión Selectiva: Asegúrese de que solo los usuarios necesarios estén incluidos en RoleBindings o ClusterRoleBindings. Audite regularmente y elimine usuarios irrelevantes para mantener una seguridad estricta.
Roles vs. ClusterRoles: Prefiera usar Roles y RoleBindings para permisos específicos de namespace en lugar de ClusterRoles y ClusterRoleBindings, que se aplican a nivel de clúster. Este enfoque ofrece un control más fino y limita el alcance de los permisos.
Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE) Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE)