Una auditoría de seguridad manual consiste en recorrer, de forma ordenada, los puntos por los que un servidor suele quedar expuesto: paquetes sin actualizar, cuentas sobrantes, SSH permisivo, puertos abiertos sin motivo, permisos incorrectos o registros que nadie revisa. En esta guía tienes una lista de verificación para Ubuntu 24.04 en la que cada punto va acompañado del comando que lo comprueba, del resultado esperado y de cómo corregirlo. Al final guardarás las evidencias en un directorio fechado para poder comparar auditorías futuras.

Todos los comandos son de solo lectura salvo los que aparecen explícitamente como corrección.

Requisitos previos

  • Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath. Casi todo sirve en Debian 12; las diferencias para Rocky Linux 9 se indican donde importan.
  • Un usuario no root con privilegios sudo.
  • Una segunda sesión SSH abierta antes de modificar SSH o el firewall, para no quedarte fuera.

Paso 1: Preparar el directorio de evidencias

Guardar la salida de cada comprobación te permite demostrar qué revisaste y comparar con la siguiente auditoría. Crea un directorio protegido con la fecha del día:

AUDIT_DIR="$HOME/auditoria-$(date +%F)"
mkdir -p "$AUDIT_DIR"
chmod 700 "$AUDIT_DIR"

A lo largo de la guía puedes añadir | tee "$AUDIT_DIR/nombre.txt" a cualquier comando para guardar su salida. Empieza por la información básica del sistema:

hostnamectl | tee "$AUDIT_DIR/sistema.txt"
uname -r | tee -a "$AUDIT_DIR/sistema.txt"
 Static hostname: web01
Operating System: Ubuntu 24.04.3 LTS
          Kernel: Linux 6.8.0-84-generic
    Architecture: x86-64

Paso 2: Actualizaciones y parches

Los paquetes con vulnerabilidades conocidas son la vía de entrada más común. Comprueba qué hay pendiente:

sudo apt update
apt list --upgradable

Esperado: lista vacía o solo paquetes publicados en los últimos días.

Comprueba si hay un reinicio pendiente (por ejemplo, tras actualizar el kernel):

cat /var/run/reboot-required 2>/dev/null || echo "No hace falta reiniciar"

Verifica que las actualizaciones de seguridad automáticas están activas:

cat /etc/apt/apt.conf.d/20auto-upgrades
systemctl is-enabled unattended-upgrades
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
enabled

Corrección: si falta el archivo o los valores son 0, instala y activa el paquete:

sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades

En Rocky Linux 9 el equivalente es sudo dnf check-update y el paquete dnf-automatic.

Paso 3: Cuentas de usuario

Solo root debe tener UID 0. Cualquier otra cuenta con UID 0 tiene privilegios completos:

awk -F: '$3 == 0 {print $1}' /etc/passwd
root

Ninguna cuenta debe tener la contraseña vacía:

sudo awk -F: '$2 == "" {print $1}' /etc/shadow

Esperado: ninguna salida. Corrección: bloquea la cuenta con sudo passwd -l nombre_usuario.

Lista las cuentas que pueden iniciar sesión con una shell interactiva y confirma que conoces a todas:

grep -Ev '(/nologin|/false)$' /etc/passwd | cut -d: -f1,3,7

Revisa los inicios de sesión recientes y los intentos fallidos:

last -n 20
sudo lastb -n 20

Corrección: elimina las cuentas que ya no se usan con sudo deluser --remove-home nombre_usuario, o bloquéalas con sudo usermod -L -e 1 nombre_usuario si necesitas conservar sus archivos.

Paso 4: Privilegios de sudo

Comprueba quién pertenece a los grupos con acceso de administración (sudo en Ubuntu y Debian, wheel en Rocky):

getent group sudo
sudo:x:27:your_user

Busca reglas que permitan sudo sin contraseña, que convierten cualquier sesión robada en root inmediato:

sudo grep -rn 'NOPASSWD' /etc/sudoers /etc/sudoers.d/

Esperado: ninguna regla o solo reglas justificadas para comandos concretos (no ALL). Edita siempre con sudo visudo o sudo visudo -f /etc/sudoers.d/archivo para que se valide la sintaxis.

Paso 5: Configuración de SSH

