Tienes la auditoría avanzada activa, Sysmon corriendo con una configuración razonable y un agente de Wazuh instalado en las tres máquinas del laboratorio. Ninguna de esas tres cosas vale nada si el evento no sale del host. Este es el módulo menos vistoso del curso y, en la práctica, el que más incidentes reales explica cuando alguien pregunta por qué no saltó la alerta: casi nunca es porque la regla estuviera mal escrita, es porque el dato nunca llegó al motor que la ejecuta.
Aquí se cubre el tramo que va del canal de eventos local al SIEM: cómo funciona de verdad Windows Event Forwarding (colector, suscripciones, filtrado XPath, gestión con wecutil), cómo se registra y cifra un agente como el de Wazuh frente a alternativas como Elastic Agent o el Universal Forwarder de Splunk, cómo se configuran auditd y journald en Linux sin que una regla mal escrita dispare el volumen de golpe, y qué hace que syslog sea fiable o no según el transporte elegido. El objetivo final es simple de enunciar y difícil de lograr: saber, con una prueba y no con fe, que ningún evento se está perdiendo por el camino.
Qué aprenderás
- Diferenciar los modelos de recolección basados en agente y sin agente, y cuándo conviene cada uno.
- Configurar el servicio WinRM y el colector de Windows Event Forwarding, y crear suscripciones filtrando eventos con XPath.
- Gestionar suscripciones WEF con wecutil: crearlas, consultar su estado, cambiar su modo de entrega y depurarlas.
- Entender por qué las suscripciones se separan en niveles tipo Baseline y Suspect en vez de una sola suscripción gigante.
- Saber cómo se registra, cifra y pone en cola el agente de Wazuh, y en qué se diferencia de Elastic Agent, Winlogbeat y Splunk Universal Forwarder.
- Escribir reglas de auditd con auditctl, hacerlas persistentes y evitar las que disparan el volumen de registro sin avisar.
- Configurar journald para que reenvíe a rsyslog y elegir el transporte de syslog correcto (UDP, TCP o TLS) según lo que no te puedes permitir perder.
- Detectar cuándo un origen ha dejado de enviar telemetría, en vez de asumir que el silencio significa que no pasa nada.
- Estimar cuánto volumen de ingesta va a mover tu SIEM antes de desplegar, con una fórmula medida en tu propio laboratorio, no con una cifra memorizada.
El problema: la telemetría vale cero si no llega
Una regla de detección se valida contra un evento que existe en el SIEM. Si ese evento se generó en el endpoint pero nunca cruzó la red, la regla no tiene nada que evaluar: no es un falso negativo detectable, es un hueco invisible que nadie va a investigar porque nadie sabe que falta. Ese hueco es más frecuente de lo que parece porque casi ningún mecanismo de recolección avisa cuando pierde algo.
Windows Event Forwarding es el ejemplo más claro. La propia documentación de Microsoft sobre WEF lo dice sin rodeos: el registro de eventos local de la máquina origen es el único búfer que existe mientras dura un corte de conexión con el colector, y si ese registro se llena y empieza a sobrescribir eventos antiguos antes de que la conexión vuelva, no se envía ninguna notificación al colector de que se han perdido eventos ni de que hubo un hueco en la secuencia. El tamaño del canal, no un contador de pérdidas, es lo único que protege esa ventana.
Un agente como el de Wazuh se comporta distinto: mantiene su propia cola local (más adelante se ve con qué parámetros) y, si la cola se llena antes de vaciarse hacia el manager, empieza a descartar eventos, pero al menos hay un parámetro que se puede dimensionar y vigilar. La diferencia de fondo entre el modelo con agente y el modelo sin agente no es de gustos, es esta: cuánto control tienes sobre lo que pasa cuando la red falla.
| Modelo | Ejemplos | Qué se gana | Qué se pierde |
|---|---|---|---|
| Basado en agente | Agente de Wazuh, Elastic Agent, Winlogbeat, Splunk Universal Forwarder | Cola local propia ante cortes de red, cifrado y autenticación del canal gestionados por el propio agente, acceso a telemetría que solo se lee desde dentro del host (auditd, inventario del sistema) | Un binario más que desplegar, actualizar y vigilar en cada endpoint; el propio agente puede fallar o quedarse desactualizado |
| Sin agente | Windows Event Forwarding, syslog nativo de red y de electrodomésticos de red, lectura por API | No hay software adicional que instalar ni mantener en el equipo de origen | El propio log local es el único búfer, sin aviso cuando se sobrescribe; depende de que el protocolo de transporte (WS-Management, syslog) esté disponible y bien configurado en los dos extremos |
La elección entre uno y otro no siempre es excluyente. En el laboratorio de este curso el agente de Wazuh ya corre en el generador Windows y en el endpoint Linux desde el módulo 2; a partir de aquí se añade, donde tenga sentido, un segundo camino sin agente (WEF hacia un colector, syslog remoto desde rsyslog) para comparar los dos modelos con el mismo tráfico real.
Windows Event Forwarding: cómo funciona de verdad
Arquitectura: colector y origen
WEF tiene dos papeles. El colector (Windows Event Collector, WEC) es el servidor que recibe y almacena los eventos reenviados, normalmente en el log ForwardedEvents. El origen es cualquier equipo Windows que lee su propio registro de eventos y reenvía lo que coincide con una suscripción. La comunicación va sobre WS-Management, el mismo protocolo que usa WinRM para PowerShell remoto, así que activar WEF y activar la administración remota comparten buena parte de la fontanería.
Ya viste en el módulo anterior que existen dos modos de suscripción, source-initiated y collector-initiated; aquí toca configurarlos de verdad, con el servicio WinRM, la directiva de grupo y wecutil.
Configurar WinRM y el colector
En el equipo colector hacen falta dos comandos con privilegios elevados: uno deja el servicio WinRM escuchando (crea el listener HTTP en el puerto 5985 y abre la excepción de cortafuegos) y el otro prepara el servicio de colector de eventos (habilita el canal ForwardedEvents, pone el servicio en inicio retardado y lo arranca):
winrm qc -q
wecutil qc /q
Si el equipo origen y el colector están en el mismo dominio, con Kerberos disponible, el mismo winrm qc -q en el origen basta para el transporte: la conexión va autenticada y cifrada por Kerberos (con NTLM como alternativa si Kerberos no está disponible, aunque se puede desactivar por directiva de grupo), aunque en pantalla aparezca la opción HTTP sin TLS visible. Si el origen no está en el dominio del colector, hace falta HTTPS con certificados de cliente y de servidor; ese escenario exige más trabajo (abrir el puerto 5986, instalar certificados de autenticación en los dos extremos, mapear el certificado a una cuenta en el colector) y solo compensa cuando de verdad hay equipos fuera de dominio que reenviar.
Crear suscripciones en modo push con directiva de grupo
El modo source-initiated (push) escala mejor cuando el número de endpoints es alto o cambia con frecuencia: el colector publica una suscripción sin listar a mano cada origen, y son los propios clientes los que se apuntan, dirigidos por una directiva de grupo. Esa directiva vive en Configuración del equipo, Plantillas administrativas, Componentes de Windows, Reenvío de eventos, en la opción «Configurar el administrador de suscripciones de destino». El valor que se introduce ahí sigue un formato concreto:
Server=http://<FQDN-del-colector>:5985/wsman/SubscriptionManager/WEC,Refresh=60
El parámetro Refresh marca cada cuántos segundos el cliente vuelve a consultar al colector por si hay suscripciones nuevas o cambiadas; con HTTPS el mismo valor añade IssuerCA= con la huella del certificado emisor. Tras aplicar la directiva (gpupdate /force) y esperar al intervalo de refresco, el cliente se apunta solo a cualquier suscripción para la que tenga permiso.
En el colector, la suscripción se crea con un fichero XML y wecutil. Esta es una versión reducida, sin todos los campos opcionales, de una suscripción source-initiated real con un único filtro por creación de proceso:
<Subscription xmlns="http://schemas.microsoft.com/2006/03/windows/events/subscription">
<SubscriptionId>BaselineSOC</SubscriptionId>
<SubscriptionType>SourceInitiated</SubscriptionType>
<Enabled>true</Enabled>
<Uri>http://schemas.microsoft.com/wbem/wsman/1/windows/EventLog</Uri>
<ConfigurationMode>Normal</ConfigurationMode>
<Query>
<![CDATA[
<QueryList>
<Query Path="Security">
<Select>*[System[EventID=4688]]</Select>
</Query>
</QueryList>
]]>
</Query>
<ReadExistingEvents>false</ReadExistingEvents>
<ContentFormat>RenderedText</ContentFormat>
<LogFile>ForwardedEvents</LogFile>
<AllowedSourceDomainComputers>O:NSG:NSD:(A;;GA;;;DC)(A;;GA;;;NS)</AllowedSourceDomainComputers>
</Subscription>
wecutil cs baseline-soc.xml
Filtrar con XPath: sintaxis y su límite documentado
El filtro que decide qué eventos se reenvían es una expresión XPath 1.0, con las limitaciones propias que documenta Microsoft (solo eje hijo y atributo, sin espacios de nombres, sin conjuntos de nodos), colocada dentro de un elemento Select. Una consulta simple selecciona un tipo de evento de un canal:
<QueryList>
<Query Id="0" Path="Security">
<Select Path="Security">*[System[EventID=4688]]</Select>
</Query>
</QueryList>
Una compuesta combina condiciones con and u or, con los operadores de comparación escritos en su forma XML (>=, <=), como en este ejemplo adaptado de la propia guía de Microsoft para acotar por rango de identificador de evento:
*[System[Provider[@Name='Microsoft Antimalware'] and (EventID >= 1116 and EventID <= 1119)]]
Aquí hay un límite documentado que conviene conocer antes de escribir una consulta larga: si la expresión XPath compuesta supera 20 expresiones, o si hace falta seleccionar eventos de más de un canal a la vez, Microsoft exige pasar a una consulta XML estructurada, con varios elementos Query y su propio Select cada uno, en vez de una expresión gigante. Superar ese límite sin cambiar de formato no da un aviso claro, da un error de consulta inválida al crear la suscripción.
Gestión con wecutil
Todo el ciclo de vida de una suscripción se gestiona desde la línea de comandos con wecutil, sin necesidad del Visor de eventos:
wecutil es
wecutil gs BaselineSOC
wecutil gr BaselineSOC
wecutil ss BaselineSOC /e:true
wecutil ds BaselineSOC
En orden: es (enum-subscription) lista los nombres de todas las suscripciones que existen en el colector; gs (get-subscription) muestra su configuración completa; gr (get-subscriptionruntimestatus) muestra el estado real de cada origen conectado a esa suscripción, activo, con error o nunca conectado; ss (set-subscription) cambia parámetros, en este caso la habilita; y ds (delete-subscription) la borra. gr es el comando que de verdad importa para vigilar la tubería: sin él no hay forma de saber, desde el propio colector, si un origen concreto lleva horas sin reenviar nada.
El formato de entrega y el ritmo de envío también se ajustan por línea de comandos cuando ninguna de las tres opciones predefinidas del Visor de eventos (Normal, Minimizar ancho de banda, Minimizar latencia) encaja. Por ejemplo, para pasar al formato binario compacto (más barato que el texto renderizado por defecto, que puede doblar o triplicar el tamaño de cada evento porque incluye la descripción textual) y forzar un envío casi inmediato:
wecutil ss BaselineSOC /cf:Events
wecutil ss BaselineSOC /cm:Custom
wecutil ss BaselineSOC /dmi:1
wecutil ss BaselineSOC /dmlt:1000
/dmi fija cuántos eventos se acumulan como máximo antes de enviarlos en lote, y /dmlt el tiempo máximo en milisegundos que puede pasar sin enviar aunque el lote no se haya llenado. El equilibrio es el de siempre entre latencia y carga de red: valores bajos entregan casi en tiempo real a costa de más conexiones; valores altos ahorran ancho de banda a costa de retraso.
Suscripciones por niveles: Baseline y Suspect
Meter todos los eventos que interesan a un SOC en una sola suscripción gigante funciona en un laboratorio y se vuelve inmanejable en producción: cualquier cambio pequeño obliga a tocar una consulta enorme, y no hay forma de dar acceso más amplio a un subconjunto de máquinas sin dárselo a todas. La guía de Microsoft sobre WEF para detección de intrusiones resuelve esto con dos suscripciones separadas.
La suscripción Baseline se publica a todos los equipos sin excepción y cubre lo que interesa vigilar siempre: creación de procesos, eventos de AppLocker, instalación de servicios, cambios de cuenta local, borrado del registro de eventos, entre otros. La suscripción Suspect (la propia documentación también la llama Targeted en otros puntos del mismo texto) solo se activa en el subconjunto de máquinas bajo sospecha o vigilancia reforzada, y añade telemetría más ruidosa o más sensible: sesiones de red completas, eventos CAPI2 de certificados, ejecución de PowerShell, grupos asignados en el inicio de sesión. Al vivir en consultas separadas, ampliar Suspect a un host nuevo, por ejemplo porque una técnica de la matriz ATT&CK apareció en él, no toca ni el volumen ni la configuración de Baseline en el resto del parque, y viceversa.
Esa separación por niveles no es un capricho de organización, es una forma de acotar el coste. Ampliar la cobertura de un host que preocupa no debería significar multiplicar el volumen de los otros mil que no.
Límites de escalado documentados
Antes de decidir cuántos colectores hacen falta, conviene conocer los límites que la propia Microsoft documenta para un único servidor WEC en hardware convencional. La regla general de su guía es planificar para un total de 3.000 eventos por segundo de media entre todas las suscripciones configuradas en ese colector, con tres factores que la condicionan: la velocidad de escritura en disco del fichero .evtx (el colector no valida ni procesa el evento, solo lo escribe), el número de conexiones simultáneas que el propio colector puede sostener (los orígenes no mantienen conexión permanente, pero tampoco se desconectan de inmediato tras enviar), y el tamaño del registro de Windows donde se guarda la información de seguimiento de cada origen: por encima de 1.000 orígenes históricos el Visor de eventos empieza a ir lento al abrir el nodo de suscripciones, por encima de 50.000 hay que gestionarlo obligatoriamente con wecutil porque el Visor deja de ser viable, y por encima de 100.000 el registro deja de ser legible y hay que reconstruir el colector. Para volúmenes por encima de las decenas de miles de eventos por segundo, la misma guía apunta a repartir la carga entre varios colectores en vez de escalar uno solo en vertical.
Agentes: cómo funciona el de Wazuh y en qué se diferencian sus alternativas
Registro, cifrado y cola local del agente de Wazuh
En el módulo del laboratorio instalaste el agente pasando la variable WAZUH_MANAGER con la IP del manager, y con eso bastó para que apareciera activo. Lo que ocurrió por debajo es un proceso de enrolamiento: el agente, al arrancar sin clave todavía, se conecta contra el servicio wazuh-authd del manager por el puerto 1515 (el proceso completo lo documenta la guía de enrolamiento de agentes de Wazuh), un canal que sí usa TLS, y de ahí recibe una clave única que queda guardada en el manager (fichero client.keys) y en el propio agente. A partir de ese momento, el tráfico normal de eventos viaja por el puerto 1514 cifrado con el protocolo propio de Wazuh (AES, bloques de 128 bits, claves de 256 bits; Blowfish existe como alternativa configurable), no con TLS genérico, aunque la documentación de Wazuh también contempla TLS como opción para ese canal.
El enrolamiento automático por variable de entorno es cómodo mientras se confía en la red del laboratorio, pero cualquiera que conozca la IP del manager podría, en teoría, enrolar un agente falso durante esa ventana. Cuando hace falta control explícito sobre quién se registra, la alternativa es la herramienta agent-auth, que hace lo mismo a mano y admite una contraseña compartida o certificados de cliente:
/var/ossec/bin/agent-auth -A soc-lab-linux01 -m 10.0.0.5
Del lado del agente, el bloque client de ossec.conf define contra qué manager habla y con qué cifrado:
<client>
<server>
<address>10.0.0.5</address>
<port>1514</port>
<protocol>tcp</protocol>
</server>
<crypto_method>aes</crypto_method>
</client>
Justo debajo, el bloque client_buffer es la cola local que absorbe los picos de eventos antes de que el manager los reciba. Sus valores por defecto documentados son una cola de 5.000 eventos como máximo y un límite de envío de 500 eventos por segundo:
<client_buffer>
<disabled>no</disabled>
<queue_size>5000</queue_size>
<events_per_second>500</events_per_second>
</client_buffer>
Cuando la cola se llena (un pico de auditd mal ajustado, por ejemplo, o un corte de red prolongado), el agente empieza a descartar los eventos más nuevos hasta que hay hueco otra vez; desactivar el búfer del todo (disabled=yes) hace que el agente envíe sin ningún control de congestión, algo que la propia documentación desaconseja fuera de entornos muy pequeños porque puede saturar tanto al manager como a la red.
Elastic Agent, Winlogbeat y Splunk Universal Forwarder
El agente de Wazuh no es la única opción, y en un SOC real es habitual convivir con más de una según qué pila use cada equipo o cliente.
Elastic Agent es el agente unificado del stack Elastic: un único binario que, gestionado desde Fleet, despliega y configura por debajo los distintos Beats (incluido Winlogbeat, para el registro de eventos de Windows) o el Elastic Endpoint según la política asignada. El enrolamiento, tal como lo describe la guía de instalación de Elastic Agent gestionado por Fleet, requiere un token de Fleet generado en Kibana y, para producción, un certificado de autoridad de certificación que valide la conexión TLS contra el Fleet Server: sin esa CA, el agente falla la conexión con un error de certificado no confiable.
Winlogbeat también existe como binario independiente, sin pasar por Elastic Agent ni por Fleet: lee uno o varios canales de eventos de Windows mediante las API nativas, filtra según la configuración y envía directamente a Elasticsearch o a Logstash. Es la opción más ligera cuando no hace falta la gestión centralizada de Fleet.
Splunk Universal Forwarder sigue otra filosofía: por defecto envía datos «cocinados» (etiquetados con metadatos de origen, tipo de fuente y host, y troceados en bloques de 64 kilobytes) sin analizar ni indexar nada en el propio origen, lo que lo hace más ligero en recursos que un indexador completo. El receptor se apunta por línea de comandos y queda escrito en outputs.conf:
./splunk add forward-server 10.0.0.20:9997 -auth admin:changeme
[tcpout]
defaultGroup = soc-lab
[tcpout:soc-lab]
server = 10.0.0.20:9997
Ninguna documentación oficial de estos tres agentes publica cifras de rendimiento comparables entre sí en condiciones equivalentes, así que cualquier comparativa de ese tipo que circule por foros conviene tratarla con la misma sospecha que una regla de detección sin fuente. La elección real casi siempre depende de qué SIEM ya tienes desplegado y de si hace falta gestión centralizada de políticas o basta con reenviar.
Linux: auditd, journald y rsyslog
auditd: arquitectura y auditctl
auditd es el componente en espacio de usuario del subsistema de auditoría del kernel de Linux: recibe los eventos que el kernel genera cuando se cumple una regla activa y los escribe en disco, normalmente en /var/log/audit/audit.log. Las reglas no las carga auditd, las carga auditctl directamente en el kernel; auditd solo persiste lo que ya está pasando por el subsistema.
Hay un matiz de sintaxis que sorprende a quien aprendió auditd hace años: la forma clásica de vigilar un fichero con -w (watch) está marcada como obsoleta en la documentación actual de auditctl por su rendimiento pobre, y se recomienda convertirla a su forma equivalente basada en llamadas al sistema (-a con -F). Las dos reglas siguientes vigilan lo mismo, el fichero /etc/shadow ante escrituras y cambios de atributos, pero la segunda es la que la documentación actual recomienda:
auditctl -w /etc/shadow -p wa -k identity
auditctl -a always,exit -F arch=b64 -F path=/etc/shadow -F perm=wa -k identity
-a always,exit añade la regla a la lista de salida de llamada al sistema con acción de generar registro siempre; -F arch=b64 fija la arquitectura (hace falta una regla por arquitectura si el sistema es de 64 bits pero corre también binarios de 32); -F path y -F perm hacen el mismo trabajo que -w y -p pero por la vía no obsoleta; y -k pone una etiqueta arbitraria para poder filtrar después con ausearch -k identity.
Reglas persistentes y el volumen que puede disparar una mal escrita
Las reglas cargadas con auditctl directamente desaparecen al reiniciar. Para que sobrevivan hace falta escribirlas en un fichero dentro de /etc/audit/rules.d/ (con extensión .rules) y dejar que augenrules las combine en el fichero final que auditd carga al arrancar:
echo "-a always,exit -F arch=b64 -F path=/etc/shadow -F perm=wa -k identity" | sudo tee /etc/audit/rules.d/identity.rules
sudo augenrules --load
sudo auditctl -l
La advertencia real, y la razón por la que este apartado no es un simple copia y pega, es el volumen. Una regla de vigilancia de directorio sin acotar (por ejemplo, pensada como «quiero ver todos los cambios» sobre la raíz del sistema de ficheros) puede generar cientos de miles de eventos por minuto en un sistema con actividad normal, porque cualquier escritura en cualquier fichero del árbol cuenta. El propio kernel tiene un mecanismo de contención para cuando esto pasa: un límite de mensajes en cola, con 64 mensajes por defecto, y un límite opcional de mensajes por segundo; si cualquiera de los dos se supera, entra en juego el modo de fallo configurado (silencioso, aviso en el log del kernel, o pánico del sistema), que por defecto es el aviso. En la práctica, antes de dejar una regla nueva en producción conviene probarla en el laboratorio, medir cuántos eventos genera por minuto de actividad normal, y acotar el ámbito (un fichero concreto, un directorio concreto, un tipo de llamada al sistema concreto) hasta que el volumen sea el esperado, no una sorpresa.
journald y su relación con rsyslog
systemd-journald recoge por su cuenta los mensajes del kernel, de los propios servicios systemd y de cualquier programa que escriba en el socket de journal, y los guarda en un formato binario indexado. Por defecto en las distribuciones actuales su almacenamiento es persistente, bajo /var/log/journal, con reserva a memoria volátil si el disco no está disponible; el propio manual de journald.conf documenta también los modos «volatile» (solo memoria) y «auto» (persistente solo si el directorio ya existe).
journald no sustituye a rsyslog ni a un reenvío hacia el SIEM, solo guarda localmente. Para que ese contenido llegue a un colector remoto hace falta uno de dos caminos: activar ForwardToSyslog=yes en /etc/systemd/journald.conf, que hace que journald escriba también en el socket que rsyslog escucha, o dejar que sea el propio rsyslog el que lea el journal con su módulo de entrada imjournal. Los dos métodos a la vez suelen producir eventos duplicados, así que se elige uno:
[Journal]
Storage=persistent
ForwardToSyslog=yes
MaxLevelSyslog=info
Con eso, rsyslog recibe el contenido del journal como cualquier otro mensaje de syslog y puede aplicarle las mismas reglas de reenvío que al resto: a fichero local, a otro rsyslog remoto, o directamente al manager de Wazuh por su puerto de syslog.
Qué se recoge en la práctica
En un endpoint Linux típico de un SOC, lo que de verdad se envía suele salir de tres sitios distintos, no de todo /var/log sin criterio: el propio audit.log con las reglas de auditctl activas, el journal reenviado vía rsyslog (que incluye los intentos de sudo y de SSH), y cualquier log de aplicación específico que el host aloje, leído directamente por el agente con una regla de fichero de texto plano, como ya se hizo con el generador Windows en el módulo del laboratorio. Reenviar el árbol completo de /var/log sin decidir qué aporta señal solo multiplica el volumen sin mejorar la cobertura.
syslog como protocolo: formato y transporte
De RFC 3164 a RFC 5424
syslog nació como una convención de facto sin especificación formal, documentada más tarde y con carácter retrospectivo en la RFC 3164 («The BSD Syslog Protocol»), que el propio IETF describe como informativa: recoge cómo lo implementaba ya el software existente, no define un estándar. La versión de referencia hoy es la RFC 5424 («The Syslog Protocol»), publicada en marzo de 2009, de categoría Standards Track, que sustituye formalmente a la 3164: define una cabecera estructurada con marca de tiempo en formato ISO 8601 con zona horaria, un campo STRUCTURED-DATA para pares clave-valor sin depender de parsear texto libre, y UTF-8 como codificación. La diferencia práctica es esta: si el emisor y el receptor hablan 5424, el analizador del SIEM puede extraer campos sin adivinar el formato; si el emisor todavía habla 3164, algo frecuente en dispositivos de red y electrodomésticos que no se actualizan, hace falta una regla de parseo más frágil basada en posición y expresión regular.
Transporte: UDP, TCP y TLS
El formato del mensaje (3164 o 5424) es independiente del transporte que lo lleva, y ahí es donde de verdad se decide si vas a perder eventos sin enterarte.
| RFC | Contenido | Estado | Puerto por defecto |
|---|---|---|---|
| RFC 3164 | Formato de mensaje BSD syslog, el heredado | Informational, sustituida por la RFC 5424 | UDP/514 |
| RFC 5424 | Formato de mensaje estructurado (STRUCTURED-DATA, marca de tiempo ISO 8601) | Standards Track | Depende del transporte elegido |
| RFC 5426 | Transporte sobre UDP | Standards Track | UDP/514 |
| RFC 6587 | Transporte sobre TCP | Historic | Sin puerto asignado por IANA; por convención, TCP/514 |
| RFC 5425 | Transporte sobre TLS | Standards Track | TCP/6514 |
UDP fue el transporte histórico de syslog y sigue siendo el más usado por dispositivos de red y electrodomésticos que no ofrecen otra opción, pero no tiene entrega garantizada ni ningún mecanismo de reintento: si un paquete se pierde en la red, o si el receptor está momentáneamente ocupado y lo descarta, el mensaje desaparece sin que ni el emisor ni el receptor lo sepan. No hay confirmación, no hay cola, no hay forma de detectarlo desde el propio protocolo. TCP corrige la parte de la entrega punto a punto (el sistema operativo garantiza que los bytes llegan en orden o la conexión falla de forma visible), pero su estado formal, confirmado por la propia RFC 6587, es Historic: documenta una práctica ya existente, no un estándar cerrado, precisamente porque durante años cada implementación resolvía a su manera dónde empieza y dónde acaba un mensaje dentro del flujo TCP. TLS sobre TCP, especificado en la RFC 5425 con el puerto 6514 asignado por IANA como valor por defecto, añade cifrado y autenticación mutua opcional del canal; es el transporte recomendado cuando el syslog cruza una red que no controlas por completo.
La elección de transporte para una fuente concreta no es una preferencia técnica abstracta, es una respuesta a la pregunta de qué pasa si se pierde ese evento en concreto. Para telemetría de detección seria (autenticaciones, cambios de configuración, alertas de otro sistema de seguridad) UDP debería descartarse por defecto justo por eso: pierde en silencio.
Fiabilidad de la tubería: colas, contrapresión y pérdida silenciosa
Cada salto de la tubería de recolección (agente, colector WEF, rsyslog, el propio manager) tiene un límite de cuánto puede procesar por segundo y un tamaño finito de cola para absorber los picos por encima de ese límite. Cuando la cola se llena, hay varios comportamientos posibles y solo uno es bueno del todo: bloquear al emisor hasta que haya hueco (contrapresión, la opción más lenta pero la que no pierde nada), escribir en disco lo que no cabe en memoria (lo que hace rsyslog con sus colas asistidas por disco, que dejan de tocar el disco en cuanto la carga vuelve a niveles normales), o descartar directamente lo más nuevo (lo que hace el agente de Wazuh al superar queue_size, y lo que hace WEF cuando el propio registro de eventos se sobrescribe).
rsyslog resuelve esto con colas configurables por acción: una cola en memoria simple es la más rápida pero se vacía al reiniciar el proceso; una cola asistida por disco combina velocidad en condiciones normales con la capacidad de escribir a disco, limitada solo por el espacio libre, cuando el destino está caído o va más lento que la entrada, y recupera esos mensajes al arrancar de nuevo. Para un destino que se cae con cierta frecuencia (un enlace poco fiable, un SIEM que se reinicia para mantenimiento), una cola asistida por disco delante de la acción de envío marca la diferencia entre perder horas de registros o no perder ninguno.
Pero ninguna cola, por bien dimensionada que esté, avisa por sí sola de que un origen concreto ha dejado de enviar del todo. Eso hace falta detectarlo por el lado contrario: vigilando la ausencia de datos, no solo su contenido. Un origen que llevaba semanas mandando cientos de eventos por hora y de repente deja de aparecer en el SIEM es, en sí mismo, una señal (puede ser un fallo de red, un servicio caído, o alguien que desactivó el reenvío para tapar sus huellas; ese último caso ya es terreno del curso de DFIR y respuesta a incidentes, no de este módulo), y detectarlo exige una regla que dispare por falta de eventos en una ventana de tiempo, no por su presencia. WEF ayuda aquí con su latido: si un origen no tiene eventos nuevos que enviar, se conecta igualmente de forma periódica solo para confirmar que sigue activo, y ese latido es configurable por suscripción; el agente de Wazuh hace algo equivalente con su propio mensaje de estado hacia el manager. Cualquiera de los dos mecanismos permite escribir una regla de «origen silencioso» con una base real, en vez de adivinar cuánto tiempo sin eventos es sospechoso.
Sincronización horaria y zonas
Correlacionar eventos de dos máquinas distintas solo tiene sentido si el reloj de las dos está de acuerdo. Un desfase de unos pocos segundos entre el endpoint y el SIEM ya puede romper una regla de correlación que busca dos eventos relacionados dentro de una ventana corta (una autenticación seguida de un acceso a un recurso, por ejemplo); un desfase de minutos u horas, más habitual de lo deseable en máquinas virtuales que llevan tiempo apagadas o en entornos sin NTP bien configurado, puede hacer que un analista busque un evento en el rango de tiempo equivocado y concluya, sin razón, que no existe.
El protocolo de referencia para esto es NTP, especificado en su versión 4 por la RFC 5905, publicada en 2010. En Windows, el servicio W32Time sincroniza contra el controlador de dominio en un entorno de Active Directory; en Linux, chrony o ntpd cumplen el mismo papel contra un servidor de referencia. Lo que suele fallar no es la sincronización en sí (los sistemas operativos modernos la traen activa por defecto), sino la zona horaria: si el SIEM normaliza todo a UTC pero un origen queda mal configurado en hora local sin la zona correcta, cada evento de ese origen entra desplazado por un número fijo de horas, y ese desplazamiento no se nota hasta que alguien intenta correlacionar algo entre ese origen y el resto. La comprobación antes de dar por buena cualquier fuente nueva es simple: generar un evento con hora conocida en el origen y confirmar que llega al SIEM con la misma marca de tiempo en UTC, no solo que llega.
Dimensionar la ingesta
Antes de comprometerse con un plan de licencia, un tamaño de disco o un número de colectores, hace falta una cifra de cuánto volumen se va a mover, y esa cifra no sale de una tabla genérica encontrada por ahí: sale de medirla en el propio laboratorio con la configuración real que se va a desplegar. La fórmula en sí es sencilla:
volumen_diario_bytes = num_endpoints * eventos_por_segundo_por_endpoint * tamano_medio_evento_bytes * 86400
Los dos factores que de verdad varían, y que solo se conocen midiendo, son los eventos por segundo por endpoint (dependen del rol de la máquina, de qué auditoría y qué Sysmon tiene activos, y de si es un puesto de usuario o un servidor con tráfico constante) y el tamaño medio del evento (cambia mucho entre un evento de Windows en formato «RenderedText», con la descripción textual incluida, y el mismo evento en un formato compacto de un agente moderno). Para medirlos con lo que ya hay montado en el laboratorio: cuenta cuántos eventos entraron en el SIEM desde un host concreto durante un periodo conocido de uso normal, ni recién instalado ni en reposo total, y divide entre los segundos de ese periodo; para el tamaño, toma el tamaño medio del documento indexado o del evento almacenado en ese mismo periodo.
La guía de WEF de Microsoft, aunque piensa en términos de eventos por segundo agregados en el colector y no por endpoint, da una referencia útil de a qué escala corresponde cada tipo de almacén: hasta unos pocos miles de eventos por segundo en total, una base de datos convencional o un gestor de eventos de seguridad sencillo aguantan; por encima de eso y hasta varias decenas de miles, hace falta ya un gestor de eventos de seguridad dimensionado para ese volumen; y a partir de ahí, un sistema pensado para ingesta masiva tipo Hadoop o un lago de datos. Es una orientación de a qué escala aproximarse, no un sustituto de medir el propio caso. NIST SP 800-92, la guía de gestión de logs de seguridad informática, sigue siendo de 2006 (su revisión 1 permanece en fase de borrador inicial) y no da una fórmula de dimensionado como tal, pero insiste en el mismo principio de fondo: planificar la capacidad de almacenamiento y de red a partir de una estimación medida y revisada con el tiempo, no de una cifra fijada una vez y olvidada.
Ejercicio: demostrar que no se pierde ningún evento
El objetivo es configurar el reenvío desde una máquina Windows y desde una Linux hasta el SIEM del laboratorio, y demostrarlo con un recuento, no con una impresión. Reutiliza las tres máquinas ya montadas: el generador Windows, el endpoint Linux y el nodo central con el manager de Wazuh.
Parte Windows: WEF de origen a colector
- En el propio generador Windows (para no necesitar una segunda máquina, va a hacer de origen y de colector a la vez; en producción viven separados, pero el mecanismo es idéntico), prepara WinRM y el servicio de colector:
winrm qc -q wecutil qc /q - Crea un fichero
baseline-soc.xmlcon la suscripción source-initiated de la sección anterior, filtrando por creación de procesos, y créala:wecutil cs baseline-soc.xml - Genera un número conocido de eventos de prueba, por ejemplo 50 procesos:
for ($i=1; $i -le 50; $i++) { Start-Process cmd.exe -ArgumentList "/c exit" -WindowStyle Hidden } - Espera al intervalo de refresco de la suscripción y cuenta cuántos eventos con Event ID 4688 llegaron al log
ForwardedEventsen esa ventana:Get-WinEvent -FilterHashtable @{ LogName='ForwardedEvents'; Id=4688 } | Measure-Object
Si el recuento no coincide con los 50 generados (puede ser mayor, porque Windows arranca procesos propios de fondo, o menor, si algo falló), el hueco puede estar en tres sitios: la suscripción no está activa (wecutil gr baseline-soc lo confirma), la subcategoría de auditoría Process Creation no está activa en el origen, o el intervalo de refresco todavía no ha pasado. Verifica cada uno en tu propio entorno; el número exacto que veas depende de la actividad de fondo de tu máquina en ese momento.
Parte Linux: auditd, rsyslog y el manager como receptor de syslog
- En el manager de Wazuh, añade un bloque de escucha syslog al
ossec.confdel servidor, apuntando a la IP del endpoint Linux:<remote> <connection>syslog</connection> <port>514</port> <protocol>tcp</protocol> <allowed-ips>10.0.0.20/32</allowed-ips> </remote> - En el endpoint Linux, apunta rsyslog a ese receptor por TCP (la sintaxis clásica de rsyslog usa una arroba doble para forzar TCP en vez de UDP) y recarga el servicio:
echo '*.* @@10.0.0.5:514' | sudo tee /etc/rsyslog.d/60-soc-lab.conf sudo systemctl restart rsyslog - Genera un número conocido de eventos con
logger, que escribe en el journal y de ahí pasa a rsyslog:for i in $(seq 1 200); do logger -t soc-drill "evento de prueba numero $i"; done - Cuenta cuántos llegaron realmente al lado que recibe. Con acceso al fichero donde el sistema receptor archiva el syslog entrante, un recuento simple basta para comparar contra los 200 enviados:
grep -c "soc-drill" /var/log/syslog
Repite el mismo recuento después de simular un corte: detén rsyslog un momento, sigue generando eventos con el bucle de logger, y vuelve a arrancarlo. Con UDP como transporte, los eventos generados durante el corte desaparecen sin dejar rastro; con TCP, rsyslog los mantiene en su cola (en memoria, o en disco si el corte se alarga) y los entrega en cuanto la conexión vuelve. Comparar los dos transportes con el mismo experimento, en tu propio laboratorio, es la mejor demostración de por qué UDP no es la opción por defecto para telemetría que importa.
Preguntas frecuentes
¿Qué suscripción WEF debería crear primero, Baseline o Suspect?
Baseline. Es la que se publica a todo el parque y sostiene la detección diaria; Suspect solo tiene sentido una vez que hay un motivo concreto, un host con un hallazgo previo o un servidor especialmente sensible, para ampliarle la cobertura. Crear primero Suspect sin Baseline deja sin vigilancia al resto de la organización mientras se afina un caso puntual.
¿Por qué mi suscripción WEF aparece como activa pero no llegan eventos?
Con wecutil gr se ve el estado real del origen, pero que aparezca activo solo significa que la conexión WS-Management funciona, no que haya eventos que coincidan con el filtro. Las causas más comunes son una consulta XPath que no coincide con nada real en ese momento, la subcategoría de auditoría correspondiente sin activar en el origen, o el valor ReadExistingEvents en falso, que hace que WEF solo reenvíe eventos generados después de que el origen recibiera la suscripción, no los que ya existían en el log.
¿El agente de Wazuh pierde eventos si se corta la red un rato?
No de inmediato: primero absorbe el corte con su cola local (client_buffer, 5.000 eventos por defecto) y reintenta la conexión. Si el corte dura más que lo que tarda esa cola en llenarse al ritmo de generación de eventos de ese host, empieza a descartar los eventos más nuevos hasta que hay hueco otra vez. Para un host muy ruidoso conviene subir queue_size a mano en vez de asumir que el valor por defecto siempre alcanza.
¿Tiene sentido usar UDP para syslog hoy en día?
Para volumen bajo y fuentes donde perder algún evento suelto no cambia nada (métricas de estado, algún log informativo) sigue siendo una opción válida por su sencillez, y muchos dispositivos de red y electrodomésticos no ofrecen otra cosa. Para telemetría de la que depende una detección (autenticación, cambios de configuración, alertas de otro producto de seguridad), no: UDP no tiene forma de avisar de una pérdida, así que cualquier hueco es indetectable salvo que se vigile la ausencia de eventos por otro camino.
¿Cómo sé si un origen ha dejado de enviar telemetría sin mirarlo a mano cada día?
Con una regla que dispare por ausencia, no por presencia: si un host llevaba semanas generando un volumen medible de eventos por hora y ese volumen cae a cero, o por debajo de un umbral razonable, durante una ventana determinada, eso es en sí mismo un caso de uso de detección, no solo un problema de infraestructura aparte. WEF y el agente de Wazuh ya traen un mecanismo de latido periódico, y ese latido es la base real para construir esa regla, en vez de inventar un umbral de tiempo sin medir cómo se comporta cada fuente en condiciones normales.
