Las tres lecciones anteriores han construido prevención: un modelo de control de acceso, identidades bien gestionadas, un servicio confinado y un sistema endurecido. Todo eso reduce la probabilidad de que ocurra algo malo y limita el daño si ocurre. Pero ninguna de esas medidas responde a la pregunta que de verdad angustia a quien administra un servidor en producción: ¿cómo sé si ha pasado algo?
Imagina el escenario concreto que resolveremos al final de esta lección. Son las 09:00 y la monitorización avisó de madrugada: entre las 03:12 y las 03:40 hubo un pico de escrituras en /var/lib/meteora que multiplica por veinte lo normal para esa hora, y ahora mismo hay un proceso en ejecución cuyo nombre nadie del equipo reconoce. ¿Qué haces? ¿Lo matas? ¿Reinicias el servidor? ¿Desconectas la red? ¿Miras primero los registros o el proceso? Cada una de esas decisiones, tomada en el orden equivocado, destruye información que no volverá, y algunas empeoran el incidente en lugar de contenerlo.
Esta lección da el método. Primero, qué se registra en un Linux y dónde: syslog con sus facilidades y prioridades, y journald con sus filtros —los que de verdad usarás—. Después, cómo se diseña el registro de una aplicación como meteo-api: qué debe contener cada evento y, sobre todo, qué nunca debe aparecer ahí, con la advertencia de RGPD que corresponde. Luego la rotación y la retención, el subsistema auditd del núcleo con su coste real en rendimiento, y el problema más incómodo de todos: la integridad de un registro escrito por un sistema que el atacante controla. Seguimos con la detección de cambios en el host —AIDE, rootkits, indicadores concretos— y terminamos con el ciclo de respuesta a incidentes aplicado paso a paso al caso de las 03:12, con la preservación de evidencias y sus implicaciones legales.
Contenido
- Por qué sin registro no hay detección ni respuesta
syslog: facilidades, prioridades y/var/log/journaldyjournalctlen la práctica- Diseño del registro de una aplicación
- Rotación y retención con
logrotate - El subsistema de auditoría del núcleo:
auditd - Integridad de los registros frente a un atacante con privilegios
- Detección de cambios e intrusos en el host
- El ciclo de respuesta a incidentes
- Caso práctico: el pico de las 03:12
- Preservación de evidencias
- Qué medidas preventivas deja cada incidente
Por qué sin registro no hay detección ni respuesta
Los controles de seguridad se agrupan en tres familias, y conviene ver dónde encaja cada cosa que hemos aprendido:
| Tipo de control | Qué hace | Ejemplos del módulo |
|---|---|---|
| Preventivo | Impide que ocurra | Permisos, capabilities, AppArmor, cortafuegos, seccomp |
| Detectivo | Avisa de que ha ocurrido | Registros, auditd, AIDE, monitorización |
| Correctivo | Repara o contiene | Copias de seguridad, aislamiento, reinstalación |
Un sistema con controles preventivos y sin controles detectivos tiene un problema estructural: cuando la prevención falla, nadie se entera. Y la prevención falla siempre alguna vez, porque el software tiene fallos, las configuraciones se degradan y las personas cometen errores.
Sin registros, cuatro cosas resultan imposibles, no difíciles:
- Detectar. Un atacante que no rompe nada visible puede permanecer meses. La mediana del tiempo de permanencia no detectada en incidentes reales se mide en semanas, no en horas.
- Investigar. Sin traza no se puede responder a las preguntas que importan: qué entró, cuándo, por dónde, qué tocó y qué se llevó.
- Contener con criterio. Sin saber el alcance, la única opción es apagarlo todo, que suele ser desproporcionado y a veces destruye la evidencia.
- Aprender. Un incidente del que no se saca una medida preventiva concreta se repetirá.
De ahí la regla de trabajo de esta lección: el registro no es un subproducto del sistema, es un control de seguridad y se diseña como tal, con su contenido, su retención, su protección y su verificación.
syslog: facilidades, prioridades y /var/log/
syslog es el mecanismo clásico de UNIX: un demonio recibe mensajes de todos los programas y los clasifica por dos dimensiones. Sigue siendo relevante porque es el lenguaje común de la industria: routers, cortafuegos, cabinas de almacenamiento y colectores centralizados hablan syslog.
| Dimensión | Valores |
|---|---|
| Facilidad (de dónde viene) | kern, user, mail, daemon, auth, authpriv, cron, syslog, lpr, news, uucp, local0–local7 |
| Prioridad (qué de grave es) | emerg(0), alert(1), crit(2), err(3), warning(4), notice(5), info(6), debug(7) |
Las que más te importarán: auth y authpriv recogen todo lo relativo a autenticación y elevación —inicios de sesión, sudo, PAM—, y authpriv es la variante para lo que puede contener datos sensibles, por lo que su fichero tiene permisos más restrictivos. Y local0–local7 están reservadas para aplicaciones propias: meteo-api puede usar local3, por ejemplo, y así se separa de todo lo demás sin tocar el resto del sistema.
| Fichero | Qué contiene | Por qué mirarlo |
|---|---|---|
/var/log/auth.log |
Autenticación, sudo, SSH, PAM |
El primero en cualquier investigación |
/var/log/syslog |
Todo lo general | Visión conjunta |
/var/log/kern.log |
Mensajes del núcleo | OOM killer, discos, denegaciones de AppArmor |
/var/log/meteora/meteo-api.log |
El registro de la aplicación | Actividad del servicio |
/var/log/audit/audit.log |
Subsistema auditd |
Auditoría fina (apartado 6) |
/var/log/wtmp, btmp, lastlog |
Sesiones correctas, fallidas y último acceso | Binarios: se leen con last, lastb, lastlog |
# /etc/rsyslog.d/50-meteora.conf local3.* /var/log/meteora/meteo-api.log auth,authpriv.* /var/log/auth.log *.emerg :omusrmsg:* auth,authpriv.* @@colector.meteora.example:6514 # copia REMOTA por TLS
Cómo se lee esa configuración: cada línea es un selector (facilidad.prioridad) seguido de un destino. local3.* manda todo lo de la aplicación a su propio fichero. *.emerg avisa a todos los usuarios conectados de las emergencias. Y la última línea es la importante para el apartado 7: @@ significa envío por TCP con TLS a un colector remoto —con una sola @ sería UDP, sin garantía de entrega—, de modo que los eventos de autenticación existen también fuera de la máquina. Ese detalle es lo que separa un registro que sirve en una investigación de uno que no.
journald y journalctl en la práctica
En un Debian actual, el registro principal es el diario de systemd: un almacén binario e indexado en el que cada entrada lleva campos estructurados además del texto —unidad, PID, UID, ejecutable, prioridad, identificador de arranque—, y por eso se puede consultar como una pequeña base de datos.
| syslog | journald | |
|---|---|---|
| Formato | Texto plano | Binario indexado |
| Consulta | grep, awk |
journalctl con filtros por campo |
| Metadatos | Los que traiga la línea | Automáticos y no falsificables por el emisor |
| Persistencia | Siempre en disco | Configurable: volátil o persistente |
| Integridad | Ninguna | Sellado con FSS (--setup-keys) |
| Interoperabilidad | Universal | Propia de systemd (con reenvío a syslog) |
La propiedad decisiva es la tercera: journald añade los metadatos por su cuenta, tomándolos del propio sistema y no del texto del mensaje. Un proceso no puede mentir sobre su PID, su UID o su unidad, porque no es él quien los escribe. En syslog, cualquiera que escriba en el socket puede afirmar ser quien quiera.
# --- Persistencia: lo PRIMERO que hay que comprobar ---
sudo mkdir -p /var/log/journal && sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald
journalctl --disk-usage
# --- Filtros esenciales ---
journalctl -u meteo-api # por unidad
journalctl -u meteo-api -f # seguir en vivo
journalctl -p err # prioridad err o superior
journalctl --since "2026-09-01 03:00" --until "2026-09-01 04:00"
journalctl --since "-2h" # las dos últimas horas
journalctl -b # solo este arranque
journalctl -b -1 # el arranque ANTERIOR
journalctl _UID=990 # por campo: todo lo del usuario meteora
journalctl _COMM=sudo # todas las elevaciones
journalctl -k -g -i apparmor # mensajes del núcleo que casen con un patrón
journalctl -u meteo-api -o json-pretty # con TODOS los campos, para automatizarLos que marcan la diferencia en una investigación. --since y --until acotan la ventana temporal, que es siempre el primer paso: no se lee "el log", se lee la media hora relevante. -b -1 consulta el arranque anterior, imprescindible cuando el servidor se ha reiniciado —o lo han reiniciado— y necesitas ver qué pasó justo antes. Los filtros por campo (_UID=, _COMM=, _PID=) son la ventaja real del formato indexado: journalctl _UID=990 --since "-24h" te da todo lo que hizo la identidad del servicio en un día, sin depender de que el texto del mensaje contenga la palabra adecuada. Y -o json-pretty expone todos los campos, que es lo que necesitas para enviar a un colector o para automatizar una comprobación.
La comprobación de persistencia no es opcional. Sin
/var/log/journal, el diario vive en/run, que es tmpfs (04-03): se pierde entero en cada reinicio. Un atacante que reinicie la máquina borra el registro sin tocar un solo fichero, y tú te quedas investigando un incidente del que no queda nada. Es de las primeras cosas que hay que verificar en un servidor recién instalado.
Y los tres límites de retención, que hay que fijar de forma consciente:
# /etc/systemd/journald.conf Storage=persistent SystemMaxUse=2G # tope total del diario SystemMaxFileSize=128M MaxRetentionSec=90day # ← la VENTANA DE INVESTIGACIÓN ForwardToSyslog=yes # copia a rsyslog, y de ahí al colector remoto
MaxRetentionSec es la decisión de seguridad de este bloque: define cuánto hacia atrás puedes investigar. Si un compromiso se detecta a las seis semanas —lo habitual— y tu retención es de siete días, los registros del momento de la entrada ya no existen y nunca sabrás por dónde entraron.
Diseño del registro de una aplicación
Un registro útil no sale solo: se diseña. Estos son los campos que debe llevar cada evento de meteo-api:
| Campo | Por qué | Ejemplo |
|---|---|---|
| Marca de tiempo con zona | Sin zona, correlacionar con otros sistemas es imposible | 2026-09-01T03:12:07.481+02:00 |
| Evento | Qué ocurrió, en vocabulario cerrado | auth.fallo, consulta.ok, export.denegado |
| Identidad | Quién lo hizo | cliente_id=CLI-4471 |
| Origen | Desde dónde | origen=203.0.113.45 |
| Objeto | Sobre qué | recurso=/lecturas/2026-08-31 |
| Resultado | Éxito o fracaso, siempre | resultado=denegado |
| Identificador de correlación | Para seguir una petición entre servicios | traza=7f3a9c21 |
| Severidad | Para filtrar y alertar | nivel=warning |
import logging, json, uuid
from logging.handlers import SysLogHandler
log = logging.getLogger("meteo-api")
log.addHandler(SysLogHandler(address="/dev/log", facility=SysLogHandler.LOG_LOCAL3))
def registrar(evento, resultado, **campos):
log.info(json.dumps({"evento": evento, "resultado": resultado, **campos}))
# En el punto de la aplicación:
traza = uuid.uuid4().hex[:8]
registrar("auth.fallo", "denegado", cliente="CLI-4471",
origen=peticion.ip, motivo="token_caducado", traza=traza)Tres decisiones de este código. El formato estructurado (JSON) permite consultar y agregar sin depender de expresiones regulares frágiles; un colector puede filtrar por evento sin entender el texto. El identificador de correlación se genera al recibir la petición y acompaña a todos los eventos que provoque, incluidos los de ingestor y agregador si se propaga: es lo que permite reconstruir una petición entre tres servicios. Y el motivo del fallo se registra siempre, porque "denegado" sin motivo no sirve para nada en una investigación.
Qué NUNCA debe aparecer en un registro
| Nunca | Por qué |
|---|---|
| Contraseñas, ni siquiera fallidas | Un fallo suele ser un dedazo sobre la contraseña correcta |
| Tokens, claves de API, cookies de sesión | Quien lea el registro puede reutilizarlos tal cual |
| Números de tarjeta, datos bancarios | Prohibido por normativa sectorial |
| Datos personales innecesarios | Minimización: si no hace falta para operar o investigar, no se registra |
| Contenido completo de peticiones | Arrastra todo lo anterior sin querer |
| Volcados de memoria en el registro | Contienen secretos recién leídos (05-03) |
El caso de las contraseñas fallidas merece detenerse. Parece inofensivo registrar el intento fallido "para investigar", y es una de las peores prácticas posibles: la mayoría de los fallos son errores de tecleo sobre la contraseña buena, así que el registro acaba conteniendo, en claro y con nombre de usuario al lado, las credenciales reales de tus usuarios. Y ese registro lo lee todo el grupo adm, viaja al colector central y entra en las copias de seguridad.
Con datos personales, la regla operativa es registrar identificadores, no personas: cliente=CLI-4471 en lugar del nombre y el correo, y una tabla aparte —con su propio control de acceso— que traduzca el identificador cuando haga falta de verdad.
Advertencia de RGPD y cumplimiento normativo. Una dirección IP, un identificador de usuario o un historial de accesos son datos personales en el marco del RGPD. Registrarlos exige base legal, información a los interesados, minimización, plazo de conservación definido y justificado, control de acceso y, cuando proceda, evaluación de impacto. La retención de registros entra además en conflicto habitual con el derecho de supresión, y hay obligaciones sectoriales que imponen plazos mínimos. Define la política de registro y retención junto con el responsable de cumplimiento normativo o con asesoría jurídica, por escrito, antes de desplegarla, y no la improvises en medio de un incidente.
Rotación y retención con logrotate
Sin rotación, un registro crece hasta llenar el disco, y un /var/log lleno para servicios —incluido el propio registro, con lo que dejas de tener traza justo cuando más falta hace—.
# /etc/logrotate.d/meteora
/var/log/meteora/*.log {
daily # rotar cada día
rotate 90 # conservar 90 ficheros = 90 días de ventana
compress # comprimir los antiguos (los .log comprimen ~10:1)
delaycompress # no comprimir el más reciente: puede seguir abierto
missingok # no fallar si aún no existe
notifempty # no rotar un fichero vacío
create 0640 meteora adm # el nuevo nace con los permisos de 04-06
dateext # nombres por fecha: meteo-api.log-20260901
sharedscripts
postrotate
systemctl reload meteo-api > /dev/null 2>&1 || true
endscript
}Las tres directivas que causan problemas si se entienden mal. create 0640 meteora adm es imprescindible: sin ella, el fichero nuevo hereda la umask del proceso de rotación —que corre como root— y puede quedar con permisos incorrectos o con propietario root, y entonces el servicio deja de poder escribir en su propio registro. postrotate con reload existe por una razón que ya conoces de 04-04: cuando logrotate renombra el fichero, el proceso sigue escribiendo en el mismo inodo a través de su descriptor abierto, así que sus mensajes van al fichero rotado y el nuevo se queda vacío; hay que avisarle para que reabra. La alternativa es copytruncate, que copia y trunca en el sitio, pero pierde las líneas escritas entre la copia y el truncado, así que solo se usa cuando no hay forma de avisar al proceso. Y delaycompress evita comprimir un fichero que todavía puede estar abierto.
El compromiso de la retención se calcula con números concretos. meteo-api genera unos 40 MB de registro al día; noventa días sin comprimir serían 3,6 GB, y comprimidos rondan los 400 MB. La pregunta que decide el valor no es cuánto ocupa, sino cuánto hacia atrás necesitas poder investigar:
| Retención | Espacio (comprimido) | Qué permite investigar |
|---|---|---|
| 7 días | ~30 MB | Solo incidentes detectados de inmediato |
| 90 días | ~400 MB | Compromiso detectado semanas después: lo habitual |
| 365 días | ~1,6 GB | Investigación completa; puede chocar con la minimización de datos |
Noventa días es un punto de partida razonable para meteo-01: cubre el caso realista de detección tardía sin acumular datos personales durante un año. Pero es una decisión que debe validarse con cumplimiento normativo, porque puede haber plazos mínimos obligatorios o máximos exigidos por la minimización.
sudo logrotate -d /etc/logrotate.d/meteora # simular SIN hacer nada
sudo logrotate -f /etc/logrotate.d/meteora # forzar una rotación de pruebaEl subsistema de auditoría del núcleo: auditd
journald registra lo que los programas deciden contar. auditd registra lo que ocurre en el núcleo, tanto si el programa quiere como si no: qué proceso abrió qué fichero, qué llamada al sistema se ejecutó, quién cambió un permiso. Es la diferencia entre el testimonio del sospechoso y la grabación de la cámara.
# /etc/audit/rules.d/meteora.rules ## 1. Vigilancia sobre ficheros críticos (w = escritura, a = cambio de atributos) -w /etc/meteora/meteora.conf -p wa -k meteora_conf -w /etc/meteora/secrets.conf -p rwa -k meteora_secretos # también LECTURA -w /etc/passwd -p wa -k identidad -w /etc/shadow -p wa -k identidad -w /etc/sudoers -p wa -k escalada -w /etc/sudoers.d/ -p wa -k escalada -w /etc/ssh/sshd_config -p wa -k acceso_remoto ## 2. Llamadas al sistema sensibles -a always,exit -F arch=b64 -S execve -F euid=0 -F auid>=1000 -F auid!=-1 -k root_exec -a always,exit -F arch=b64 -S mount -S umount2 -k montaje -a always,exit -F arch=b64 -S init_module -S finit_module -k modulos -a always,exit -F arch=b64 -S chmod -S chown -S setxattr -F dir=/var/lib/meteora -k permisos ## 3. Inmutabilidad de las reglas: NADIE puede cambiarlas sin reiniciar -e 2
Cada bloque responde a una necesidad distinta. Las reglas -w vigilan rutas: fíjate en que secrets.conf lleva también r, porque en un fichero de claves leerlo ya es el evento relevante, no solo modificarlo. Las reglas de llamadas al sistema son más precisas: la primera registra todo execve ejecutado con privilegios de root por alguien que inició sesión como usuario normal —auid es el identificador de auditoría, que no cambia con su ni con sudo y por eso permite atribuir la acción a la persona real—; las siguientes cubren montaje, carga de módulos y cambios de permisos en el árbol de datos. Y -e 2 hace las reglas inmutables: a partir de ahí ni root puede modificarlas sin reiniciar la máquina, y un reinicio es en sí mismo un evento muy visible.
sudo augenrules --load && sudo auditctl -l # cargar y verificar
# Consultas
sudo ausearch -k meteora_secretos -i # -i traduce UID y llamadas a nombres
sudo ausearch -k escalada --start today -i
sudo ausearch -ua 1001 --start recent -i # todo lo del auid 1001 (carlos)
sudo aureport --summary ; sudo aureport --auth --failed -iausearch busca por clave, por usuario de auditoría, por rango temporal o por proceso, y -i es prácticamente obligatorio porque traduce los números a nombres legibles. aureport genera resúmenes: el de autenticaciones fallidas es de los más útiles para una revisión diaria.
El coste en rendimiento es real y hay que dimensionarlo. Cada evento auditado supone trabajo en el núcleo y una escritura en disco, y una regla mal pensada puede degradar el sistema notablemente. La regla peligrosa por excelencia es auditar todas las lecturas y escrituras de un árbol activo: el ingestor escribe 720.000 lecturas al día en /var/lib/meteora/lecturas, así que una regla -S read -S write sobre ese directorio generaría millones de eventos diarios, llenaría el disco en horas y añadiría latencia a cada operación. El criterio correcto es auditar lo raro, no lo frecuente: cambios de configuración, accesos a secretos, elevaciones de privilegio, carga de módulos, montajes. Y comprobar el volumen con aureport --summary durante los primeros días para ajustar.
Integridad de los registros frente a un atacante con privilegios
Llegamos al problema más incómodo, y el que hay que tener claro antes que ningún otro:
Un atacante con root en
meteo-01puede modificar o borrar cualquier registro local. Puede editar/var/log/auth.log, purgar el diario, pararauditd, quitar unchattr +aconCAP_LINUX_IMMUTABLEy reescribir la historia. Un registro local nunca es prueba suficiente de nada.
Eso no significa que las defensas locales sean inútiles; significa que hay que entender qué aporta cada una.
| Defensa | Qué aporta | Qué no aporta |
|---|---|---|
chattr +a (04-06) |
Impide truncar y modificar; solo se puede añadir | Root puede quitar el atributo. Evita accidentes y obliga a un paso deliberado |
Permisos 0640 meteora:adm |
Impide lectura y escritura por otros usuarios | Nada frente a root |
| Sellado FSS de journald | Detecta manipulación a posteriori con una clave externa | No la impide |
| Envío remoto inmediato | El evento ya está fuera antes de que puedan borrarlo | Si el envío es por lotes, se pierde la ventana |
| Colector con credenciales propias | El servidor no puede borrar lo ya enviado | Requiere infraestructura separada |
# 1. Solo-añadir en los registros locales
sudo chattr +a /var/log/meteora/meteo-api.log /var/log/auth.log
# 2. Sellado criptográfico del diario (guarda la clave FUERA de la máquina)
sudo journalctl --setup-keys --interval=1h
sudo journalctl --verify # detecta si el diario ha sido manipulado
# 3. Envío inmediato al colector, por TCP con TLS
# /etc/rsyslog.d/60-remoto.conf
# *.* action(type="omfwd" target="colector.meteora.example" port="6514"
# protocol="tcp" StreamDriverMode="1" StreamDriverAuthMode="x509/name"
# queue.type="LinkedList" queue.saveOnShutdown="on"
# action.resumeRetryCount="-1")La configuración de envío remoto tiene cuatro decisiones importantes. TCP con TLS garantiza entrega y confidencialidad, frente a UDP que pierde mensajes en silencio justo cuando hay saturación —que es cuando ocurren los incidentes—. StreamDriverAuthMode="x509/name" hace que el emisor verifique la identidad del colector, para que nadie pueda suplantarlo y absorber tus registros. La cola en disco con saveOnShutdown evita perder eventos si el colector no está disponible un rato. Y resumeRetryCount="-1" reintenta indefinidamente.
Y las tres propiedades que debe cumplir el colector para que todo esto valga:
Credenciales separadas. meteo-01 debe poder enviar eventos y no poder leerlos ni borrarlos. Si el certificado del servidor permitiera administrar el colector, un atacante con root en meteo-01 borraría también la copia remota, y no habríamos ganado nada.
Escritura inmediata y de solo añadir en destino. El valor del envío remoto está en que el evento sale en el momento, antes de que nadie pueda borrarlo; un envío por lotes cada quince minutos deja una ventana de quince minutos perfectamente aprovechable.
Retención independiente. El plazo lo fija el colector, no el servidor de origen.
La idea de fondo, que conviene formular explícitamente: la evidencia debe salir del alcance del atacante lo antes posible. Es el mismo razonamiento que las copias inmutables de 05-03 y, por cierto, la razón por la que en el apartado 11 la copia de la memoria se hace antes de tocar nada.
Detección de cambios e intrusos en el host
Comprobación de integridad de ficheros con AIDE
AIDE calcula una base de referencia con las sumas de verificación, permisos, propietarios y tiempos de todos los ficheros que le indiques, y después compara periódicamente contra ella. Detecta exactamente lo que un atacante necesita hacer para persistir: modificar un binario, añadir una unidad de systemd, tocar la configuración.
# /etc/aide/aide.conf (extracto) Binario = p+i+n+u+g+s+m+c+md5+sha256 # todo, incluidas las sumas Config = p+i+n+u+g+s+m+c+sha256 Registro = p+u+g+n+S # los logs CRECEN: no vigiles su tamaño /usr/bin Binario /usr/sbin Binario /etc Config /etc/meteora Config /var/log/meteora Registro !/var/lib/meteora/lecturas # los .dat cambian sin parar: EXCLUIR !/var/log/journal
sudo aideinit # crear la base de referencia
sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db
sudo aide --check # compararDos decisiones son las que hacen que AIDE funcione o se convierta en ruido inútil. Las reglas por tipo de fichero: a un binario se le vigila todo, pero a un registro que crece cada segundo no se le puede vigilar el tamaño ni la suma, solo permisos y propietario —de ahí la regla Registro con S, que tolera el crecimiento pero detecta un truncado—. Y las exclusiones: /var/lib/meteora/lecturas cambia constantemente por diseño, así que incluirlo generaría miles de diferencias diarias y nadie volvería a leer el informe.
Y el punto crítico: la base de referencia debe guardarse fuera de la máquina, o al menos en un medio de solo lectura. Si vive en /var/lib/aide/aide.db y el atacante tiene root, la actualiza tras hacer sus cambios y AIDE informará de que todo está en orden. Lo mismo vale para las listas de referencia de setuid y capabilities de 05-02.
Detección de rootkits e indicadores de compromiso
sudo apt install rkhunter chkrootkit
sudo rkhunter --update && sudo rkhunter --check --skip-keypress
sudo debsums -c # ficheros de paquetes ALTERADOS
sudo dpkg --verify # equivalente, integrado en dpkgEstas herramientas comparan binarios contra sumas conocidas y buscan patrones habituales. Son útiles y tienen un límite que hay que conocer: si el compromiso está en el núcleo, las respuestas del sistema no son fiables, incluidas las que reciben estas herramientas. Sirven para lo frecuente, no para lo sofisticado.
Los indicadores que se buscan a mano, con el comando y por qué es sospechoso:
# 1. Procesos SIN binario en disco (el ejecutable fue borrado tras arrancar)
sudo ls -l /proc/*/exe 2>/dev/null | grep -i deleted
# 2. Puertos en escucha no previstos y conexiones establecidas
sudo ss -tulnp ; sudo ss -tp state established
# 3. Ficheros setuid o con capabilities NUEVOS (05-02)
sudo find / -xdev -perm -4000 -type f 2>/dev/null | sort | diff /root/ref/suid.ref -
sudo getcap -r / 2>/dev/null | sort | diff /root/ref/caps.ref -
# 4. Tareas programadas y unidades desconocidas
sudo ls -la /etc/cron.* /var/spool/cron/crontabs/ ; systemctl list-timers --all
systemctl list-unit-files --state=enabled | grep -v '@'
# 5. Ficheros modificados recientemente en rutas de sistema
sudo find /etc /usr/bin /usr/sbin -newermt '-3 days' -type f -ls 2>/dev/null
# 6. Claves SSH añadidas
sudo find /home /root -name authorized_keys -newermt '-30 days' -lsEl primero merece explicación porque es el más revelador de todos: (deleted) en /proc/<pid>/exe significa que el programa está en ejecución pero su fichero ya no existe en el disco. Es una técnica de evasión clásica —se ejecuta el binario y se borra acto seguido, de modo que ningún análisis del sistema de ficheros lo encuentra—, y aunque tiene explicaciones legítimas (un binario actualizado mientras el proceso viejo sigue vivo, exactamente el caso de 04-02), en un servidor estable es una anomalía que hay que explicar. Y tiene una consecuencia forense preciosa que usaremos en el apartado 11: el fichero sigue existiendo mientras el proceso viva, porque su contador de enlaces no ha llegado a cero, y se puede recuperar copiando /proc/<pid>/exe.
Correlación centralizada
Un solo servidor produce eventos; una organización produce millones, repartidos entre servidores, cortafuegos, aplicaciones y servicios en la nube. La correlación centralizada —lo que se conoce genéricamente como SIEM, sin entrar en producto— hace tres cosas que ningún host puede hacer solo: normaliza formatos distintos a un esquema común, correlaciona eventos de fuentes distintas —"un acceso SSH correcto desde una IP que el cortafuegos vio escaneando hace diez minutos"—, y alerta sobre patrones definidos. Requiere el envío remoto del apartado 7 y una disciplina de nombres de evento como la del apartado 4; sin esas dos cosas, es un almacén caro de texto que nadie consulta.
El ciclo de respuesta a incidentes
Un incidente se gestiona con un método, no improvisando. Las seis fases son las mismas en todos los marcos de referencia:
graph LR
A["1. PREPARACIÓN<br/>Antes de que pase"] --> B["2. DETECCIÓN<br/>Y ANÁLISIS<br/>¿Qué ocurre?"]
B --> C["3. CONTENCIÓN<br/>Frenar sin destruir"]
C --> D["4. ERRADICACIÓN<br/>Quitar la causa"]
D --> E["5. RECUPERACIÓN<br/>Volver al servicio"]
E --> F["6. LECCIONES<br/>APRENDIDAS"]
F -.mejora.-> A
| Fase | Qué se hace | Error típico |
|---|---|---|
| 1. Preparación | Registro, copias, contactos, procedimiento escrito, práctica | No tenerla: improvisar bajo presión |
| 2. Detección y análisis | Confirmar, delimitar el alcance, preservar evidencia | Actuar antes de entender; destruir la evidencia |
| 3. Contención | Frenar el daño sin destruir la información | Apagar el servidor de inmediato |
| 4. Erradicación | Eliminar la causa raíz, no solo el síntoma | Matar el proceso y dar por cerrado |
| 5. Recuperación | Restaurar servicio y vigilar de cerca | Volver a producción sin saber si sigue dentro |
| 6. Lecciones aprendidas | Medidas preventivas concretas, con responsable y fecha | Un documento que nadie lee |
Los dos errores que más daño hacen son de la fase 3, y conviene entenderlos antes del caso práctico. Apagar el servidor destruye toda la memoria volátil: procesos, conexiones, claves de cifrado en RAM y el contenido de los binarios borrados que solo existen a través de /proc. Y matar el proceso sospechoso sin más elimina la evidencia y no resuelve nada, porque si hay un mecanismo de persistencia —una tarea programada, una unidad de systemd, una clave SSH— el proceso volverá en minutos y habrás perdido la oportunidad de observarlo.
Caso práctico: el pico de las 03:12
Situación. Son las 09:00 del 1 de septiembre de 2026. La monitorización avisó de un pico de escrituras en /var/lib/meteora entre las 03:12 y las 03:40, veinte veces lo normal para esa hora. Hay un proceso llamado kworkerd que nadie del equipo reconoce.
Fase 2: detección y análisis (sin tocar nada)
# 1. FOTO DEL ESTADO VOLÁTIL — primero, porque es lo que antes desaparece
ps auxf > /tmp/ev/ps.txt ; ss -tunap > /tmp/ev/red.txt
sudo lsof -n > /tmp/ev/lsof.txt ; date -Iseconds > /tmp/ev/hora.txt
# 2. EL PROCESO: qué es y de dónde viene
pgrep -a kworkerd # PID y línea de comandos
sudo ls -l /proc/<PID>/exe # ¿el binario existe?
# /proc/4471/exe -> /var/tmp/.cache/kworkerd (deleted) ← BORRADO
sudo cat /proc/<PID>/environ | tr '\0' '\n' # entorno
sudo ls -l /proc/<PID>/cwd ; sudo cat /proc/<PID>/status | grep -E 'Uid|PPid'
# Uid: 990 990 990 990 ← corre como meteora
# PPid: 1 ← su padre murió: fue "adoptado" por init (02-01)
# 3. RECUPERAR EL BINARIO antes de que el proceso muera
sudo cp /proc/<PID>/exe /tmp/ev/binario-recuperado
sha256sum /tmp/ev/binario-recuperado > /tmp/ev/binario.sha256
# 4. LA VENTANA TEMPORAL en los registros
journalctl --since "2026-09-01 02:30" --until "2026-09-01 04:30" > /tmp/ev/journal.txt
sudo ausearch --start 09/01/2026 02:30:00 --end 09/01/2026 04:30:00 -i > /tmp/ev/audit.txt
sudo grep -E 'sshd|sudo|su\[' /var/log/auth.log | sed -n '/Sep 1 02:/,/Sep 1 05:/p'
last -F | head -20 ; sudo lastb -F | head -20 # sesiones correctas y FALLIDASCómo se lee lo obtenido, y por qué en este orden. La foto del estado volátil va primero por el orden de volatilidad del apartado siguiente: procesos y conexiones desaparecen en cuanto algo cambie, mientras que los ficheros seguirán ahí dentro de una hora. El (deleted) en /proc/<PID>/exe confirma la técnica de evasión del apartado 8, y el PPid: 1 indica que el proceso padre ya murió, lo que suele significar que fue lanzado y abandonado deliberadamente. El Uid: 990 es la información más valiosa de todo el bloque: el proceso corre como meteora, no como root, así que el vector es casi con seguridad meteo-api o el ingestor, y el confinamiento de 05-03 nos dice de inmediato hasta dónde ha podido llegar. Y la copia del binario desde /proc hay que hacerla ya: si el proceso muere, el inodo se libera y el binario desaparece para siempre.
# 5. ¿QUÉ ESCRIBIÓ? Correlacionar con los ficheros de datos
ls -la --time-style=full-iso /var/lib/meteora/lecturas/ | head -20
sudo find /var/lib/meteora -newermt '2026-09-01 03:00' ! -newermt '2026-09-01 04:00' -ls
sudo ausearch -k meteora_secretos --start 09/01/2026 -i # ¿leyó las claves?
sudo ausearch -k escalada --start 09/01/2026 -i # ¿intentó subir a root?
# 6. ¿HAY PERSISTENCIA?
sudo find / -xdev -perm -4000 -type f 2>/dev/null | sort | diff /root/ref/suid.ref -
systemctl list-unit-files --state=enabled | diff /root/ref/units.ref -
sudo ls -la /etc/cron.* /var/spool/cron/crontabs/
sudo find /home /root -name authorized_keys -newermt '-7 days' -ls
sudo aide --check | head -40Hallazgos del caso. El proceso corre como meteora desde un binario borrado en /var/tmp/.cache/. auditd muestra que a las 03:11:58 hubo un execve desde el árbol de procesos de meteo-api, un minuto antes del pico. No hay eventos en meteora_secretos, así que no llegó a leer las claves de API. No hay eventos en escalada, y NoNewPrivileges=yes explica por qué. Y aide --check no marca cambios en /usr/bin ni en /etc: el confinamiento del apartado 9 de 05-03 impidió escribir fuera de las rutas declaradas. La persistencia se limita a una entrada de cron del usuario meteora que relanza el binario cada hora.
Fase 3: contención (frenar sin destruir)
# a) AISLAR LA RED sin apagar: mantiene la memoria y los procesos vivos
sudo nft insert rule inet filter salida ip daddr != 10.0.1.0/24 drop
# b) CONGELAR el proceso en lugar de matarlo: deja de actuar y sigue inspeccionable
sudo kill -STOP <PID>
# c) Cortar la persistencia
sudo crontab -l -u meteora > /tmp/ev/cron-meteora.txt && sudo crontab -r -u meteora
# d) Preservar los datos ANTES de cualquier limpieza
sudo cp -a --preserve=all /var/lib/meteora /mnt/evidencia/Las cuatro decisiones, con su porqué. Aislar la red en lugar de apagar detiene la exfiltración y el mando a distancia conservando todo el estado volátil, que es la evidencia más valiosa y la primera en perderse. kill -STOP en lugar de kill -9: el proceso deja de ejecutarse pero sigue existiendo, con su memoria, sus descriptores abiertos y su /proc/<PID>/exe intactos y disponibles para el análisis. Cortar la persistencia antes que nada más, porque si no volverá en menos de una hora. Y copiar los datos con -a --preserve=all para conservar permisos, ACL y marcas de tiempo (04-06), que forman parte de la evidencia.
Fases 4 a 6
Erradicación. No basta con borrar el binario: hay que encontrar cómo entró. El execve a las 03:11:58 desde el árbol de meteo-api apunta a la aplicación; con el identificador de correlación del apartado 4 se localiza la petición concreta que lo provocó y se identifica el fallo. Se corrige, se actualizan las dependencias, y se rotan todas las credenciales que el proceso podía leer —aunque auditd diga que no las leyó, porque la ausencia de un evento es una prueba más débil que su presencia—.
Recuperación. Restaurar los datos afectados desde la copia (05-03) verificando las sumas, volver a poner el servicio en producción, y mantener vigilancia reforzada durante semanas: alertas específicas sobre execve de meteora, sobre escrituras fuera de horario y sobre conexiones salientes nuevas. Si hubiera habido cualquier indicio de compromiso del núcleo o de acceso a root, la única opción defendible sería reinstalar desde cero, porque en un sistema con el núcleo comprometido no se puede confiar en nada de lo que el sistema dice de sí mismo.
Lecciones aprendidas. Una reunión sin buscar culpables, con una tabla de medidas concretas, cada una con responsable y fecha. Para este caso: noexec en /var/tmp (que habría impedido ejecutar el binario), SystemCallFilter sin execve en la unidad de meteo-api (que habría impedido lanzarlo), revisión del código de análisis de peticiones, alerta automática sobre execve con _UID=990, y cron deshabilitado para las cuentas de servicio.
Preservación de evidencias
Si el incidente puede tener consecuencias legales —denuncia, seguro, reclamación laboral, notificación a la autoridad de protección de datos—, la forma de recoger la evidencia determina si servirá de algo.
El orden de volatilidad dicta la secuencia de recogida, de lo más efímero a lo más duradero:
| Orden | Qué | Se pierde cuando |
|---|---|---|
| 1 | Registros y cachés de la CPU | Al instante |
| 2 | Memoria RAM: procesos, conexiones, claves, binarios borrados | Al apagar |
| 3 | Estado de red: conexiones, tabla ARP | En minutos |
| 4 | Procesos en ejecución | Al terminar o al reiniciar |
| 5 | Sistemas de ficheros temporales (/tmp, /run, /dev/shm) |
Al reiniciar (04-03) |
| 6 | Disco | Persiste |
| 7 | Copias de seguridad y registros remotos | Persiste fuera del alcance del atacante |
Por qué no apagar sin pensar. Un reinicio destruye los niveles 1 a 5 de esa tabla: toda la memoria, las conexiones activas, las claves de cifrado que solo existían en RAM, el contenido de /tmp y /dev/shm —incluido /dev/shm/meteora-cache— y los binarios borrados que solo eran accesibles a través de /proc. Es, con diferencia, la forma más rápida de perder la mitad de la investigación. Apagar solo se justifica si el daño en curso es mayor que el valor de la evidencia; en la mayoría de los casos, aislar la red contiene igual de bien y conserva todo.
# Volcado de memoria (requiere herramienta específica, p. ej. LiME) — ANTES de nada
# Imagen del disco: bit a bit, con verificación, y trabajando siempre sobre la COPIA
sudo dd if=/dev/sda of=/mnt/evidencia/meteo01-sda.img bs=4M status=progress conv=noerror
sha256sum /mnt/evidencia/meteo01-sda.img | tee /mnt/evidencia/meteo01-sda.sha256La suma de verificación es lo que da valor a la imagen: se calcula al copiar y se vuelve a calcular después, y si coincide demuestra que la imagen no se ha alterado desde su obtención. El análisis se hace siempre sobre una copia de trabajo, montada en solo lectura, nunca sobre el original ni sobre el sistema afectado.
Cadena de custodia. Es el registro documental de quién ha tenido la evidencia en cada momento, y sin ella una prueba técnicamente impecable puede ser inadmisible. Debe anotar, para cada elemento: qué es y de dónde salió, quién lo obtuvo y cuándo (con zona horaria), su suma de verificación, dónde se guarda, y cada transferencia con fecha, personas y motivo. Con acceso restringido y sin huecos.
Advertencia legal, y es importante. Un incidente de seguridad puede conllevar obligaciones formales con plazo: en el marco del RGPD, una brecha que afecte a datos personales exige notificar a la autoridad de control en un plazo muy breve, y en ciertos casos también a las personas afectadas. Puede haber además obligaciones sectoriales, contractuales y con la aseguradora. En cuanto se sospeche de una brecha con datos personales, involucra de inmediato a la asesoría jurídica y al responsable de protección de datos, y valora con ellos la denuncia ante las autoridades competentes. No borres nada, no negocies con un atacante por tu cuenta y no hagas públicas conclusiones antes de tenerlas confirmadas. Las decisiones sobre notificación, conservación de evidencias y comunicación no son decisiones técnicas.
Qué medidas preventivas deja cada incidente
Un incidente que no produce medidas concretas es un incidente que se repetirá. Esta es la traducción del caso de las 03:12, y sirve de modelo para cualquier otro:
| Hallazgo del incidente | Medida preventiva | Dónde se implementa |
|---|---|---|
Binario ejecutado desde /var/tmp |
noexec en /var/tmp, /tmp y /dev/shm |
/etc/fstab (05-03) |
meteo-api pudo lanzar un proceso |
SystemCallFilter sin execve; AppArmor sin reglas de ejecución |
Unidad de systemd (05-01, 05-03) |
Persistencia vía cron de meteora |
cron deshabilitado para cuentas de servicio |
/etc/cron.deny |
| Nadie lo detectó hasta las 09:00 | Alerta automática sobre execve con _UID=990 |
Colector y reglas de alerta |
| El binario estaba borrado | Alerta sobre procesos con exe (deleted) |
Comprobación periódica |
| El fallo estaba en el código | Revisión, sanitizers y actualización de dependencias | Integración continua (05-03) |
| La investigación fue lenta | Procedimiento escrito y ensayado | Fase de preparación |
Fíjate en el patrón: la mayoría de las medidas son directivas de configuración que ya conocías. La diferencia entre saberlas y tenerlas aplicadas es exactamente lo que separa un incidente contenido de un compromiso completo.
Errores Comunes y Consejos
No comprobar que el diario es persistente. Sin /var/log/journal, journald guarda en tmpfs y se pierde todo al reiniciar. Un atacante que reinicie borra el registro sin tocar un fichero. Verifícalo en cada servidor nuevo.
Registrar contraseñas o tokens "para depurar". Los fallos de contraseña suelen ser dedazos sobre la buena, así que el registro acaba conteniendo las credenciales reales en claro, legibles por el grupo adm, replicadas al colector y presentes en las copias.
Retener siete días. Un compromiso se detecta semanas después. Con siete días de retención, los registros del momento de la entrada ya no existen y nunca sabrás por dónde entraron.
Confiar en el registro local tras un compromiso. Un atacante con root lo modifica. Envía los eventos a un colector con credenciales distintas y en el momento, no por lotes.
Auditar demasiado con auditd. Una regla sobre lecturas y escrituras de /var/lib/meteora generaría millones de eventos diarios, llenaría el disco y añadiría latencia. Audita lo raro, no lo frecuente, y mide con aureport --summary.
Apagar el servidor al detectar un incidente. Destruye la memoria, las conexiones, /tmp y los binarios borrados accesibles solo por /proc. Aísla la red en su lugar.
Matar el proceso sospechoso. Elimina la evidencia y no resuelve nada: si hay persistencia, vuelve en minutos. Usa kill -STOP y busca el mecanismo de persistencia.
Guardar la base de referencia de AIDE en la propia máquina. Un atacante con root la regenera tras sus cambios y el informe saldrá limpio. Lo mismo con las listas de setuid y capabilities.
Olvidar create en logrotate. El fichero nuevo puede nacer con propietario o permisos incorrectos, y el servicio deja de poder escribir su propio registro. Y sin postrotate con reload, el proceso sigue escribiendo en el inodo antiguo.
Consejo: ensaya la respuesta antes de necesitarla. Un simulacro anual de dos horas —"aparece un proceso desconocido, ¿qué hacemos y en qué orden?"— revela que faltan los teléfonos, que nadie sabe dónde están las copias y que la retención es de siete días. Descubrir eso en un simulacro cuesta una mañana; descubrirlo en un incidente real cuesta muchísimo más.
Ejercicios
Ejercicio 1: auditar tu propio sistema de registro
Sobre una máquina propia o virtual: (a) comprueba si el diario es persistente y cuál es su retención real, y corrígelo si procede; (b) localiza los cinco últimos intentos fallidos de autenticación y los cinco últimos usos de sudo, indicando el comando usado en cada caso; (c) escribe tres consultas de journalctl que usen filtros por campo en lugar de grep, y explica qué ventaja tiene cada una; (d) calcula cuánto espacio ocuparía retener 90 días de tus registros actuales y decide una política de retención justificada, indicando qué aspectos consultarías con cumplimiento normativo.
Ejercicio 2: diseñar el registro y la auditoría de Meteora
Diseña el sistema de registro completo del servicio: (a) los eventos que meteo-api debe registrar, con sus campos, en formato estructurado, y al menos tres que no debe registrar nunca, con la razón; (b) el fichero de logrotate para /var/log/meteora/, justificando cada directiva; (c) cinco reglas de auditd para meteo-01, explicando qué detecta cada una y por qué no has incluido una regla sobre las escrituras de /var/lib/meteora/lecturas; y (d) el esquema de protección de la integridad de los registros, explicando qué aporta y qué no aporta cada capa frente a un atacante que ha obtenido root.
Ejercicio 3: respuesta a un incidente
A las 08:15 detectas: meteo-api reiniciándose en bucle cada pocos minutos; /var/lib/meteora al 98 % de ocupación cuando ayer estaba al 60 %; un fichero /var/lib/meteora/lecturas/README_RECOVER.txt; y los .dat de los últimos tres días con extensión .dat.locked. Redacta el plan de actuación completo por fases, con los comandos exactos en el orden correcto y la justificación de cada decisión. Indica expresamente: qué no debes hacer y por qué; qué evidencias preservas y en qué orden; cuándo y por qué involucras a asesoría jurídica; y las cinco medidas preventivas que dejaría este incidente.
Soluciones
Solución 1
# (a) Persistencia y retención
ls -ld /var/log/journal 2>/dev/null || echo "VOLÁTIL: se pierde al reiniciar"
journalctl --disk-usage ; journalctl --header | grep -i -A2 'sequential\|boot'
journalctl | head -1 # fecha de la entrada MÁS ANTIGUA = retención real
sudo mkdir -p /var/log/journal && sudo systemctl restart systemd-journald # corregir
# (b) Autenticación fallida y elevaciones
sudo journalctl _COMM=sshd -p warning -n 20
sudo lastb -F | head -5
sudo journalctl _COMM=sudo -n 5 -o short-full
# (c) Tres consultas por CAMPO
journalctl _UID=990 --since "-24h" # todo lo hecho por la identidad del servicio
journalctl _SYSTEMD_UNIT=ssh.service -p err # errores de una unidad concreta
journalctl _COMM=sudo _UID=1001 # elevaciones de un usuario concreto(a) La retención real no es la configurada, sino la que resulta de los topes de espacio: si SystemMaxUse se alcanza antes que MaxRetentionSec, journald borra lo antiguo y la ventana efectiva es menor de lo que crees. Por eso la comprobación válida es mirar la fecha de la entrada más antigua, no el fichero de configuración.
(c) La ventaja de los filtros por campo sobre grep es doble. Son precisos: _UID=990 selecciona los eventos que el núcleo atribuye a ese UID, mientras que grep 990 casaría también con un 990 que aparezca en un mensaje cualquiera. Y son no falsificables: los campos con guion bajo los añade journald tomándolos del sistema, no del texto del emisor, así que un proceso no puede mentir sobre su UID o su unidad, cosa que sí puede hacer con el contenido del mensaje.
(d) El cálculo es journalctl --disk-usage dividido por los días de retención actual, multiplicado por 90. La decisión debe equilibrar la ventana de investigación —90 días cubre el caso realista de detección tardía— con la minimización de datos, porque los registros contienen IP e identificadores de usuario, que son datos personales. Con cumplimiento normativo hay que consultar: la base legal del tratamiento, el plazo máximo justificable, si hay plazos mínimos obligatorios en el sector, cómo se atienden los derechos de acceso y supresión sobre los registros, y quién puede leerlos.
Solución 2
(a) Eventos de meteo-api:
{"ts":"2026-09-01T03:12:07.481+02:00","evento":"auth.fallo","resultado":"denegado",
"cliente":"CLI-4471","origen":"203.0.113.45","motivo":"token_caducado","traza":"7f3a9c21"}
{"ts":"2026-09-01T03:12:09.112+02:00","evento":"consulta.ok","resultado":"exito",
"cliente":"CLI-2210","recurso":"/lecturas/2026-08-31","filas":720000,"ms":184,"traza":"9a1b4e77"}
{"ts":"2026-09-01T03:12:11.004+02:00","evento":"config.recarga","resultado":"exito",
"actor":"uid=990","fichero":"/etc/meteora/meteora.conf","traza":"c2d8f013"}Registrar siempre: autenticaciones (con éxito y con fracaso, con su motivo), accesos a datos con el recurso y el volumen, cambios de configuración, arranques y paradas, y errores con contexto suficiente para reproducirlos.
Nunca, con la razón: contraseñas, incluidas las fallidas, porque la mayoría de los fallos son dedazos sobre la contraseña correcta y el registro acabaría conteniendo credenciales reales en claro; tokens y claves de API, porque quien lea el registro puede reutilizarlos directamente —y el registro lo lee el grupo adm, viaja al colector y entra en las copias—; y datos personales innecesarios como nombre y correo del cliente, que se sustituyen por el identificador CLI-4471 y una tabla de traducción con su propio control de acceso, aplicando el principio de minimización.
(b) El fichero de logrotate es el del apartado 5. Justificación por directiva: daily + rotate 90 fija la ventana de investigación en 90 días; compress reduce ~10:1 el espacio de los .log; delaycompress evita comprimir un fichero que aún puede estar abierto; create 0640 meteora adm es imprescindible porque sin ella el fichero nuevo puede nacer con propietario root y el servicio dejaría de poder escribir; y postrotate con reload existe porque tras renombrar, el proceso sigue escribiendo en el mismo inodo por su descriptor abierto (04-04), de modo que sin avisarle el fichero nuevo se queda vacío.
(c) Cinco reglas y qué detecta cada una:
-w /etc/meteora/secrets.conf -p rwa -k meteora_secretos # 1. LECTURA de las claves -w /etc/sudoers.d/ -p wa -k escalada # 2. reglas de sudo nuevas -a always,exit -F arch=b64 -S execve -F euid=990 -k meteora_exec # 3. ejecuciones del servicio -a always,exit -F arch=b64 -S init_module -S finit_module -k modulos # 4. módulos del núcleo -w /root/.ssh/ -p wa -k persistencia # 5. claves SSH de root -e 2
(1) detecta el acceso a los secretos, y lleva r porque en un fichero de claves leerlo ya es el evento. (2) detecta la concesión de privilegios nuevos. (3) es la que habría detectado el incidente de las 03:12 en el momento, porque meteo-api no debe ejecutar nada. (4) detecta el paso previo a un rootkit de núcleo. (5) detecta una de las persistencias más habituales.
No incluyo una regla sobre las escrituras de /var/lib/meteora/lecturas porque el ingestor escribe 720.000 lecturas diarias: generaría millones de eventos al día, llenaría el disco en horas y añadiría latencia a la ruta crítica del servicio, con un valor de detección prácticamente nulo, ya que esas escrituras son el funcionamiento normal. El criterio es auditar lo raro, no lo frecuente.
(d) Integridad de los registros:
| Capa | Qué aporta | Qué NO aporta |
|---|---|---|
chattr +a |
Impide truncar y modificar; obliga a un paso deliberado y auditable | Root puede quitarlo con CAP_LINUX_IMMUTABLE |
Permisos 0640 meteora:adm |
Aísla del resto de usuarios y servicios | Nada frente a root |
| Sellado FSS | Detecta manipulación con una clave guardada fuera | No la impide |
| Envío remoto inmediato por TLS | El evento ya está fuera del alcance del atacante | Requiere colector; si va por lotes, deja ventana |
| Credenciales de solo envío | El servidor no puede borrar lo ya enviado | Requiere infraestructura separada |
La conclusión que ordena la tabla: solo la última fila protege de verdad frente a un atacante con root, y las anteriores tienen valor real contra accidentes, contra usuarios sin privilegios y para detectar la manipulación a posteriori.
Solución 3
Lo que NO debes hacer, y por qué. No apagar ni reiniciar: destruiría la memoria, las conexiones, /tmp y /dev/shm, y con ellas posibles claves de cifrado en RAM que en algunos casos de ransomware permiten recuperar los datos sin pagar. No borrar los ficheros cifrados: son evidencia y a veces son recuperables. No restaurar la copia de seguridad de inmediato sobre el mismo sistema: si el atacante sigue dentro, cifrará también lo restaurado. No pagar ni negociar por iniciativa propia: es una decisión de dirección con implicaciones legales. Y no matar el proceso antes de haberlo documentado.
# --- FASE 2: análisis y preservación, por orden de volatilidad ---
mkdir -p /tmp/ev && date -Iseconds > /tmp/ev/hora.txt
ps auxf > /tmp/ev/ps.txt ; ss -tunap > /tmp/ev/red.txt ; sudo lsof -n > /tmp/ev/lsof.txt
cat /var/lib/meteora/lecturas/README_RECOVER.txt | tee /tmp/ev/nota.txt # solo LEER
sudo find /var/lib/meteora -name '*.locked' -newermt '-24 hours' -ls > /tmp/ev/cifrados.txt
sudo journalctl --since "-24h" > /tmp/ev/journal.txt
sudo ausearch --start recent -i > /tmp/ev/audit.txt
sudo grep -E 'sshd|sudo' /var/log/auth.log > /tmp/ev/auth.txt
df -h ; sudo du -sh /var/lib/meteora/* # el 98 % explica el bucle de reinicios
# --- FASE 3: contención sin destruir ---
sudo nft insert rule inet filter salida ip daddr != 10.0.1.0/24 drop # aislar red
sudo systemctl stop meteo-api ingestor agregador # parar el servicio, NO la máquina
PID=$(pgrep -f '<proceso sospechoso>') && sudo kill -STOP $PID
sudo mount -o remount,ro /var/lib/meteora # congelar el estado del volumenJustificación. El disco al 98 % explica el bucle de reinicios: meteo-api no puede escribir y Restart=on-failure lo relanza; es un síntoma, no la causa. La nota de rescate y las extensiones .locked confirman ransomware. Se aísla la red para cortar la comunicación con el atacante conservando el estado volátil; se para el servicio, que ya no funciona y solo añade ruido; se congela el proceso en lugar de matarlo para poder analizarlo; y se remonta el volumen en solo lectura para que no se cifre nada más. Las evidencias se recogen en el orden de volatilidad: memoria y procesos, luego red, luego ficheros temporales, y por último el disco.
Asesoría jurídica: inmediatamente, y en paralelo al análisis. Un ransomware implica casi con seguridad una brecha de datos personales, con posible obligación de notificar a la autoridad de control en un plazo muy breve, y quizá a los clientes afectados. Además hay que valorar la denuncia ante las autoridades competentes, las obligaciones contractuales con los clientes y la comunicación con la aseguradora. Nada de eso es una decisión técnica y todo tiene plazos.
Recuperación: reconstruir el servidor desde cero —no limpiar el existente, porque no se puede demostrar que no queda persistencia—, restaurar desde una copia anterior al compromiso verificando sumas, aplicar el endurecimiento de 05-03 antes de volver a exponerlo, rotar todas las credenciales, y mantener vigilancia reforzada.
Cinco medidas preventivas: (1) copias inmutables con credenciales separadas y retención forzada en destino, que es la única defensa real contra el ransomware; (2) prueba de restauración trimestral con tiempo medido; (3) alerta por volumen de escrituras fuera del patrón horario, que habría avisado a las 03:20 en lugar de a las 08:15; (4) noexec y ProtectSystem=strict para impedir la ejecución desde rutas de datos; y (5) procedimiento de respuesta escrito y ensayado, con los teléfonos, la ubicación de las copias y los pasos en orden, porque a las 08:15 de un incidente real no se improvisa.
Conclusión
Sin registro no hay detección, ni investigación, ni contención con criterio, ni aprendizaje: los controles preventivos de las tres lecciones anteriores necesitan controles detectivos al lado, porque la prevención falla alguna vez y, cuando falla en silencio, el atacante se queda semanas. En Linux, ese registro tiene dos caras: syslog, con sus facilidades y prioridades —auth y authpriv son las primeras que se miran— y su valor como lenguaje común de la industria; y journald, binario e indexado, cuya ventaja decisiva es que añade los metadatos por su cuenta y no puede mentir sobre ellos el emisor, lo que hace que journalctl _UID=990 --since "-24h" valga más que cualquier grep. Lo primero que hay que verificar en un servidor es que el diario sea persistente, porque en /run se pierde entero al reiniciar, y lo segundo, que la retención real cubra la ventana de investigación que necesitas —90 días, no siete—.
El registro de una aplicación se diseña: marca de tiempo con zona, evento de vocabulario cerrado, identidad, origen, objeto, resultado siempre, identificador de correlación y severidad, en formato estructurado. Y con una lista de exclusiones tan importante como la de inclusiones: nunca contraseñas —los fallos suelen ser dedazos sobre la buena—, nunca tokens ni claves, y datos personales minimizados a identificadores con una tabla de traducción aparte; todo ello con la política de retención acordada por escrito con cumplimiento normativo, porque una IP es un dato personal. La rotación con logrotate evita llenar el disco, y sus dos directivas críticas son create, que preserva permisos y propietario, y postrotate con reload, porque el proceso sigue escribiendo en el inodo antiguo por su descriptor abierto. auditd añade lo que el núcleo ve tanto si el programa quiere como si no —vigilancia de secrets.conf incluyendo la lectura, de sudoers, de execve con privilegio, de módulos y montajes, con -e 2 para hacer las reglas inmutables—, con la regla de oro de auditar lo raro y no lo frecuente, porque una regla sobre las escrituras del ingestor generaría millones de eventos diarios.
Sobre la integridad, la afirmación que hay que interiorizar es dura: un atacante con root modifica cualquier registro local, así que un registro local nunca es prueba suficiente. chattr +a, los permisos y el sellado FSS aportan protección frente a accidentes y detección a posteriori; lo único que protege de verdad es el envío inmediato a un colector con credenciales de solo envío, porque saca la evidencia del alcance del atacante en el momento en que se genera. En el host, AIDE detecta cambios en binarios y configuración —con reglas por tipo de fichero, exclusiones sensatas y la base de referencia fuera de la máquina—, y los indicadores manuales cubren lo demás: procesos con exe (deleted), puertos inesperados, setuid y capabilities nuevos, tareas y unidades desconocidas, y claves SSH recientes.
Y el ciclo de respuesta en seis fases —preparación, detección y análisis, contención, erradicación, recuperación, lecciones aprendidas— con sus dos errores capitales bien identificados: apagar el servidor, que destruye la memoria, las conexiones, /tmp y los binarios borrados accesibles solo por /proc, cuando aislar la red contiene igual y conserva todo; y matar el proceso, cuando kill -STOP lo congela y lo deja inspeccionable. El caso de las 03:12 mostró el método completo: foto del estado volátil primero por el orden de volatilidad, lectura de /proc/<PID>/ para descubrir el binario borrado y el UID 990, recuperación del binario desde /proc antes de que el proceso muera, ventana temporal en journalctl y ausearch, búsqueda de persistencia contra las listas de referencia, contención sin destruir y, al final, una tabla de medidas preventivas concretas con responsable y fecha. La preservación de evidencias —orden de volatilidad, imagen con suma de verificación, trabajo siempre sobre la copia, cadena de custodia sin huecos— y la advertencia legal: ante una brecha con datos personales hay plazos de notificación breves y decisiones que no son técnicas, así que la asesoría jurídica y el responsable de protección de datos entran desde el primer minuto.
Cierre del módulo 5
Merece la pena mirar el recorrido completo, porque el módulo ha tenido un hilo muy claro: de los mecanismos a la práctica, y de la prevención a la detección.
Empezamos con el marco (05-01): la distinción entre protección —mecanismo interno, demostrable— y seguridad —propiedad global frente a un adversario—, que impone la regla de que ningún mecanismo es una solución y todos son capas. Vimos los cuatro conceptos que describen cualquier control de acceso —sujetos, objetos, derechos y dominios de protección, donde lo interesante son los cambios de dominio—, la matriz de acceso con sus dos únicas implementaciones posibles —ACL por columnas y capacidades por filas, con el descubrimiento de que un descriptor de fichero es una capacidad—, los ocho principios de Saltzer y Schroeder aplicados uno a uno a Meteora, y los cuatro modelos DAC, MAC, RBAC y ABAC. Y los tres mecanismos que Linux pone encima de los nueve bits: las capabilities que trocean el "todo o nada" de root, SELinux y AppArmor que añaden una comprobación obligatoria que ni root se salta, y seccomp que reduce la superficie de syscalls de 350 a 40. Cerramos con la TCB, la superficie de ataque y el delegado confuso.
Después bajamos a la identidad (05-02): el UID como identidad real, los tres UID de cada proceso y el patrón de soltar privilegio, los tres ficheros de /etc campo a campo, el ciclo de vida de una cuenta con sus dos puntos de riesgo —la acumulación de privilegios y la baja incompleta, donde authorized_keys es lo que todo el mundo olvida—, las KDF con sal y coste que protegen las contraseñas, PAM con sus cuatro pilas, SSH con clave pública, y sudo con su lección más sutil: una regla no acota lo que el usuario puede hacer, sino lo que puede ejecutar.
Luego el adversario y el endurecimiento (05-03): el catálogo de amenazas con su indicio observable y los cuatro ejes comunes —proceso, puerto, fichero, conexión—, el modelo de amenazas como ejercicio que da criterio para priorizar, las clases de vulnerabilidad explicadas por su causa raíz, las defensas del sistema (ASLR, NX, canarios, PIE, RELRO) como capas que encarecen pero no arreglan, y el endurecimiento ordenado de meteo-01: actualizaciones, superficie mínima, cortafuegos con policy drop, aislamiento con systemd —el bloque de más valor por línea escrita—, montaje, límites, cifrado, secretos y copias 3-2-1 con su prueba de restauración.
Y esta última lección ha respondido a cómo se sabe que algo ha ocurrido, y qué hacer entonces.
Si el módulo 4 respondía a cómo se guarda algo para que siga estando mañana, el módulo 5 ha respondido a cómo se garantiza que solo quien debe pueda tocarlo, y cómo se sabe si alguien lo intentó. La respuesta ha tenido siempre la misma forma: capas independientes, cada una acotando una superficie distinta, ninguna suficiente por sí sola, y todas verificables con un comando concreto.
Pero fíjate en lo que hemos dado por supuesto durante cinco lecciones enteras. Hemos protegido meteo-01 como si fuera una máquina: un núcleo, un sistema de ficheros, un conjunto de procesos que comparten todo excepto lo que hemos separado a mano con permisos, capabilities, perfiles y directivas de systemd. Cada capa de este módulo ha sido, en el fondo, un intento de simular aislamiento dentro de un sistema que no está aislado. ProtectSystem=strict finge que el sistema de ficheros es de solo lectura; PrivateTmp finge que el /tmp es propio; IPAddressDeny finge que la red no existe.
¿Y si el aislamiento no hubiera que fingirlo? ¿Y si meteo-api pudiera ejecutarse con su propio sistema de ficheros, su propia tabla de procesos, su propia red, sin ver siquiera que existe el resto? ¿Y si el propio núcleo pudiera duplicarse, de modo que un compromiso total de un sistema operativo no alcanzara al de al lado? Eso ya no es control de acceso: es aislamiento, y es el siguiente nivel de defensa —además de la base sobre la que funciona toda la informática moderna en la nube—.
Es el Módulo 6: Virtualización y Contenedores, y empieza en Virtualización: Hipervisores y Máquinas Virtuales.
Fundamentos de Sistemas Operativos
Módulo 1: Introducción a los Sistemas Operativos
- Conceptos Básicos de Sistemas Operativos
- Historia y Evolución de los Sistemas Operativos
- Tipos de Sistemas Operativos
- Funciones Principales de un Sistema Operativo
- Arquitectura del Núcleo: Monolítico, Microkernel e Híbrido
- Modo Usuario, Modo Núcleo y Llamadas al Sistema
Módulo 2: Gestión de Recursos
- Gestión de Procesos
- Planificación de la CPU
- Gestión de Memoria
- Memoria Virtual y Paginación
- Gestión de Almacenamiento
- Gestión de Dispositivos
- Controladores, Interrupciones y Operaciones de E/S
Módulo 3: Concurrencia
- Conceptos de Concurrencia
- Hilos y Procesos
- Comunicación entre Procesos (IPC)
- Sincronización y Exclusión Mutua
- Problemas Clásicos de Concurrencia
- Interbloqueos: Prevención, Detección y Recuperación
Módulo 4: Estructuras de Archivos
- Sistemas de Archivos
- Estructuras de Directorios
- Particiones, Montaje y Sistema de Archivos Virtual
- Gestión de Archivos
- Asignación de Espacio, Journaling e Integridad
- Seguridad y Permisos de Archivos
Módulo 5: Protección y Seguridad del Sistema
- Principios de Protección y Control de Acceso
- Usuarios, Autenticación y Escalada de Privilegios
- Amenazas Comunes y Endurecimiento del Sistema
- Auditoría, Registros y Respuesta a Incidentes
Módulo 6: Virtualización y Contenedores
- Virtualización: Hipervisores y Máquinas Virtuales
- Contenedores: Namespaces y cgroups
- El Sistema Operativo en la Nube
- Sistemas Operativos Móviles y de Tiempo Real
