--- title: "Cómo detectar si tu servidor Linux está bajo ataque" description: "Revisa conexiones, intentos de login SSH, procesos, tareas programadas y logs en Ubuntu 24.04 para saber si tu servidor está bajo ataque y cómo contenerlo." category: "Guía de Solución de Problemas" language: es source: https://cubepath.com/es/docs/guía-de-solución-de-problemas/detectar-servidor-bajo-ataque updated: 2026-09-25 --- # Cómo detectar si tu servidor Linux está bajo ataque Un servidor lento, con la CPU al 100 % o con miles de conexiones abiertas puede estar sufriendo un ataque, o puede que ya esté comprometido. En esta guía seguirás un procedimiento ordenado para averiguarlo en Ubuntu 24.04: primero la red y los accesos, después los procesos, la persistencia y los ficheros, y por último la contención y la prevención. Todos los comandos son de solo lectura hasta llegar al paso de contención. ## Requisitos previos - Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath. En Debian 12 los comandos son los mismos. - Un usuario no root con privilegios `sudo`. - Saber qué es "normal" en tu servidor (servicios, puertos y usuarios esperados). Sin esa referencia es difícil distinguir un ataque de un pico de tráfico legítimo. > Importante: si sospechas que un atacante tiene acceso root, no confíes al 100 % en las herramientas del propio sistema, ya que pueden haber sido sustituidas. Recoge evidencias, aísla el servidor y valora reinstalarlo desde una copia de seguridad limpia. ## Paso 1: Instalar las herramientas de diagnóstico La mayoría de comandos de esta guía vienen con Ubuntu, pero algunos (tráfico por conexión, estadísticas históricas, captura de paquetes) necesitan paquetes adicionales: ```bash sudo apt update sudo apt install sysstat iftop tcpdump lsof debsums ``` Averigua también el nombre de tu interfaz de red pública, porque lo usarás en varios comandos: ```bash ip -br addr ``` ```output lo UNKNOWN 127.0.0.1/8 ::1/128 eth0 UP 203.0.113.25/24 2001:db8::25/64 ``` En los ejemplos se usa `eth0`. Sustitúyelo por el nombre que veas (por ejemplo `ens18`). ## Paso 2: Hacer una evaluación rápida Antes de profundizar, estos comandos te dan una foto del estado del servidor en menos de un minuto. Carga del sistema y usuarios conectados: ```bash uptime w ``` ```output 10:42:01 up 12 days, 3:10, 1 user, load average: 7.85, 6.20, 3.11 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT admin pts/0 198.51.100.7 10:40 0.00s 0.03s 0.00s w ``` Resumen de sockets y procesos que más CPU y memoria consumen: ```bash ss -s ps -eo pid,user,%cpu,%mem,etime,cmd --sort=-%cpu | head -10 ``` Fíjate en tres cosas: una carga muy superior al número de núcleos (`nproc`), un número de conexiones TCP muy por encima de lo habitual y procesos que no reconoces o que se ejecutan con un usuario inesperado. Cada una te lleva a uno de los pasos siguientes. ## Paso 3: Analizar las conexiones de red ### Conexiones por IP de origen Un ataque de denegación de servicio a nivel de aplicación suele verse como muchas conexiones desde pocas IP. Este comando cuenta las conexiones establecidas por IP remota: ```bash ss -Htn state established | awk '{print $4}' | sed 's/:[0-9]*$//' | sort | uniq -c | sort -rn | head -15 ``` ```output 842 198.51.100.44 611 198.51.100.45 12 203.0.113.80 3 192.0.2.10 ``` Cientos de conexiones desde una sola IP hacia un servidor web pequeño no son normales. Si las conexiones vienen de miles de IP distintas con pocas conexiones cada una, se trata de un ataque distribuido y bloquear IP una a una no servirá. ### Inundación SYN En un ataque SYN flood el servidor acumula conexiones a medio abrir en estado `SYN-RECV`: ```bash ss -Htn state syn-recv | wc -l ``` Unas pocas son normales; cientos o miles de forma sostenida indican un ataque. Comprueba que las SYN cookies están activas (en Ubuntu lo están por defecto), porque permiten seguir aceptando conexiones legítimas durante la inundación: ```bash sysctl net.ipv4.tcp_syncookies ``` ```output net.ipv4.tcp_syncookies = 1 ``` ### Ancho de banda y paquetes Para ver en tiempo real qué conexiones consumen más ancho de banda, usa `iftop` sin resolución de nombres (`-n`) y mostrando puertos (`-P`). Pulsa `q` para salir: ```bash sudo iftop -i eth0 -nP ``` Para ver el tráfico por segundo de la interfaz, usa `sar` (del paquete `sysstat`), que muestra 5 muestras de 1 segundo: ```bash sar -n DEV 1 5 ``` Si sospechas de un SYN flood, captura 2000 paquetes SYN y cuenta sus orígenes con `tcpdump`: ```bash sudo tcpdump -ni eth0 -c 2000 'tcp[tcpflags] & tcp-syn != 0 and tcp[tcpflags] & tcp-ack == 0' 2>/dev/null \ | awk '{print $3}' | cut -d. -f1-4 | sort | uniq -c | sort -rn | head -10 ``` Si el volumen de tráfico satura el enlace del servidor, ninguna regla local lo va a solucionar, porque los paquetes ya han consumido el ancho de banda al llegar. En ese caso la mitigación tiene que hacerse antes de que el tráfico llegue a tu servidor: contacta con el soporte de CubePath con las IP de destino, los puertos y la hora de inicio del ataque. ### Tráfico saliente Tu servidor también puede ser el origen del ataque si está comprometido y forma parte de una botnet. Revisa las conexiones salientes y qué proceso las abre: ```bash sudo ss -tunp state established | grep -v -E ':22 |:80 |:443 ' | head -30 ``` Conexiones a puertos como 3333, 4444 o 14444 suelen corresponder a pools de minería de criptomonedas. ## Paso 4: Detectar ataques de fuerza bruta contra SSH Los intentos de login fallidos se registran en `/var/log/auth.log`. Este comando cuenta los intentos fallidos por IP de origen, incluidos los de usuarios que no existen: ```bash sudo grep -hE 'Failed password|Invalid user' /var/log/auth.log \ | grep -oE 'from [0-9a-fA-F.:]+' | awk '{print $2}' | sort | uniq -c | sort -rn | head -10 ``` ```output 1893 198.51.100.23 744 203.0.113.199 35 192.0.2.61 ``` Para ver cuántos intentos ha habido en la última hora, usa el journal del servicio SSH (en Ubuntu 24.04 la unidad se llama `ssh`): ```bash sudo journalctl -u ssh --since "1 hour ago" | grep -c 'Failed password' ``` Qué usuarios intentan adivinar: ```bash sudo grep -h 'Invalid user' /var/log/auth.log | awk '{for (i=1;i<=NF;i++) if ($i=="user") print $(i+1)}' | sort | uniq -c | sort -rn | head ``` Los intentos fallidos en sí no son un problema si solo permites autenticación por clave. Lo que de verdad importa es si alguno ha tenido éxito. Revisa los inicios de sesión aceptados y el historial de accesos: ```bash sudo grep 'Accepted' /var/log/auth.log | tail -20 last -n 20 sudo lastb -n 20 ``` Cualquier `Accepted password` o `Accepted publickey` desde una IP que no reconoces es una señal de compromiso. Comprueba también que no se han añadido claves SSH desconocidas: ```bash sudo find /root /home -name authorized_keys -exec ls -l {} \; -exec cat {} \; ``` ## Paso 5: Buscar procesos sospechosos Un servidor comprometido casi siempre tiene algún proceso ajeno: un minero, un bot de DDoS o una shell inversa. Empieza por los procesos que escuchan en puertos: ```bash sudo ss -tulpn ``` Cada puerto debe corresponder a un servicio que conoces (`sshd`, `nginx`, `mysqld`...). Después busca procesos cuyo binario se ejecuta desde directorios temporales o ha sido borrado del disco, dos técnicas habituales del malware: ```bash sudo ls -l /proc/[0-9]*/exe 2>/dev/null | grep -E '\(deleted\)|/tmp/|/var/tmp/|/dev/shm/' ``` ```output lrwxrwxrwx 1 www-data www-data 0 Sep 25 10:12 /proc/48213/exe -> /tmp/.x/kworkerd (deleted) ``` Si encuentras un PID sospechoso, examínalo antes de matarlo. Sustituye `PID` por el número del proceso: ```bash ps -fp PID sudo ls -l /proc/PID/exe /proc/PID/cwd sudo tr '\0' ' ' < /proc/PID/cmdline; echo sudo lsof -nP -p PID -i ``` Estas son señales típicas de un proceso malicioso: - Nombre que imita un hilo del kernel (`kworkerd`, `[kthreadd]`) pero con un binario en disco. - Se ejecuta como `www-data` u otro usuario de servicio y no pertenece a ese servicio. - Consume casi el 100 % de la CPU de forma constante (típico de los mineros como `xmrig`). - Tiene conexiones abiertas hacia IP externas desconocidas. ## Paso 6: Revisar los mecanismos de persistencia Tras entrar, los atacantes suelen asegurarse de volver aunque reinicies el servidor o mates sus procesos. Revisa las tareas cron de todos los usuarios y del sistema: ```bash sudo ls -la /var/spool/cron/crontabs/ sudo cat /var/spool/cron/crontabs/* 2>/dev/null sudo cat /etc/crontab /etc/cron.d/* ``` Busca líneas que descarguen algo con `curl` o `wget`, que ejecuten ficheros de `/tmp` o que contengan cadenas en base64. Revisa los temporizadores y servicios de systemd, y en especial las unidades modificadas en los últimos días: ```bash systemctl list-timers --all sudo find /etc/systemd/system /usr/lib/systemd/system -type f -mtime -7 -ls ``` Comprueba que no hay usuarios nuevos con UID 0 y que no existe `/etc/ld.so.preload`, un fichero que se usa a menudo para ocultar procesos: ```bash awk -F: '$3 == 0 {print $1}' /etc/passwd ls -l /etc/ld.so.preload ``` ```output root ls: cannot access '/etc/ld.so.preload': No such file or directory ``` Solo debe aparecer `root`, y lo normal es que `/etc/ld.so.preload` no exista. ## Paso 7: Comprobar la integridad de los ficheros ### Binarios del sistema `debsums` compara los ficheros instalados con las sumas MD5 de los paquetes Debian. La opción `-c` muestra solo los ficheros que han cambiado: ```bash sudo debsums -c ``` Una salida vacía es la situación esperada. Si aparece un binario como `/usr/bin/ps` o `/usr/bin/ss`, el sistema está comprometido. Ten en cuenta que los ficheros de configuración de `/etc` que tú has editado no se comprueban con `-c`, así que no generarán ruido. ### Directorios temporales y web Revisa los ficheros recientes en los directorios con permiso de escritura para todos, donde el malware suele dejar sus binarios: ```bash sudo find /tmp /var/tmp /dev/shm -type f -mtime -3 -ls ``` Si alojas aplicaciones web, busca ficheros PHP modificados en la última semana y funciones típicas de las web shells: ```bash sudo find /var/www -type f -name '*.php' -mtime -7 -ls sudo grep -rlE 'eval\s*\(\s*(base64_decode|gzinflate|str_rot13)' /var/www --include='*.php' ``` Un fichero PHP dentro de un directorio de subidas (`uploads/`) casi nunca es legítimo. ### Escáneres de rootkits `rkhunter` y `chkrootkit` buscan firmas de rootkits conocidos y configuraciones anómalas: ```bash sudo apt install rkhunter chkrootkit sudo rkhunter --check --skip-keypress --report-warnings-only sudo chkrootkit -q ``` Ambos generan falsos positivos (por ejemplo, avisos sobre scripts en `/usr/bin` o ficheros ocultos legítimos). Úsalos como pista para investigar, no como veredicto. ## Paso 8: Analizar los logs del servidor web Muchos ataques se dirigen a la aplicación y no al sistema. Con el formato de log por defecto de Nginx (`combined`), estas consultas muestran las IP con más peticiones y las peticiones por minuto: ```bash sudo awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10 sudo awk '{print $4}' /var/log/nginx/access.log | cut -d: -f1-3 | uniq -c | tail -10 ``` ```output 4210 [25/Sep/2026:10:38 4388 [25/Sep/2026:10:39 9876 [25/Sep/2026:10:40 ``` Un salto brusco de peticiones por minuto marca el inicio del ataque. Para ver qué URL se atacan y con qué códigos responde el servidor: ```bash sudo awk '{print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10 sudo awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn ``` Miles de peticiones a `/wp-login.php` o `/xmlrpc.php` indican fuerza bruta contra WordPress; muchas respuestas 404 a rutas como `/.env` o `/.git/config` indican un escaneo automatizado. Con Apache, los logs están en `/var/log/apache2/access.log` y usan el mismo formato. ## Paso 9: Contener el ataque Cuando tengas claro qué ocurre, actúa por este orden. ### Recoger evidencias Guarda el estado del sistema antes de cambiar nada, porque matar procesos o reiniciar borra información útil: ```bash INCIDENT_DIR="/root/incident-$(date +%Y%m%d-%H%M%S)" sudo mkdir -p "$INCIDENT_DIR" ps auxf | sudo tee "$INCIDENT_DIR/processes.txt" > /dev/null sudo ss -tunap | sudo tee "$INCIDENT_DIR/connections.txt" > /dev/null last -F | sudo tee "$INCIDENT_DIR/logins.txt" > /dev/null sudo cp /var/log/auth.log /var/log/syslog "$INCIDENT_DIR/" ``` Si hay un proceso malicioso, copia también su binario, que sigue accesible desde `/proc` aunque se haya borrado del disco: ```bash sudo cp /proc/PID/exe "$INCIDENT_DIR/malware.bin" ``` ### Bloquear IP atacantes Con UFW, inserta la regla de denegación en la primera posición para que se evalúe antes que las reglas `allow`: ```bash sudo ufw insert 1 deny from 198.51.100.23 sudo ufw status numbered ``` Para bloquear una red completa, usa la notación CIDR (`198.51.100.0/24`). ### Detener procesos y cuentas comprometidas Mata el proceso y bloquea la cuenta que lo lanzó, cerrando además todas sus sesiones (sustituye `your_user` por el usuario afectado): ```bash sudo kill -9 PID sudo usermod -L -e 1 your_user sudo pkill -KILL -u your_user ``` Elimina después las entradas de cron, unidades de systemd y claves SSH que encontraste en los pasos 4 y 6. Si el atacante obtuvo root o `debsums` detectó binarios modificados, no intentes limpiar el sistema: restaura desde una copia de seguridad anterior al compromiso o reinstala, y cambia todas las credenciales. ## Paso 10: Prevenir nuevos ataques ### Bloqueo automático con Fail2ban Fail2ban lee los logs y bloquea temporalmente las IP que fallan demasiadas veces. En Ubuntu 24.04 conviene que lea directamente del journal, para lo que necesita `python3-systemd`: ```bash sudo apt install fail2ban python3-systemd ``` Crea la configuración local de la jaula de SSH: ```bash sudo nano /etc/fail2ban/jail.local ``` ```ini [sshd] enabled = true backend = systemd maxretry = 5 findtime = 10m bantime = 1h ``` Activa el servicio, reinícialo para que cargue la nueva configuración y comprueba que la jaula está funcionando: ```bash sudo systemctl enable fail2ban sudo systemctl restart fail2ban sudo fail2ban-client status sshd ``` ```output Status for the jail: sshd |- Filter | |- Currently failed: 3 | |- Total failed: 27 | `- Journal matches: _SYSTEMD_UNIT=sshd.service + _COMM=sshd `- Actions |- Currently banned: 2 |- Total banned: 2 `- Banned IP list: 198.51.100.23 203.0.113.199 ``` ### Endurecer SSH La medida más eficaz contra la fuerza bruta es desactivar las contraseñas. Asegúrate primero de que puedes entrar con tu clave SSH, y después crea un fichero de configuración adicional: ```bash sudo nano /etc/ssh/sshd_config.d/10-hardening.conf ``` ```text PasswordAuthentication no PermitRootLogin no ``` Valida la sintaxis y recarga el servicio: ```bash sudo sshd -t sudo systemctl reload ssh ``` ### Guardar histórico de métricas Para poder comparar la próxima vez con lo "normal", activa la recogida periódica de `sysstat`. Edita `/etc/default/sysstat` y cambia `ENABLED="false"` por `ENABLED="true"`, y después: ```bash sudo systemctl enable --now sysstat ``` A partir de ahí, `sar -n DEV` y `sar -q` muestran el tráfico y la carga de todo el día. ## Solución de problemas - **`/var/log/auth.log` no existe**: el sistema no tiene `rsyslog`. Usa `sudo journalctl -u ssh` en su lugar, o instala `rsyslog`. - **`ss` muestra direcciones como `[::ffff:198.51.100.44]`**: son conexiones IPv4 aceptadas por un socket IPv6. Es normal y el conteo sigue siendo válido. - **Fail2ban no arranca con el error `Have not found any log file for sshd jail`**: falta `backend = systemd` en la jaula o no está instalado `python3-systemd`. - **Te has bloqueado a ti mismo con UFW**: accede por la consola del servidor y elimina la regla con `sudo ufw delete NUMERO`, usando el número que muestra `sudo ufw status numbered`. ## Conclusión Ya tienes un procedimiento para diagnosticar un posible ataque: identificar el origen del tráfico y de los accesos, localizar procesos y mecanismos de persistencia ajenos, verificar la integridad del sistema y contener el problema sin perder evidencias. Como siguientes pasos, configura copias de seguridad automáticas que te permitan restaurar un sistema limpio, limita el acceso a SSH por IP con UFW y pon en marcha una monitorización que te avise de picos de conexiones o de CPU antes de que los notes tú.