Saltar al contenido
Nuevo

DeepSeek V4.1 Flash gratis por 7 días: 10M tokens al día tras cualquier recarga. Hasta el 30/11.

Cómo funciona

Cómo escribir una regla Sigma: tu primera detección, probada

Escribe una regla Sigma para fallos de inicio de sesión en Windows, valida, convierte a Splunk y prueba con eventos buenos y malos.

Intermedio14 min de lecturaPor NotHoly

Qué es una regla Sigma

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.

Por qué importa

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:

  • Una regla puede compartirse, revisarse y versionarse como texto, igual que revisas código.
  • La misma regla puede probarse contra eventos de ejemplo antes de llegar a un SIEM de producción.

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.

Las partes de una regla

Esta es la regla que construirás en el laboratorio, con cada campo explicado.

yaml
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.t1110

Tu 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.

  • title es un nombre corto y legible. Aparece en las alertas y en las listas de reglas.
  • id es un UUID que identifica la regla, no el contenido. Mantenlo estable cuando cambies la lógica.
  • status indica al lector cuánto confiar en la regla. Los valores permitidos son stable, test, experimental, deprecated y unsupported. Una regla nueva que aún no se ha probado en un entorno real va como experimental.
  • description dice qué busca la regla, en una o dos frases.
  • logsource indica de dónde vienen los eventos. 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.
  • detection contiene la lógica de coincidencia. Cada bloque con nombre, aquí selection, es un conjunto de condiciones sobre campos. Los nombres de los campos son los que usa la fuente de logs.
  • condition dice cómo se combinan los bloques. 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.
  • falsepositives enumera los casos legítimos que también van a coincidir. Escribirlo forma parte de la regla, no es un detalle para después.
  • level es la severidad que recibe la regla cuando se activa. Los valores permitidos son 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.
  • tags vinculan la regla con frameworks. El prefijo 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.

Cómo se asocia Sigma con el lenguaje de un SIEM

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.

Laboratorio práctico: escribir, validar y convertir la regla

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.

Paso 1: crear un entorno virtual e instalar sigma-cli

Crea una carpeta para el laboratorio y ejecuta:

bash
python3 -m venv .venv
. .venv/bin/activate
pip install sigma-cli

En 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:

bash
. .venv/Scripts/activate

Verifica la instalación:

bash
sigma version

En 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.

Paso 2: escribir la regla

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.

Paso 3: validar la regla

bash
sigma check failed_logon.yml

sigma 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.

Paso 4: instalar el backend de Splunk

bash
sigma plugin install splunk

En la máquina usada para este artículo, el comando mostró Successfully installed plugin 'splunk' y pySigma version is compatible with sigma-cli.

Paso 5: convertir sin pipeline

bash
sigma convert -t splunk --without-pipeline failed_logon.yml

La salida fue:

text
Parsing Sigma rules
EventID=4625

Así 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.

Paso 6: convertir con el pipeline de Splunk

Prueba la misma conversión sin --without-pipeline:

bash
sigma convert -t splunk failed_logon.yml

El 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:

bash
sigma list pipelines
sigma convert -t splunk -p splunk_windows failed_logon.yml

La lista mostró tres pipelines de Splunk: splunk_windows, splunk_sysmon_acceleration y splunk_cim. La conversión con splunk_windows imprimió:

text
Parsing Sigma rules
source="WinEventLog:Security" EventCode=4625

El 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.

Paso 7: comparar con el evento que generaste

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:

  • El campo Event ID en el Visor de eventos debe ser 4625. Ese es el valor que busca la selección de Sigma.
  • El nombre del campo en el Visor es Event ID. En la salida de Splunk aparece como EventCode, porque el pipeline lo convierte al nombre que usa el add-on de Windows.
  • El 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.

Prueba la regla

Una regla que convierte sigue siendo una suposición hasta que la pruebas. La prueba mínima tiene dos mitades:

  • Eventos conocidos como malos. Eventos que la regla debe capturar. Para esta regla, son eventos 4625.
  • Eventos conocidos como buenos. Eventos que la regla no debe capturar. Los inicios de sesión correctos (4624), los cierres de sesión (4634) y la creación de procesos (4688) son buenos negativos.

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.

python
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í:

json
[
  {"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:

bash
python test_failed_logon.py

En la máquina usada para este artículo, la salida fue:

text
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 passed

Fí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.

La regla todavía no está terminada

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:

yaml
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: medium

Guárdalo como multi.yml y conviértelo con el mismo pipeline:

bash
sigma convert -t splunk -p splunk_windows multi.yml

La salida fue:

text
Parsing Sigma rules
source="WinEventLog:Security" EventCode=4625

| bin _time span=10m
| stats count as event_count by _time TargetUserName

| search event_count >= 5

La 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.

Errores comunes

  • Escribir la regla y saltarse los negativos. Una regla solo con pruebas positivas puede coincidir con todo y aun así pasar. Agrega eventos buenos a propósito.
  • Nombrar el campo con la etiqueta del Visor de eventos. Sigma usa EventID. Splunk usa EventCode después del pipeline. Mezclar los dos nombres en una misma regla causa fallos silenciosos.
  • Convertir sin pipeline y confiar en la salida. --without-pipeline es una opción deliberada, no un atajo. La salida puede no ejecutarse en tu plataforma.
  • Usar 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.
  • Olvidar el campo falsepositives. Si no puedes nombrar un caso legítimo, probablemente todavía no has pensado lo suficiente en el entorno.
  • Cambiar el id al editar la lógica. El id debe identificar la regla a lo largo del tiempo. Una regla nueva recibe un id nuevo. Una regla editada conserva el suyo.
  • Tomar una validación aprobada como prueba. sigma check revisa la estructura del archivo. No comprueba si la detección encuentra los eventos correctos.

Cómo seguir

Cuando tengas una regla que valida, convierte y pasa sus pruebas, los siguientes pasos son directos:

  • Ajusta la regla de correlación con datos reales: cambia el umbral y la ventana de tiempo, y compara aciertos y falsos positivos con la regla base.
  • Lee el resto de la especificación de Sigma para ver filtros, modificadores como |contains y |endswith, y el campo category.
  • Convierte la misma regla a un segundo backend, como Elastic o Splunk SPL2, y compara las consultas. Anota dónde el pipeline cambia la lógica y dónde solo renombra campos.
  • Arma un conjunto de eventos de prueba más grande, incluyendo eventos de un laboratorio donde controlas la actividad. Genera fallos de inicio de sesión solo en cuentas y sistemas que sean tuyos, y solo en un laboratorio donde tengas permiso para probar.

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.

Fuentes

Fuentes

  1. SigmaHQ, Sigma specification
  2. SigmaHQ, Sigma rules documentation
  3. SigmaHQ, sigma-cli
  4. MITRE ATT&CK, T1110 Brute Force
  5. SigmaHQ, Sigma correlation rules specification

Más en Detección y blue team

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.

Principiante14 min de lectura