Ataque mi propio servidor: el perimetro estaba bien y aun asi era root
El escaneo desde internet salia impecable. Lo que estaba mal solo se ve preguntando: si alguien ya esta dentro, hasta donde llega. Cinco hallazgos y por que ninguno era un exploit exotico.
Le pedí a un asistente que atacara mi propio servidor como si fuera un pentester y me dijera qué encontraba. Esperaba una lista de nimiedades sobre cabeceras HTTP. Lo primero que salió fue que cualquiera con acceso a mi laptop era root en el servidor, sin saber ninguna contraseña.
El perímetro estaba bien, y eso me confió
Lo primero que revisé fue lo que todo el mundo revisa. Desde internet solo respondían 22, 80 y 443. Login de root deshabilitado, autenticación por contraseña deshabilitada, solo llaves. SELinux en enforcing, firewalld activo, fail2ban baneando. Cero actualizaciones de seguridad pendientes.
Todo eso está bien y no servía de nada contra lo que venía.
El grupo docker es root, y no hay letra chica
Mi usuario estaba en el grupo docker, como el de casi todos. Es lo cómodo: no tener que escribir sudo cuarenta veces al día.
El problema es que el demonio de Docker corre como root, y quien puede hablarle puede pedirle cosas como esta:
docker run --rm -v /:/anfitrion alpine cat /anfitrion/etc/shadow
Montas la raíz del servidor dentro de un contenedor y lees lo que quieras. Escribes, también. No hay contraseña que pedir porque no estás usando sudo: estás usando Docker, que ya es root.
Es decir: mi sudo con contraseña no protegía nada. Estaba puesto, funcionaba, y era decorativo.
La cadena completa
Ahí es donde se juntó con la otra pieza. Mi llave SSH no tenía passphrase. Un archivo en mi carpeta de usuario en Windows.
Encadenado queda así: alguien copia ese archivo — un USB, un respaldo mal guardado, cualquier programa que corra con mis permisos — y entra por SSH sin saber nada más. Ya dentro, un docker run lo hace root. Todas mis defensas estaban después de ese punto.
Lo arreglé por el lado barato: le puse passphrase a la llave. Sacarme del grupo docker sería lo correcto, pero administro muchos stacks al día y el costo de escribir sudo en cada comando era alto. Elegí a conciencia, que es distinto de no haberlo pensado.
Los .env que cualquiera podía leer
Seis de ocho aplicaciones tenían su .env en 644. Lectura para todos.
$ ls -l ~/apps/*/.env
-rw-r--r-- 1 manuel manuel ... # cualquier usuario del sistema lo lee
Adentro: contraseñas de base de datos, tokens de WhatsApp, llaves de API, tokens de ingesta. En un servidor de un solo usuario suena inofensivo — hasta que recuerdas que cualquier proceso que corra con otro usuario, incluido uno que se escape de un contenedor mal configurado, también los lee.
chmod 600 ~/apps/*/.env
Un comando. Tres semanas expuestos por no haberlo escrito.
La configuración de SSH que funcionaba por accidente
Este fue el hallazgo que más me hizo pensar. El sshd_config principal decía PermitRootLogin yes. El archivo de cloud-init decía PasswordAuthentication yes. Y sin embargo root no entraba y las contraseñas no servían.
¿Por qué? Porque los archivos de sshd_config.d/ se leen en orden alfabético, y el mío se llamaba 00-hardening.conf. Ganaba por el nombre.
Funcionaba, sí. Pero el día que alguien renombre ese archivo, o agregue uno que empiece con un guion bajo, root vuelve a entrar por SSH y nadie se entera. Una configuración que depende del orden alfabético no está endurecida: está teniendo suerte.
Lo que me llevo
Ninguno de estos hallazgos era un exploit exótico. Los cinco eran decisiones razonables de cuando las tomé, que envejecieron mal o que nunca volví a mirar.
Y todos comparten algo: el servidor se veía perfecto desde fuera. Un escaneo de puertos desde internet salía impecable. Lo que estaba mal solo se ve preguntando "y si alguien ya está dentro, ¿qué tan lejos llega?".
Esa es la pregunta que no me estaba haciendo.