Comprobar mi conexión

Guías · Investigar una IP

Intentos de acceso SSH en mis logs: ¿me están hackeando?

Entras en tu servidor, echas un vistazo a /var/log/auth.log y te encuentras miles de líneas de Failed password for root desde direcciones de medio mundo. Parece un asedio. Es sobre todo meteorología.

El puerto 22 es la puerta más previsible de internet, así que los scripts automáticos llaman sin parar, en todas partes, a todas horas. No van a por ti. Prueban una lista corta de usuarios (root, admin, oracle, ubuntu, test) con las contraseñas más elegidas y siguen su camino. Un intento fallido no les cuesta nada y a ti solo te dice que SSH es accesible. Tu tarea es responder a dos preguntas: ¿algún intento salió bien?, ¿podría salir bien alguno en el futuro?

Dónde mirar

En Debian y Ubuntu con rsyslog, SSH escribe en /var/log/auth.log. En Red Hat, Fedora, Rocky y Alma es /var/log/secure. Las instalaciones recientes de Debian pueden no escribir ese archivo y guardarlo todo en el journal de systemd. El journal funciona allí donde haya systemd; el servicio se llama ssh en Debian y Ubuntu y sshd en la familia Red Hat:

sudo journalctl -u ssh --since today        # Debian, Ubuntu
sudo journalctl -u sshd --since "1 hour ago" # Red Hat, Fedora, Rocky, Alma

Tres recuentos cuentan casi toda la historia:

sudo grep -c "Failed password" /var/log/auth.log
sudo grep "Accepted" /var/log/auth.log
sudo grep "Failed password" /var/log/auth.log | grep -oE "from [0-9.]+" | sort | uniq -c | sort -rn | head

El primero mide el ruido. El segundo es el que importa: cada acceso correcto. El tercero muestra qué direcciones insisten más.

Un ejemplo real: una noche en un VPS pequeño

Doce líneas de un servidor llamado web1. Las dos direcciones de personas (el atacante que prueba con admin y el dueño que entra a la mañana siguiente) son direcciones de documentación, así que aquí no aparece ninguna persona real. Las demás son infraestructura pública.

El log de ejemplo (12 líneas)
Nov  6 03:12:41 web1 sshd[24811]: Invalid user admin from 203.0.113.77 port 51022
Nov  6 03:12:43 web1 sshd[24811]: Failed password for invalid user admin from 203.0.113.77 port 51022 ssh2
Nov  6 03:12:44 web1 sshd[24811]: Connection closed by invalid user admin 203.0.113.77 port 51022 [preauth]
Nov  6 03:12:50 web1 sshd[24815]: Failed password for root from 185.220.101.1 port 40122 ssh2
Nov  6 03:12:53 web1 sshd[24815]: Failed password for root from 185.220.101.1 port 40122 ssh2
Nov  6 03:12:55 web1 sshd[24815]: Disconnected from authenticating user root 185.220.101.1 port 40122 [preauth]
Nov  6 03:14:02 web1 sshd[24830]: Invalid user oracle from 3.5.140.1 port 33412
Nov  6 03:14:04 web1 sshd[24830]: Failed password for invalid user oracle from 3.5.140.1 port 33412 ssh2
Nov  6 03:14:04 web1 sshd[24830]: Received disconnect from 3.5.140.1 port 33412:11: Bye Bye [preauth]
Nov  6 03:20:17 web1 sshd[24902]: Connection closed by 167.94.138.35 port 49212 [preauth]
Nov  6 08:41:09 web1 sshd[25510]: Accepted publickey for deploy from 198.51.100.20 port 52814 ssh2: ED25519 SHA256:k3X0exampleexampleexampleexampleexampleexa
Nov  6 08:41:09 web1 sshd[25510]: pam_unix(sshd:session): session opened for user deploy(uid=1001) by (uid=0)

Pasadas por el comprobador de logs de iplover, las cinco direcciones quedan así:

Dirección IPLíneasCategoríaTipo de red
203.0.113.773Privadas o reservadasDirección privada o reservada (no comprobada)
185.220.101.13Nodos de salida de TorNodo de salida de Tor
3.5.140.13Nube y hostingHosting, nube o centro de datos
167.94.138.351Escáneres de internetNo identificado
198.51.100.201Privadas o reservadasDirección privada o reservada (no comprobada)

(Las dos direcciones de documentación salen como reservadas; en tu log se comprobarían las direcciones reales.) Ahora lee las líneas, porque las categorías solo dicen quién llamó, no si la puerta se abrió.

Veredicto: un solo acceso aceptado, y es del dueño. No ha entrado nadie. Pero root todavía acepta contraseñas, así que los intentos de la cuarta línea podrían salir bien algún día si la contraseña de root es débil. Eso es lo que hay que arreglar.