No revises solo /etc/ssh/sshd_config: en Ubuntu 24.04 los archivos de /etc/ssh/sshd_config.d/ (por ejemplo 50-cloud-init.conf) pueden cambiar los valores. sshd -T muestra la configuración efectiva:

sudo sshd -T | grep -Ei '^(permitrootlogin|passwordauthentication|kbdinteractiveauthentication|pubkeyauthentication|maxauthtries|x11forwarding|permitemptypasswords) '

Valores recomendados:

ParámetroValor recomendado
permitrootloginno (o prohibit-password si necesitas root con clave)
passwordauthenticationno
kbdinteractiveauthenticationno (salvo que uses 2FA)
pubkeyauthenticationyes
maxauthtries3 o 4
x11forwardingno
permitemptypasswordsno

Revisa también qué claves públicas pueden entrar en cada cuenta, incluida root:

sudo ssh-keygen -lf /root/.ssh/authorized_keys
ssh-keygen -lf ~/.ssh/authorized_keys

Cada línea muestra la huella y el comentario de una clave. Elimina las que no reconozcas.

Corrección: pon los valores en /etc/ssh/sshd_config.d/10-hardening.conf (el primer valor leído es el que se aplica, y 10- se lee antes que 50-cloud-init.conf), valida con sudo sshd -t y aplica con sudo systemctl reload ssh. La guía de gestión de claves SSH de esta sección lo explica en detalle.

Paso 6: Puertos abiertos y servicios

Lista los puertos en escucha y el proceso que los abre:

sudo ss -tulpn
Netid State  Local Address:Port  Peer Address:Port Process
tcp   LISTEN 0.0.0.0:22          0.0.0.0:*         users:(("sshd",pid=812,fd=3))
tcp   LISTEN 127.0.0.1:3306      0.0.0.0:*         users:(("mysqld",pid=945,fd=21))
tcp   LISTEN 0.0.0.0:443         0.0.0.0:*         users:(("nginx",pid=1020,fd=6))

Esperado: los servicios internos (bases de datos, Redis, paneles de administración) escuchan en 127.0.0.1 o en una IP privada, nunca en 0.0.0.0 sin firewall.

Revisa los servicios en ejecución y deshabilita los que no uses:

systemctl list-units --type=service --state=running --no-pager

Corrección: sudo systemctl disable --now nombre_servicio.

Paso 7: Firewall

Confirma que el firewall está activo, que la política por defecto de entrada es denegar y que solo están abiertos los puertos que viste en el paso anterior:

sudo ufw status verbose
Status: active
Default: deny (incoming), allow (outgoing), disabled (routed)

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW IN    Anywhere
443/tcp                    ALLOW IN    Anywhere

Corrección: si UFW está inactivo, permite SSH antes de activarlo:

sudo ufw allow OpenSSH
sudo ufw enable

En Rocky Linux 9 usa sudo firewall-cmd --list-all.

Paso 8: Parámetros del kernel

Algunos parámetros de red y de memoria reducen la superficie de ataque. Consulta sus valores actuales:

sysctl net.ipv4.ip_forward net.ipv4.tcp_syncookies net.ipv4.conf.all.accept_redirects net.ipv4.conf.all.send_redirects net.ipv4.conf.all.accept_source_route net.ipv4.conf.all.log_martians kernel.randomize_va_space kernel.kptr_restrict kernel.dmesg_restrict fs.suid_dumpable
ParámetroValor recomendadoMotivo
net.ipv4.ip_forward0El servidor no enruta tráfico (1 si usas Docker, Kubernetes o VPN).
net.ipv4.tcp_syncookies1Mitiga inundaciones SYN.
net.ipv4.conf.all.accept_redirects0Ignora redirecciones ICMP.
net.ipv4.conf.all.send_redirects0No envía redirecciones.
net.ipv4.conf.all.accept_source_route0Rechaza paquetes con ruta de origen.
net.ipv4.conf.all.log_martians1Registra paquetes con direcciones imposibles.
kernel.randomize_va_space2ASLR completo.
kernel.kptr_restrict1 o 2Oculta direcciones del kernel.
kernel.dmesg_restrict1Solo root lee dmesg.
fs.suid_dumpable0Sin volcados de memoria de binarios SUID.

