auditd: auditoría a nivel syscall y análisis de accesos

El kernel Linux tiene un subsistema de auditoría que intercepta llamadas al sistema antes de que se completen y genera registros estructurados con el UID real, el PID, la hora exacta y el resultado de la operación. auditd es el demonio en espacio de usuario que recibe esos eventos a través de un socket netlink y los persiste en /var/log/audit/audit.log. No es logging de aplicación — es logging del kernel, lo que significa que no puede ser silenciado por el proceso auditado ni por un usuario con CAP_DAC_OVERRIDE.

La distinción importa porque herramientas como syslog o journald registran lo que las aplicaciones deciden reportar. auditd registra lo que el kernel observa, independientemente de si la aplicación coopera. Si alguien abre /etc/shadow con un editor hexadecimal a las 3 de la mañana, auditd lo ve. Si ese mismo proceso nunca llama a syslog, journald no sabe nada.

Las reglas se definen en /etc/audit/rules.d/*.rules y augenrules las compila en /etc/audit/audit.rules al arrancar el servicio. El motor de reglas opera en dos modalidades: reglas de vigilancia (-w) que monitorizan rutas del sistema de archivos a nivel de llamadas open/rename/unlink, y reglas de sistema (-a always,exit) que interceptan syscalls concretas con filtros sobre campos como UID o arquitectura. Cuando una regla hace match, el kernel añade el evento a una cola en memoria; auditd la drena y escribe el resultado. Si la cola se satura porque auditd no da abasto, el kernel puede entrar en modo pánico o descartar eventos según la política configurada en failure_action.

Usarlo mal tiene consecuencias reales en ambas direcciones: reglas demasiado amplias en un servidor con mucha I/O pueden saturar el disco con gigabytes de eventos inútiles y degradar el rendimiento porque cada syscall auditada tiene coste. Reglas demasiado estrechas o ausentes significan que, cuando pasa algo, no tienes evidencia — y en una investigación forense, la ausencia de log equivale a la ausencia del hecho.

# Instalar auditd y las herramientas de consulta
apt install auditd audispd-plugins

# Activar el servicio (en Debian no arranca solo tras instalar)
systemctl enable --now auditd

# ── Definir reglas de auditoría ──────────────────────────────────────────

cat > /etc/audit/rules.d/hardening.rules << 'EOF'
# Eliminar todas las reglas previas al cargar este conjunto
-D

# Tamaño del buffer en el kernel (eventos en vuelo)
-b 8192

# Política cuando el kernel no puede escribir eventos: 1=log en kernel, 2=panic
-f 1

# Detectar si alguien modifica las propias reglas de auditoría en tiempo real
-w /etc/audit/audit.rules -p wa -k audit_rules_modified
-w /etc/audit/rules.d/ -p wa -k audit_rules_modified

# Archivos de autenticación críticos
-w /etc/passwd -p wa -k passwd_changes
-w /etc/shadow -p wa -k shadow_changes
-w /etc/group -p wa -k group_changes
-w /etc/sudoers -p wa -k sudoers_changes
-w /etc/sudoers.d/ -p wa -k sudoers_changes

# Binarios de escalada de privilegios: vigilar ejecución (x) y atributos (a)
-w /usr/bin/sudo -p xa -k privilege_escalation
-w /usr/bin/su -p xa -k privilege_escalation
-w /bin/su -p xa -k privilege_escalation

# Syscalls de gestión de cuentas (cualquier arquitectura)
-a always,exit -F arch=b64 -S useradd,userdel,usermod,groupadd,groupdel,groupmod -k account_changes
-a always,exit -F arch=b32 -S useradd,userdel,usermod,groupadd,groupdel,groupmod -k account_changes

# Ejecución de comandos por root fuera de rutas estándar (detección de backdoors)
-a always,exit -F arch=b64 -S execve -F uid=0 -F exe!=/usr/bin/sudo -k root_commands

# Cambios en SSH: ficheros de configuración y authorized_keys
-w /etc/ssh/sshd_config -p wa -k sshd_config
-w /root/.ssh/ -p wa -k ssh_keys
# Para usuarios normales usarías -w /home/deploy/.ssh/ según el caso

# Montajes y desmontajes (un atacante puede montar un tmpfs para ocultar herramientas)
-a always,exit -F arch=b64 -S mount,umount2 -k mounts

# Cargas de módulos del kernel: vector de rootkits
-w /sbin/insmod -p x -k module_load
-w /sbin/rmmod -p x -k module_load
-w /sbin/modprobe -p x -k module_load
-a always,exit -F arch=b64 -S init_module,finit_module,delete_module -k module_load

# Hacer las reglas inmutables hasta el próximo reinicio
# Con -e 2 nadie puede modificar las reglas sin reiniciar el sistema
-e 2
EOF

# Recargar las reglas sin reiniciar el sistema
# augenrules compila todos los *.rules en /etc/audit/audit.rules
augenrules --load

# Verificar que las reglas están activas
auditctl -l

# ── Consulta de eventos ──────────────────────────────────────────────────

# Todos los eventos con clave passwd_changes (últimas 24h)
ausearch -k passwd_changes --start today

# Eventos de una clave con salida en formato interpretable
ausearch -k sudoers_changes -i

# Todos los comandos ejecutados por el usuario uid=1001 hoy
ausearch -ua 1001 --start today -i

# Informe de resumen: qué claves se han disparado y cuántas veces
aureport --key --summary

# Informe de autenticaciones fallidas
aureport --auth --failed

# Informe de accesos a ficheros con la clave shadow_changes
aureport --file -k shadow_changes

# ── Contexto de sesión y accesos ─────────────────────────────────────────

# Historial de logins (lee /var/log/wtmp, incluye reinicios)
last -n 20

# Último login de cada usuario del sistema (lee /var/log/lastlog)
lastlog | grep -v 'Never logged in' | head -30

# Usuarios conectados ahora mismo con qué proceso tienen en primer plano
w

# Solo quién está conectado (sin detalle de proceso)
who

# ── Análisis de eventos SSH ──────────────────────────────────────────────

# Todos los eventos del servicio SSH desde el arranque actual
journalctl _SYSTEMD_UNIT=sshd.service -n 100

# Solo autenticaciones fallidas de SSH en las últimas 2 horas
journalctl _SYSTEMD_UNIT=sshd.service --since "2 hours ago" \
  | grep -E 'Failed|Invalid|disconnect'

# Correlacionar: quién hizo SSH y luego tocó /etc/passwd
# Primero sacar el PID de la sesión SSH de interés desde journalctl,
# luego buscar ese PID en los registros de audit:
ausearch -k passwd_changes --start today -i | grep -E 'pid|comm|name'

Lo que hace cada decisión

-b 8192 define cuántos eventos pueden estar en vuelo en el buffer del kernel esperando a que auditd los lea. El valor por defecto (320) es absurdamente bajo para un sistema activo. Si el buffer se llena, el kernel aplica la política de -f: con -f 1 simplemente loggea el overflow en el kernel log; con -f 2 provoca un kernel panic — útil en sistemas certificados donde perder eventos de auditoría es inaceptable, pero destructivo en producción general.

-p wa vs -p xa en las reglas de vigilancia: w captura escrituras (incluyendo truncado), a captura cambios de atributos (chmod, chown), r captura lecturas, x captura ejecución. En /etc/passwd no necesitas x porque no se ejecuta; en /usr/bin/sudo te interesa principalmente x para saber quién lo invoca y a para detectar si alguien le pone un SUID extra.

-a always,exit -F arch=b64 -S execve con el filtro -F uid=0 en la regla root_commands es una red amplia que puede generar mucho volumen. En producción real se refina añadiendo -F auid>=1000 para capturar solo los comandos que root ejecuta después de haber hecho su o sudo desde una cuenta de usuario (el auid — audit UID — conserva la identidad original de login, mientras que uid refleja el UID efectivo actual). Esa distinción entre uid y auid es uno de los conceptos más útiles de auditd y la mayoría de la gente la ignora.

-e 2 al final del fichero de reglas activa el modo inmutable: una vez cargadas, las reglas no pueden modificarse sin reiniciar. Esto previene que un atacante con root añada una regla para excluirse de la auditoría o simplemente vacíe las reglas con auditctl -D. La contrapartida es que tampoco puedes cambiarlas en caliente, lo que complica la depuración. En sistemas de producción hardened vale la pena; en un workstation de desarrollo, no.

ausearch -i pide interpretación: en lugar de mostrar UIDs numéricos muestra nombres de usuario, en lugar de números de syscall muestra los nombres. Sin -i, los logs son parseable pero difíciles de leer a ojo. Con -i, los tiempos también se muestran en formato humano en lugar de epoch.

aureport --key --summary es el punto de entrada correcto para una revisión diaria: te da una tabla de cuántos eventos disparó cada clave. Si passwd_changes tiene 3 eventos en una semana, es normal; si tiene 847, algo está pasando. ausearch es para investigar un evento concreto; aureport es para detectar anomalías en volumen.

last vs lastlog hacen cosas distintas que se complementan. last lee /var/log/wtmp y muestra sesiones completas con duración, incluyendo los reinicios del sistema — es lo primero que miras cuando sospechas acceso no autorizado porque te da la línea temporal. lastlog lee /var/log/lastlog que es una base de datos binaria indexada por UID: una fila por usuario, el último login solamente. Es útil para detectar cuentas de servicio que teóricamente no deberían tener logins interactivos pero de repente aparecen con una fecha.

El hilo que conecta todo esto es la filosofía de seguridad por capas en el tiempo: auditd no previene ningún ataque. Un atacante con root puede hacer lo que quiera. Lo que auditd con -e 2 garantiza es que, si llegaste a -e 2 antes de que el atacante entrara, tienes evidencia inmutable de lo que hizo, en qué orden, con qué UID real, y desde qué proceso padre. En una investigación forense, reconstruir la línea temporal del atacante a partir de los logs de auditd correlacionados con journalctl y last es exactamente cómo se determina el alcance de una intrusión — y esa reconstrucción solo es posible si las reglas estaban activas antes del incidente.

98

Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Scroll al inicio