Detección y blue team
¿Qué es un SIEM? Logs, consultas y alertas
Un SIEM recopila logs, normaliza campos, ejecuta reglas de correlación y genera alertas para triaje. Aprende el recorrido con un ejemplo ejecutable.
Escribe una regla Sigma para fallos de inicio de sesión en Windows, valida, convierte a Splunk y prueba con eventos buenos y malos.
Sigma es un formato abierto y neutral respecto de proveedores para describir una detección. Escribes la lógica una vez, en un archivo YAML pequeño, y un conversor la transforma en el lenguaje de consulta del SIEM o de la plataforma de logs que realmente usas. Splunk, Elastic, Microsoft Sentinel y otros backends tienen conversores, y la misma regla puede generar consultas para varios de ellos.
El formato lo mantiene el proyecto SigmaHQ. La especificación está en el repositorio sigma-specification, y la documentación de reglas en sigmahq.io explica cada campo. Si sabes leer un evento de Windows, ya dominas la parte difícil. Una regla Sigma es solo una forma de decir "este evento, con estos valores de campo" de un modo que otras personas y otras herramientas puedan leer.
La mayor parte de la lógica de detección se escribe directamente en el lenguaje de consulta de un producto. Una búsqueda de Splunk no corre en Sentinel, y una consulta KQL no corre en Splunk. Cuando un equipo cambia de plataforma, o cuando la comunidad comparte una detección, la lógica hay que reescribirla desde cero. Eso es lento, y la reescritura introduce errores.
Sigma separa la lógica de detección del lenguaje de consulta. La regla describe la fuente de logs y la condición. El backend convierte eso en una consulta. De ahí salen dos consecuencias:
El segundo punto es el tema de este artículo. Una regla Sigma que se interpreta y se convierte no está terminada. Solo es sintácticamente correcta. Se vuelve útil cuando puedes demostrar que se activa en los eventos que debe activar y se queda callada en los que debe ignorar.
Esta es la regla que construirás en el laboratorio, con cada campo explicado.
title: Failed Logon Event
id: bd37e49d-15ab-4e88-a3fb-53594e831b27
status: experimental
description: Detects Windows Security event 4625 (an account failed to log on).
logsource:
product: windows
service: security
detection:
selection:
EventID: 4625
condition: selection
falsepositives:
- Users mistyping passwords
level: low
tags:
- attack.credential-access
- attack.t1110Tu UUID será distinto. Genera el tuyo con cualquier biblioteca de UUID, por ejemplo python -c "import uuid; print(uuid.uuid4())", y conserva ese valor cuando edites la regra después. El id es la forma en que otras herramientas siguen la misma regra entre versiones.
stable, test, experimental, deprecated y unsupported. Una regla nueva que aún no se ha probado en un entorno real va como experimental.product: windows y service: security apuntan al registro de seguridad de Windows. Otros campos, como category, permiten describir una clase de logs, por ejemplo la creación de procesos, sin nombrar el canal exacto.selection, es un conjunto de condiciones sobre campos. Los nombres de los campos son los que usa la fuente de logs.selection solo significa "eventos que coinciden con el bloque selection". Más adelante agregarás bloques de filtro y los combinarás con and y not.informational, low, medium, high y critical. Elige el nivel según lo que significa una coincidencia en tu entorno, no según lo llamativa que suene la técnica.attack. apunta a una táctica de MITRE ATT&CK, y attack.t1110 apunta a la técnica T1110, Brute Force.Dos observaciones sobre esta regla. Primero, EventID es el nombre del campo en el mundo Sigma, y se refiere al Event ID que lees en el Visor de eventos. Segundo, level: low es una decisión. Un fallo de inicio de sesión aislado es común. La regla tal como está se activa en cada 4625, así que un nivel bajo es el punto de partida honesto hasta que agregues un umbral.
Sigma no conoce tu SIEM. Lo conoce el backend. El conversor lee la detección, aplica un pipeline de procesamiento que renombra campos y añade restricciones de índice o de origen, y escribe una consulta en el lenguaje de destino.
Un pipeline de procesamiento es un conjunto de reglas de mapeo. Responde preguntas como: cuál es el nombre del campo del Event ID en Splunk, qué índice guarda los eventos de seguridad de Windows y qué sourcetype debe buscar la consulta. Sin pipeline, el conversor puede devolver el nombre del campo Sigma tal cual está escrito. Esa salida muchas veces no sirve en la plataforma que usas.
Cada backend tiene sus propios pipelines. Algunos son obligatorios, y el conversor se niega a continuar sin uno, salvo que pidas explícitamente omitirlo. Lo verás en el laboratorio.
La idea es simple: la regla sigue igual, y el pipeline la adapta a la plataforma. Cuando pasas de Splunk a otro SIEM, cambias el backend y el pipeline, no la detección.
El laboratorio corre en tu propia máquina. No necesitas un dominio, un controlador de dominio ni ningún sistema objetivo. Estás escribiendo y convirtiendo una regla. No estás generando fallos de inicio de sesión contra nada, y no debes intentarlo contra un sistema que no sea tuyo o para el que no tengas permiso escrito de prueba.
Este laboratorio se ejecutó en Windows 11 con Git Bash, Python 3.12 y el registro de seguridad predeterminado de Windows. Los comandos son los mismos en Linux y macOS, salvo la ruta del entorno virtual.
Crea una carpeta para el laboratorio y ejecuta:
python3 -m venv .venv
. .venv/bin/activate
pip install sigma-cliEn Windows con Git Bash, python3 puede no estar en el PATH. Usa la ruta completa a tu instalación de Python 3.12, o py -3.12. Además, el entorno virtual pone los scripts en .venv/Scripts en lugar de .venv/bin, así que actívalo con:
. .venv/Scripts/activateVerifica la instalación:
sigma versionEn la máquina usada para este artículo, sigma-cli 4.0.0 se instaló junto con pysigma 2.0.2 y Python 3.12.10. Tus versiones pueden ser más nuevas. Lo que vale es la salida de versión que veas en tu máquina, no los números de arriba.
Crea un archivo llamado failed_logon.yml con el contenido de la sección anterior. Genera tu propio UUID para el campo id. Guarda el archivo en UTF-8 y sin tabulaciones en la indentación del YAML.
sigma check failed_logon.ymlsigma check interpreta el archivo y ejecuta validadores. Detecta un campo que falta, una etiqueta mal formada, un estado o nivel desconocido y varios problemas de estilo.
En la máquina usada para este artículo, el paso de validación no terminó. El validador de etiquetas carga los datos de MITRE ATT&CK por red. La solicitud devolvió un error de gateway HTTP 504, y el error se repitió en cada reintento. La salida fue un traceback que terminaba en RuntimeError: Failed to load MITRE ATT&CK data, y el código de salida fue 1.
Eso es una dependencia de red, no un error de la regla. Deberías ver un resultado de aprobación, o una lista de problemas del validador, cuando los datos carguen. Si la validación falla con el mismo mensaje de MITRE, vuelve a intentarlo más tarde, o desde una red que pueda alcanzar la fuente de datos. No marques la regla como validada hasta que la comprobación termine.
Si la validación reporta problemas, lee cada uno. Corrige la regla, no el validador. Un problema con una etiqueta suele ser una errata, como attack.t1100 en lugar de attack.t1110.
sigma plugin install splunkEn la máquina usada para este artículo, el comando mostró Successfully installed plugin 'splunk' y pySigma version is compatible with sigma-cli.
sigma convert -t splunk --without-pipeline failed_logon.ymlLa salida fue:
Parsing Sigma rules
EventID=4625Así queda la regla antes de cualquier mapeo de Splunk. El nombre del campo sigue siendo el nombre Sigma, EventID. Una búsqueda en Splunk sobre eventos de Windows suele usar EventCode y un origen, así que esta consulta no encontraría los eventos que buscas con una configuración estándar del add-on de Windows.
Prueba la misma conversión sin --without-pipeline:
sigma convert -t splunk failed_logon.ymlEl conversor se detuvo y explicó que el backend de Splunk requiere un pipeline de procesamiento. El mensaje pedía añadir --without-pipeline solo si sabías lo que hacías. Aquí el pipeline es obligatorio, así que el conversor se niega a generar la consulta sin él. Lee ese mensaje como una protección.
Ahora añade el pipeline de Windows:
sigma list pipelines
sigma convert -t splunk -p splunk_windows failed_logon.ymlLa lista mostró tres pipelines de Splunk: splunk_windows, splunk_sysmon_acceleration y splunk_cim. La conversión con splunk_windows imprimió:
Parsing Sigma rules
source="WinEventLog:Security" EventCode=4625El pipeline cambió dos cosas. Mapeó EventID a EventCode y añadió una restricción de origen a WinEventLog:Security. El resultado es una consulta que una instancia de Splunk con el add-on de Windows puede ejecutar. Tu índice y tu sourcetype pueden ser distintos, así que tómalo como punto de partida y compruébalo con tus datos.
Probar también el pipeline CIM falló con Rule type not yet supported by the Splunk data model CIM pipeline!. No todas las reglas convierten con todos los pipelines. Un fallo así es información útil: la regla o el backend no encajan con el mapeo que pediste.
En el artículo sobre el registro de eventos de Windows, miraste un evento en el Visor de eventos. Ábrelo de nuevo y compáralo con la consulta:
Event ID. En la salida de Splunk aparece como EventCode, porque el pipeline lo convierte al nombre que usa el add-on de Windows.source de la consulta, WinEventLog:Security, corresponde al canal de Seguridad que leíste en el Visor de eventos.Si tu evento en el Visor tiene un Event ID distinto de 4625, la regla no lo va a encontrar. Ese es el comportamiento correcto. La regla trata de fallos de inicio de sesión, no de todos los eventos del registro.
Una regla que convierte sigue siendo una suposición hasta que la pruebas. La prueba mínima tiene dos mitades:
Sin los negativos, no tienes evidencia de que la regla sea específica. Sin los positivos, no tienes evidencia de que funcione.
En este laboratorio, la prueba usa un archivo pequeño de eventos sintéticos, events.json, con cinco entradas: dos eventos 4625 y tres que no deben coincidir. El script carga el bloque selection de la regla y revisa cada evento. Es una prueba simplificada. Muestra que la lógica de selección hace lo que escribiste. No reemplaza probar la consulta convertida con datos reales.
import json, sys
import yaml
rule = yaml.safe_load(open("failed_logon.yml", encoding="utf-8"))
events = json.load(open("events.json", encoding="utf-8"))
selection = rule["detection"]["selection"]
def selection_matches(event):
return all(str(event.get(k)) == str(v) for k, v in selection.items())
failures = 0
for ev in events:
got = "match" if selection_matches(ev) else "no match"
ok = got == ev["expect"]
failures += 0 if ok else 1
print(f"{'PASS' if ok else 'FAIL'} {ev['name']:<40} expected={ev['expect']:<9} got={got}")
print(f"{len(events) - failures}/{len(events)} passed")
sys.exit(1 if failures else 0)El archivo de eventos se ve así:
[
{"name": "known-bad: failed logon", "EventID": 4625, "expect": "match"},
{"name": "known-bad: failed logon, second try", "EventID": 4625, "expect": "match"},
{"name": "known-good: successful logon", "EventID": 4624, "expect": "no match"},
{"name": "known-good: logoff", "EventID": 4634, "expect": "no match"},
{"name": "known-good: process creation", "EventID": 4688, "expect": "no match"}
]Ejecútalo:
python test_failed_logon.pyEn la máquina usada para este artículo, la salida fue:
PASS known-bad: failed logon expected=match got=match
PASS known-bad: failed logon, second try expected=match got=match
PASS known-good: successful logon expected=no match got=no match
PASS known-good: logoff expected=no match got=no match
PASS known-good: process creation expected=no match got=no match
5/5 passedFíjate en lo que muestra esta prueba y en lo que no muestra. Muestra que la regla coincide con los eventos que debe capturar e ignora los que debe ignorar. No muestra que la regla sea buena. Una regla que coincidiera con todos los 4625 pasaría esta prueba, porque todos los 4625 del archivo deben coincidir. La prueba es útil, pero solo como piso mínimo.
El siguiente paso, en un entorno real, es ejecutar la consulta de Splunk convertida contra un periodo de logs de seguridad de Windows que sepas que contiene fallos de inicio de sesión y actividad normal. Cuenta los resultados y abre una muestra. Cada acierto debe ser un evento 4625. Si la consulta devuelve aciertos de otros Event ID, el pipeline o el mapeo de campos está mal.
Esta regla se activa en cada 4625. Una contraseña escrita mal produce un acierto, y también una cuenta de servicio con contraseña vencida que reintenta cada minuto. Un intento de fuerza bruta son muchos fallos contra la misma cuenta en poco tiempo, y la primera versión no puede expresarlo.
Sigma lo resuelve con reglas de correlación, definidas en una especificación aparte. Una regla de correlación no busca eventos por sí misma. Apunta a una o más reglas base por su name, agrupa sus coincidencias por un campo y aplica un conteo en una ventana de tiempo. El tipo event_count cuenta coincidencias, y condition: gte: 5 significa cinco o más. Pon las dos reglas en un mismo archivo, separadas por ---, y dale un name a la regla base:
title: Failed Logon Event
name: failed_logon_event
id: bd37e49d-15ab-4e88-a3fb-53594e831b27
status: experimental
description: Detects Windows Security event 4625 (an account failed to log on).
logsource:
product: windows
service: security
detection:
selection:
EventID: 4625
condition: selection
falsepositives:
- Users mistyping passwords
level: low
tags:
- attack.credential-access
- attack.t1110
---
title: Many Failed Logons For One Account
id: 3f6c1d52-8a0e-4b7e-9d2a-6c41e0b7a915
status: experimental
description: Five or more failed logons for the same target account within ten minutes.
correlation:
type: event_count
rules:
- failed_logon_event
group-by:
- TargetUserName
timespan: 10m
condition:
gte: 5
falsepositives:
- Service accounts with an expired password
level: mediumGuárdalo como multi.yml y conviértelo con el mismo pipeline:
sigma convert -t splunk -p splunk_windows multi.ymlLa salida fue:
Parsing Sigma rules
source="WinEventLog:Security" EventCode=4625
| bin _time span=10m
| stats count as event_count by _time TargetUserName
| search event_count >= 5La primera línea es la regla base. Las tres siguientes son la correlación: agrupar los eventos en ventanas de diez minutos, contar por TargetUserName y quedarse con los grupos de cinco o más. Los valores 5 y 10 minutos son provisionales. Elígelos a partir de tus datos y prueba el resultado con los mismos eventos buenos y malos. No todos los backends admiten todos los tipos de correlación, así que revisa la salida del conversor antes de depender de ella.
Conserva la primera versión de la regla. Es la línea base, y la comparación con la versión correlacionada muestra si el umbral ayuda.
EventID. Splunk usa EventCode después del pipeline. Mezclar los dos nombres en una misma regla causa fallos silenciosos.--without-pipeline es una opción deliberada, no un atajo. La salida puede no ejecutarse en tu plataforma.level: high en una regla ruidosa. La severidad debe reflejar lo que significa una coincidencia. Un evento común sin contexto debe empezar en bajo.sigma check revisa la estructura del archivo. No comprueba si la detección encuentra los eventos correctos.Cuando tengas una regla que valida, convierte y pasa sus pruebas, los siguientes pasos son directos:
|contains y |endswith, y el campo category.En resumen: una regla es una afirmación sobre eventos. Escribe la afirmación, conviértela y luego demuéstrala con eventos que deben coincidir y eventos que no deben coincidir.
Detección y blue team
Un SIEM recopila logs, normaliza campos, ejecuta reglas de correlación y genera alertas para triaje. Aprende el recorrido con un ejemplo ejecutable.
Detección y blue team
Lee el registro Security de Windows: auditoría, eventos 4624, 4625, 4634, 4672, 4688 y 1102, qué agrega Sysmon y un inicio de sesión fallido tuyo.