Corrección: crea un archivo con los valores que no coincidan:

sudo nano /etc/sysctl.d/99-hardening.conf
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.all.log_martians = 1
fs.suid_dumpable = 0

Aplícalo y vuelve a consultar los valores:

sudo sysctl --system

Paso 9: Permisos de archivos

Los archivos de credenciales deben tener permisos estrictos:

stat -c '%a %U:%G %n' /etc/passwd /etc/shadow /etc/group /etc/gshadow /etc/ssh/sshd_config
644 root:root /etc/passwd
640 root:shadow /etc/shadow
644 root:root /etc/group
640 root:shadow /etc/gshadow
644 root:root /etc/ssh/sshd_config

Busca archivos que cualquier usuario puede modificar fuera de los directorios temporales:

sudo find / -xdev -type f -perm -0002 -not -path '/proc/*' 2>/dev/null

Esperado: ninguna salida. Corrección: sudo chmod o-w ruta/al/archivo.

Lista los binarios SUID y SGID. Guarda la lista para comparar en la siguiente auditoría: un binario SUID nuevo que no viene de un paquete es una señal de alarma.

sudo find / -xdev -type f \( -perm -4000 -o -perm -2000 \) 2>/dev/null | sort | tee "$AUDIT_DIR/suid.txt"

Comprueba además que ningún archivo instalado por paquetes ha sido modificado. debsums -s solo muestra los archivos cuya suma no coincide:

sudo apt install debsums
sudo debsums -s

Esperado: ninguna salida. Un binario de /usr/bin modificado requiere investigación inmediata.

Paso 10: Tareas programadas

Los atacantes suelen dejar persistencia en cron o en temporizadores de systemd. Revisa ambos:

ls -la /etc/cron.d /etc/cron.daily /etc/cron.hourly /etc/cron.weekly
sudo ls -la /var/spool/cron/crontabs/
systemctl list-timers --all --no-pager

Revisa el contenido de cualquier crontab de usuario que no esperes con sudo crontab -l -u nombre_usuario.

Paso 11: Registros de autenticación

Cuenta los intentos fallidos de SSH de las últimas 24 horas y las IP que más lo intentan:

sudo journalctl -u ssh --since "24 hours ago" --no-pager | grep -c 'Failed password'
sudo journalctl -u ssh --since "24 hours ago" --no-pager | grep -oP 'Failed password .* from \K[0-9.]+' | sort | uniq -c | sort -rn | head

Revisa los inicios de sesión aceptados y el método usado:

sudo journalctl -u ssh --since "7 days ago" --no-pager | grep 'Accepted'

Esperado: solo Accepted publickey desde IP que reconozcas. Un Accepted password cuando la autenticación por contraseña debería estar desactivada indica un problema de configuración.

Comprueba que los registros se conservan tras reiniciar:

journalctl --list-boots --no-pager | tail -n 3

Si solo aparece el arranque actual, el diario no es persistente. En Ubuntu 24.04 basta con crear el directorio y reiniciar el servicio:

sudo mkdir -p /var/log/journal
sudo systemctl restart systemd-journald

Paso 12: Cerrar la auditoría

Comprime las evidencias para archivarlas fuera del servidor:

tar -czf "$AUDIT_DIR.tar.gz" -C "$HOME" "$(basename "$AUDIT_DIR")"
ls -lh "$AUDIT_DIR.tar.gz"

Anota para cada punto si pasa, falla o se acepta el riesgo, y quién es responsable de corregirlo. En la siguiente auditoría, compara por ejemplo la lista SUID con diff.

Conclusión

Has revisado actualizaciones, cuentas, sudo, SSH, puertos, firewall, parámetros del kernel, permisos, tareas programadas y registros de autenticación, y has guardado las evidencias en un archivo fechado. Repite esta lista al menos cada trimestre y siempre después de un cambio importante en el servidor.

Como siguientes pasos puedes:

  • Automatizar gran parte de estas comprobaciones con Lynis y comparar su índice de endurecimiento en el tiempo.
  • Desactivar por completo el acceso por contraseña con claves SSH y añadir autenticación de dos factores.
  • Instalar Fail2ban para bloquear automáticamente las IP con muchos intentos fallidos.