¿Ha entrado alguien de verdad?

Revisa cada línea Accepted. En cada una pregúntate: ¿es mi usuario, mi clave o contraseña, y una dirección que reconozco (casa, oficina, VPN)? Luego compáralo con los registros de acceso:

last -a | head -20     # últimos accesos correctos, con la dirección remota
sudo lastb | head -20  # últimos accesos fallidos (en sistemas que los guardan)
who                     # quién está conectado ahora mismo

Algunas distribuciones recientes han sustituido last y lastb por otras herramientas; si no están, el journal y auth.log tienen la misma información.

Una línea Accepted password o Accepted publickey que no sabes explicar es el único resultado que lo cambia todo. En ese caso, da la cuenta por comprometida:

Si ves esto, haz esto

Lo que vesQué significaQué hacer
Invalid user … con nombres que no tienesIntentos que no pueden funcionarNada urgente. Desaparecen cuando quitas las contraseñas.
Failed password for root o para otra cuenta realIntentos contra una cuenta que existeDesactiva el acceso con contraseña (más abajo), o al menos el de root.
Connection closed by … [preauth] sin contraseñas probadasUn escáner leyendo tu banner de SSHNada.
Miles de fallos al día desde pocas direccionesBots insistentesInstala fail2ban, o permite SSH solo desde tus direcciones.
Líneas Accepted … que son todas tuyasNo ha entrado nadie másNada, aparte de reforzar la configuración.
Accepted … desde una dirección o un usuario que no sabes explicarProbable intrusiónSigue los pasos de arriba, empezando por authorized_keys.

Haz que los intentos no sirvan: solo claves

Una contraseña se puede adivinar; una clave SSH, en la práctica, no. Cuando solo se aceptan claves, los bots pueden seguir probando para siempre.

Primero crea una clave en tu ordenador y cópiala al servidor. macOS y Linux traen el cliente OpenSSH. En Windows es una característica opcional, a menudo ya instalada; si ssh no se reconoce, la guía de Microsoft Introducción a OpenSSH para Windows explica cómo añadirlo:

ssh-keygen -t ed25519
ssh-copy-id tu@tu-servidor     # en Windows, pega ~/.ssh/id_ed25519.pub en ~/.ssh/authorized_keys del servidor

Después, en el servidor, pon esto en /etc/ssh/sshd_config:

PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin prohibit-password

prohibit-password deja entrar a root solo con clave; usa no para dejar a root fuera de SSH del todo. Antes de reiniciar, comprueba qué va a usar SSH de verdad. También se leen los archivos de /etc/ssh/sshd_config.d/, y algunas imágenes en la nube traen uno que vuelve a activar las contraseñas. En la mayoría de opciones gana el primer valor que lee sshd:

sudo sshd -T | grep -Ei "passwordauthentication|kbdinteractive|permitrootlogin"

Reinicia SSH (sudo systemctl restart ssh, o sshd en la familia Red Hat) y deja abierta tu sesión actual mientras pruebas un acceso nuevo en otra ventana. Si el nuevo acceso falla, todavía puedes arreglarlo desde la sesión antigua.

Reduce el ruido: fail2ban y cortafuegos

Las claves hacen inofensivos los intentos. fail2ban hace legible el log: vigila los fallos repetidos y bloquea esas direcciones un tiempo en el cortafuegos. En Debian y Ubuntu, sudo apt install fail2ban, y luego crea /etc/fail2ban/jail.local:

[sshd]
enabled  = true
maxretry = 5
findtime = 10m
bantime  = 1h
# Sin /var/log/auth.log (Debian recientes), lee el journal:
# backend = systemd

Reinícialo con sudo systemctl restart fail2ban y compruébalo con sudo fail2ban-client status sshd.

Si solo tú necesitas SSH, el mejor filtro de ruido es una regla de cortafuegos que permita el puerto 22 solo desde tus direcciones, o una VPN delante del servidor. Mover SSH a otro puerto reduce mucho el ruido, pero es camuflaje, no protección: un escáner lo encontrará igualmente.

Lo que las direcciones no pueden decirte

Las direcciones de auth.log son el origen de las conexiones: a menudo un nodo de Tor, un servidor en la nube alquilado o el ordenador secuestrado de otra persona. No identifican a nadie, y bloquearlas una a una no da abasto. Denunciar ataques insistentes al contacto de abusos de la red (lo muestra la búsqueda de IP) tiene sentido para un servidor en la nube que te machaca durante días; por unos pocos accesos fallidos no merece la pena.

Fuentes

Documentos oficiales que usamos para comprobar los datos de esta guía.