lab-linux-caps — capabilities y confinamiento por syscalls ========================================================== ESTADO: LABORATORIO LOCAL Target: contenedores caps-* (sin puertos publicados) Autorizacion: sistema local creado por ti para entrenamiento. Este laboratorio es tuyo y corre en tu maquina, aislado y sin salida a internet. Todo lo que aqui se practica se practica aqui dentro. Que monta --------- El MISMO programa (un socket de Python que intenta escuchar en el puerto 80, que es privilegiado por ser <1024) en cuatro servicios con distinto nivel de privilegio: como-root corre como root -> puede con el 80 (demasiado poder) sin-root usuario 1000, sin capabilities -> falla en el 80 con-cap usuario 1000 + solo CAP_NET_BIND_SERVICE -> escucha con-seccomp un perfil seccomp que bloquea la familia chmod Ningun servicio publica puertos: el bind ocurre dentro del contenedor y se lee en los logs. El perfil de seccomp esta en seccomp-sin-chmod.json, en este mismo directorio. Nota: se usa la imagen python:3.12-slim porque trae un interprete capaz de abrir un socket sin instalar nada. Si no la tienes en cache, 'docker compose up' la descargara una vez; a partir de ahi el laboratorio funciona sin red. Comandos -------- docker compose up -d levantar los cuatro docker compose logs como-root es root: escucha en el 80 docker compose logs sin-root no es root: PermissionError docker compose logs con-cap capability justa: escucha docker compose logs con-seccomp chmod bloqueado por seccomp docker compose down -v destruir Que observar (construir -> atacar -> observar -> defender -> verificar) ---------------------------------------------------------------------- # 'como-root' y 'con-cap' imprimen: OK: escuchando en el puerto 80 # 'sin-root' imprime un PermissionError al hacer bind: # PermissionError: [Errno 13] Permission denied # # La leccion: 'con-cap' hace lo mismo que 'como-root' SIN ser root. # Le basta CAP_NET_BIND_SERVICE. No necesita ninguno de los otros # poderes de root, asi que un fallo en ese proceso no los tiene. # # 'con-seccomp' intenta chmod y el kernel responde # Operation not permitted # aunque el proceso, por permisos, podria. seccomp filtra la # syscall antes de que llegue a ejecutarse. El experimento que cierra la idea --------------------------------- Compara con-cap y como-root: ambos escuchan en el 80, pero uno tiene todo el poder de root y el otro solo el permiso de reservar un puerto bajo. Si un atacante toma el proceso 'como-root', tiene root. Si toma 'con-cap', solo puede abrir puertos bajos: nada de leer /etc/shadow, montar discos ni cargar modulos. Ese recorte es el objetivo. Como se endurece un compose real -------------------------------- cap_drop: ["ALL"] quita todas las capabilities cap_add: ["NET_BIND_SERVICE"] devuelve solo la que hace falta user: "1000:1000" no correr como root dentro security_opt: [seccomp=perfil] filtra las syscalls peligrosas read_only: true (extra) raiz de solo lectura Si algo falla ------------- con-cap tambien falla en el 80 tu Docker puede filtrar NET_BIND_SERVICE por defecto en userns-remap; revisa la config la imagen no descarga necesitas red la PRIMERA vez para traer python:3.12-slim; luego no Cuando termines, siempre: docker compose down -v