Salta al contenuto principale

01 - Sigma Rules: Logica di Detection Universale e Conversione SIEM

Scrivere Sigma rules per detection universale: sintassi YAML, logsource mapping e conversione automatica per Splunk, Elastic e Sentinel.

Cosa ne pensi di questo articolo?

01 - Sigma Rules: Logica di Detection Universale e Conversione SIEM
Detection EngineeringFoto:Brett SaylesPexels

In Breve

Scrivere Sigma rules per detection universale: sintassi YAML, logsource mapping e conversione automatica per Splunk, Elastic e Sentinel.

Sigma Rules: Logica di Detection Universale e Conversione SIEM

Nel mondo della cybersecurity difensiva, uno dei problemi più persistenti e sempre stato la frammentazione dei linguaggi di detection: ogni SIEM ha la sua sintassi proprietaria, ogni piattaforma richiede query diverse, e le regole scritte per Splunk non funzionano su Elastic, che a sua volta non e compatibile con Microsoft Sentinel. Il risultato e che i team SOC spendono enormi quantità di tempo a riscrivere le stesse logiche di rilevamento per ogni tool, anziche concentrarsi su ciò che conta davvero: trovare le minacce prima che causino danni.

Le Sigma rules nascono esattamente per risolvere questo problema. Introdotte da Florian Roth e Thomas Patzke, Sigma e oggi il formato standard de facto per scrivere regole di detection in modo portabile e indipendente dalla piattaforma. Una regola Sigma scritta una volta può essere automaticamente convertita in query Splunk SPL, Elasticsearch KQL, Microsoft Sentinel KQL, IBM QRadar, Chronicle YARA-L, e oltre 40 altri target. In questo articolo esploriamo la sintassi Sigma in profondi, i pattern di logsource mapping, le tecniche di modifica e conversione, e come integrare Sigma in una pipeline Detection-as-Code moderna.

Cosa Imparerai in Questo Articolo

  • Struttura completa di una Sigma rule: titolo, logsource, detection, condition
  • Logsource mapping: category, product, service e come si traducono nei SIEM
  • Modifiers avanzati: contains, startswith, endswith, re, base64offset
  • Aggregation conditions: count, sum, min, max per detection statistiche
  • Conversione automatica con sigma-cli verso Splunk, Elastic e Sentinel
  • Pattern per detection di lateral movement, persistence, exfiltration
  • Testing e validazione delle regole Sigma con dati sintetici
  • Gestione del repository Sigma aziendale con best practices

Cos'è Sigma e perchè e Diventato lo Standard

Sigma e un formato open, basato su YAML, per descrivere pattern di rilevamento su log di sicurezza in modo indipendente dalla piattaforma. Pensalo come YARA per i log: cosi come YARA permette di scrivere regole per file malevoli che funzionano su qualsiasi scanner, Sigma permette di scrivere regole di detection che funzionano su qualsiasi SIEM.

Il progetto SigmaHQ ospita oggi oltre 3.000 regole community coperte da continua manutenzione, mappate al framework MITRE ATT&CK, e pronte per essere convertite. La crescita e stata esplosiva: da strumento di nicchia per threat hunters, Sigma e diventato il linguaggio comune dei detection engineers professionisti. I vantaggi principali sono tre:

  • Portabilita: scrivi una regola, deployala su N SIEM diversi
  • Collaborazione: le regole sono leggibili da chiunque, indipendentemente dal SIEM in uso
  • Automazione: la conversione e completamente automatizzabile in CI/CD

Anatomia di una Sigma Rule

Una regola Sigma e un file YAML con campi ben definiti. Vediamo la struttura completa con un esempio reale che rileva l'uso di mimikatz attraverso Windows Event Logs:

title: Mimikatz Detection via Windows Security Events
id: 0d82df6e-0e4e-4fbb-a12b-6e7a00a9c7c3
status: stable
description: Detects mimikatz usage patterns via LSASS access events
  and command-line indicators
references:
  - https://github.com/gentilkiwi/mimikatz
  - https://attack.mitre.org/techniques/T1003/001/
author: Federico Calo
date: 2026/03/01
modified: 2026/03/09
tags:
  - attack.credential_access
  - attack.t1003.001
  - attack.defense_evasion
logsource:
  category: process_access
  product: windows
detection:
  selection_lsass:
    TargetImage|endswith: '\lsass.exe'
    GrantedAccess|contains:
      - '0x1010'
      - '0x1038'
      - '0x1400'
      - '0x143a'
  selection_mimikatz_cli:
    CommandLine|contains|all:
      - 'sekurlsa'
      - 'logonpasswords'
  filter_legitimate:
    SourceImage|startswith:
      - 'C:\Windows\System32\'
      - 'C:\Program Files\Windows Defender\'
  condition: (selection_lsass and not filter_legitimate) or selection_mimikatz_cli
falsepositives:
  - Legitimate security tools performing LSASS inspection
  - Antivirus and EDR solutions
level: high

Analizziamo ogni sezione nel dettaglio:

Campi Obbligatori e Metadati

Il blocco di metadati all'inizio della regola serve sia per documentazione che per automazione della gestione:

  • title: nome leggibile della regola. Deve essere univoco e descrittivo. Convenzione: "Verbo + Soggetto + Contesto"
  • id: UUID v4 univoco. Non cambia mai nel tempo, permette il tracking delle versioni e dei false positive reports
  • status: lifecycle della regola. I valori validi sono: stable, test, experimental, deprecated, unsupported
  • level: severita. Valori: informational, low, medium, high, critical
  • tags: lista di tag MITRE ATT&CK in formato attack.t<ID> per tecniche o attack.<tactic> per tattiche

Logsource: il Cuore della Portabilita

Il blocco logsource e la magia che rende Sigma portabile. Invece di specificare un index o data stream specifico del SIEM, definisce il tipo di log in modo astratto attraverso tre campi:

# Esempio 1: Windows Security Events
logsource:
  category: process_creation
  product: windows

# Esempio 2: Linux Authentication
logsource:
  category: process_creation
  product: linux

# Esempio 3: Web Server Logs
logsource:
  category: webserver
  # nessun product specifico: generico

# Esempio 4: Log specifico di un servizio
logsource:
  product: windows
  service: security

# Esempio 5: Log di rete
logsource:
  category: network_connection
  product: windows

# Esempio 6: Cloud Trail
logsource:
  product: aws
  service: cloudtrail

Il sistema di pipeline di sigma-cli traduce questi logsource astratti nei path concreti di ciascun SIEM. Per esempio, category: process_creation su product: windows diventa:

SIEM Target Traduzione del Logsource
Splunk source="WinEventLog:Security" EventCode=4688
Elasticsearch (ECS) event.category:process AND event.type:start
Microsoft Sentinel (KQL) SecurityEvent | where EventID == 4688
Chronicle (YARA-L) $event.metadata.event_type = "PROCESS_LAUNCH"

Detection: Selections e Conditions

Il blocco detection e dove si definisce la logica di rilevamento. Si compone di due parti: le selections (filtri sui campi dei log) e la condition (logica booleana che combina le selections).

detection:
  # Selection con match esatto su campo singolo
  selection_exact:
    EventID: 4625

  # Selection con lista di valori (OR implicito)
  selection_multi_value:
    CommandLine|contains:
      - 'net user'
      - 'net localgroup'
      - 'whoami'

  # Selection con match su tutti i valori (AND implicito con |all)
  selection_and_all:
    CommandLine|contains|all:
      - '-enc'
      - 'powershell'

  # Selection con regex
  selection_regex:
    CommandLine|re: '(?i)(invoke-mimikatz|sekurlsa::)'

  # Selection con wildcard
  selection_wildcard:
    TargetFilename|startswith: 'C:\Users\'
    TargetFilename|endswith: '.exe'

  # Filter per ridurre i falsi positivi
  filter_system_processes:
    ParentImage|startswith: 'C:\Windows\System32\'

  # Condition: logica booleana
  condition: selection_exact and (
    selection_multi_value or selection_and_all
  ) and not filter_system_processes

Modifiers Avanzati

I modifiers sono suffissi che si aggiungono ai nomi dei campi con il carattere pipe | per modificare il tipo di match. Conoscerli tutti e fondamentale per scrivere regole efficaci:

Modifier Descrizione Esempio
contains Substring match (wildcard ai due lati) CommandLine|contains: 'mimikatz'
startswith Match all'inizio del valore Image|startswith: 'C:\Users\'
endswith Match alla fine del valore Image|endswith: '\cmd.exe'
re Regex PCRE CommandLine|re: '(?i)sekurlsa'
base64offset Decodifica base64 con offset 0,1,2 CommandLine|base64offset|contains: 'IEX'
wide Match su Unicode wide strings CommandLine|wide|contains: 'sekurlsa'
all Tutti i valori della lista devono matchare CommandLine|contains|all: ['-enc', 'bypass']
windash Match sia con trattino che con slash CommandLine|contains|windash: '-Enc'
cidr Match su range CIDR per IP DestinationIp|cidr: '10.0.0.0/8'
lt, lte, gt, gte Comparazioni numeriche EventID|gte: 4624

Aggregation Conditions: Detection Statistica

Alcune detection richiedono di contare eventi in un certo intervallo di tempo, non di matchare un singolo evento. Sigma supporta le aggregation conditions per questi casi d'uso:

# Rilevare brute force: più di 10 login falliti in 60 secondi
title: Windows Brute Force Login Attempt
logsource:
  product: windows
  service: security
detection:
  selection:
    EventID: 4625
    LogonType: 3
  condition: selection | count() > 10
timeframe: 60s
falsepositives:
  - Users with expired passwords
level: medium

---

# Rilevare data exfiltration: upload anomalo per destinazione
title: Potential Data Exfiltration by Volume
logsource:
  category: network_connection
  product: windows
detection:
  selection:
    Initiated: 'true'
    DestinationPort:
      - 443
      - 80
  condition: selection | count(DestinationHostname) by SourceIp > 50
timeframe: 1h
level: high

---

# Port scan detection: molte porte diverse dallo stesso sorgente
title: Network Port Scan Detection
logsource:
  category: network_connection
detection:
  selection:
    EventID: 5156
  condition: selection | count(DestinationPort) by SourceAddress > 30
timeframe: 10m
level: medium

Conversione con sigma-cli: Guida Pratica

sigma-cli e lo strumento ufficiale per convertire le regole Sigma nei linguaggi di query dei SIEM. Installazione e uso di base:

# Installazione
pip install sigma-cli
pip install pySigma-backend-splunk
pip install pySigma-backend-elasticsearch
pip install pySigma-backend-microsoft365defender

# Verifica backend disponibili
sigma list backends

# Conversione base: Sigma -> Splunk SPL
sigma convert -t splunk -p splunk_windows rules/mimikatz.yml

# Output atteso:
# (source="WinEventLog:Microsoft-Windows-Sysmon/Operational"
#  EventCode=10 TargetImage="*\\lsass.exe"
#  GrantedAccess IN ("0x1010", "0x1038", "0x1400", "0x143a"))
# NOT (SourceImage="C:\\Windows\\System32\\*"
#      OR SourceImage="C:\\Program Files\\Windows Defender\\*")

# Conversione con pipeline personalizzata
sigma convert \
  -t splunk \
  -p splunk_windows \
  -p my_custom_field_mapping.yml \
  rules/

# Conversione per Elasticsearch con ECS
sigma convert \
  -t elasticsearch \
  -p ecs_windows \
  -f lucene \
  rules/credential_access/

# Conversione per Microsoft Sentinel (KQL)
sigma convert \
  -t microsoft365defender \
  -p microsoft365defender \
  rules/lateral_movement/

# Output in formato JSON per automazione
sigma convert \
  -t splunk \
  -p splunk_windows \
  --format-output json \
  rules/ > converted_rules.json

Attenzione: Pipeline e Field Mapping

Ogni organizzazione ha una propria normalizzazione dei log. Se i tuoi log non seguono lo schema standard (es. Sysmon per Windows), devi creare una pipeline personalizzata che mappa i campi Sigma ai campi reali del tuo SIEM. Senza questa mappatura, le regole convertite non funzioneranno.

Creare Pipeline Personalizzate

Le pipeline Sigma definiscono come mappare i campi astratti di Sigma ai campi concreti del tuo SIEM. Ecco come crearne una per un'infrastruttura che usa un formato di log custom:

# custom_pipeline.yml
name: Custom Windows Pipeline
priority: 20
transformations:
  # Rinominare campo Sigma -> campo reale nel SIEM
  - id: field_mapping_process
    type: field_name_mapping
    mapping:
      CommandLine: process.command_line
      Image: process.executable
      ParentImage: process.parent.executable
      User: user.name
      TargetImage: target.process.executable
      GrantedAccess: target.process.granted_access
    rule_conditions:
      - type: logsource
        category: process_creation

  # Aggiungere condizioni all'index di destinazione
  - id: index_condition
    type: detection_item_keyword
    keyword: 'index=windows_events'
    rule_conditions:
      - type: logsource
        product: windows

  # Sostituire valori nei campi
  - id: winlog_channel_map
    type: field_value_mapping
    field_name: winlog.channel
    mapping:
      'Security': 'security'
      'System': 'system'
      'Application': 'application'

Pattern di Detection per Casi d'Uso Comuni

Vediamo una raccolta di Sigma rules pronte per casi d'uso ad alta priorità, mappate alle tecniche MITRE ATT&CK più sfruttate:

Lateral Movement: Pass-the-Hash

title: Pass-the-Hash Attack Pattern
id: 6571d552-4c16-4f50-b5f6-11ae9d1b0a38
status: stable
description: Detects Pass-the-Hash attacks via anomalous NTLM authentication
tags:
  - attack.lateral_movement
  - attack.t1550.002
logsource:
  product: windows
  service: security
detection:
  selection:
    EventID: 4624
    LogonType: 3
    AuthenticationPackageName: NTLM
    KeyLength: 0
  filter_local:
    IpAddress:
      - '127.0.0.1'
      - '::1'
  filter_machine:
    SubjectUserName|endswith: '$'
  condition: selection and not filter_local and not filter_machine
falsepositives:
  - NTLMv1 authentication in legacy environments
level: high

Persistence: Scheduled Task Creation

title: Suspicious Scheduled Task Creation via CLI
id: 92a7b4f1-e6c9-4e1d-b7df-3c8e9a0b5d17
status: stable
description: Detects creation of scheduled tasks via command line
tags:
  - attack.persistence
  - attack.t1053.005
logsource:
  category: process_creation
  product: windows
detection:
  selection_schtasks:
    Image|endswith: '\schtasks.exe'
    CommandLine|contains|all:
      - '/create'
      - '/tr'
  selection_suspicious_location:
    CommandLine|contains:
      - 'C:\Users\Public\'
      - 'C:\ProgramData\'
      - '%TEMP%'
      - 'AppData\Local\Temp'
  filter_admin_tools:
    ParentImage|startswith:
      - 'C:\Windows\System32\'
      - 'C:\Program Files\Microsoft Deployment Toolkit\'
  condition: selection_schtasks and selection_suspicious_location
    and not filter_admin_tools
falsepositives:
  - Software installers creating scheduled maintenance tasks
level: high

Exfiltration: DNS Tunneling

title: Potential DNS Tunneling via High Subdomain Count
id: b7c3a9f1-d4e5-4a7b-9f2c-8d0e1b3c5a7f
status: experimental
description: Detects potential DNS tunneling via unusually long DNS queries
  or high number of unique subdomains
tags:
  - attack.exfiltration
  - attack.t1048.001
  - attack.command_and_control
  - attack.t1071.004
logsource:
  category: dns
detection:
  selection_long_query:
    QueryName|re: '^([a-zA-Z0-9]{32,}\.)+'
  selection_high_entropy:
    QueryName|re: '^[a-zA-Z0-9]{20,}\.[a-zA-Z0-9]{20,}\.'
  condition: selection_long_query or selection_high_entropy
  timeframe: 5m
falsepositives:
  - CDN providers with hashed subdomains
  - Legitimate DynamicDNS services
level: medium

Gestione del Repository Sigma Aziendale

Un repository Sigma aziendale ben organizzato e fondamentale per la scalabilità. Ecco la struttura raccomandata:

sigma-rules/
├── .github/
│   └── workflows/
│       ├── validate.yml          # Lint e validazione YAML
│       └── convert-deploy.yml    # Conversione e deploy
├── rules/
│   ├── windows/
│   │   ├── process_creation/
│   │   ├── security/
│   │   └── sysmon/
│   ├── linux/
│   │   ├── auth/
│   │   └── process/
│   ├── cloud/
│   │   ├── aws/
│   │   ├── azure/
│   │   └── gcp/
│   └── network/
│       ├── dns/
│       └── firewall/
├── pipelines/
│   ├── splunk_custom.yml
│   ├── elastic_ecs.yml
│   └── sentinel_kql.yml
├── tests/
│   ├── positive/               # Log che DEVONO triggherare
│   └── negative/               # Log che NON devono triggherare
└── scripts/
    ├── validate_rules.py
    ├── convert_all.py
    └── deploy_to_siem.py

Automazione: Script di Validazione e Conversione

Ecco uno script Python completo per validare e convertire in bulk le regole Sigma in un repository aziendale:

#!/usr/bin/env python3
"""
Sigma Rule Validator and Converter
Valida la sintassi YAML e converte le regole per tutti i SIEM target.
"""
import os
import sys
import json
import yaml
import uuid
import subprocess
from pathlib import Path
from dataclasses import dataclass, field
from typing import Optional

@dataclass
class ConversionResult:
    rule_path: str
    success: bool
    target: str
    output: str = ""
    error: str = ""

@dataclass
class ValidationResult:
    rule_path: str
    valid: bool
    errors: list[str] = field(default_factory=list)
    warnings: list[str] = field(default_factory=list)

REQUIRED_FIELDS = ['title', 'id', 'status', 'description', 'logsource', 'detection', 'level']
VALID_STATUSES = ['stable', 'test', 'experimental', 'deprecated', 'unsupported']
VALID_LEVELS = ['informational', 'low', 'medium', 'high', 'critical']

SIEM_TARGETS = [
    {"name": "splunk", "pipeline": "splunk_windows", "flag": "-t splunk"},
    {"name": "elastic", "pipeline": "ecs_windows", "flag": "-t elasticsearch"},
    {"name": "sentinel", "pipeline": "microsoft365defender",
     "flag": "-t microsoft365defender"},
]

def validate_sigma_rule(rule_path: Path) -> ValidationResult:
    """Valida una singola regola Sigma."""
    result = ValidationResult(rule_path=str(rule_path), valid=True)

    try:
        with open(rule_path, 'r', encoding='utf-8') as f:
            rule = yaml.safe_load(f)
    except yaml.YAMLError as e:
        result.valid = False
        result.errors.append(f"YAML parse error: {e}")
        return result

    # Check campi obbligatori
    for field_name in REQUIRED_FIELDS:
        if field_name not in rule:
            result.valid = False
            result.errors.append(f"Missing required field: {field_name}")

    # Validate UUID
    if 'id' in rule:
        try:
            uuid.UUID(str(rule['id']))
        except ValueError:
            result.errors.append(f"Invalid UUID format: {rule['id']}")
            result.valid = False

    # Validate status
    if 'status' in rule and rule['status'] not in VALID_STATUSES:
        result.warnings.append(
            f"Unknown status: {rule['status']}. "
            f"Valid: {VALID_STATUSES}"
        )

    # Validate level
    if 'level' in rule and rule['level'] not in VALID_LEVELS:
        result.valid = False
        result.errors.append(
            f"Invalid level: {rule['level']}. Valid: {VALID_LEVELS}"
        )

    # Check logsource ha almeno category o service
    if 'logsource' in rule:
        logsource = rule['logsource']
        if not any(k in logsource for k in ['category', 'service', 'product']):
            result.errors.append("logsource must have at least one of: category, service, product")
            result.valid = False

    # Check detection ha condition
    if 'detection' in rule and 'condition' not in rule['detection']:
        result.errors.append("detection block missing 'condition' field")
        result.valid = False

    # Warn su falsepositives mancanti per regole stable/high
    if rule.get('status') == 'stable' and rule.get('level') in ['high', 'critical']:
        if 'falsepositives' not in rule:
            result.warnings.append("Stable high-severity rule missing falsepositives documentation")

    return result

def convert_rule(rule_path: Path, target_config: dict) -> ConversionResult:
    """Converte una regola Sigma per un SIEM target."""
    cmd = [
        'sigma', 'convert',
        '-t', target_config['name'],
        '-p', target_config['pipeline'],
        str(rule_path)
    ]
    try:
        proc = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
        if proc.returncode == 0:
            return ConversionResult(
                rule_path=str(rule_path),
                success=True,
                target=target_config['name'],
                output=proc.stdout.strip()
            )
        else:
            return ConversionResult(
                rule_path=str(rule_path),
                success=False,
                target=target_config['name'],
                error=proc.stderr.strip()
            )
    except subprocess.TimeoutExpired:
        return ConversionResult(
            rule_path=str(rule_path),
            success=False,
            target=target_config['name'],
            error="Conversion timeout"
        )

def process_repository(rules_dir: str) -> dict:
    """Processa l'intero repository di regole Sigma."""
    rules_path = Path(rules_dir)
    results = {"validation": [], "conversion": {}, "summary": {}}

    rule_files = list(rules_path.rglob("*.yml"))
    print(f"Found {len(rule_files)} rules")

    valid_count = 0
    invalid_count = 0

    for rule_file in rule_files:
        val_result = validate_sigma_rule(rule_file)
        results["validation"].append({
            "path": str(rule_file.relative_to(rules_path)),
            "valid": val_result.valid,
            "errors": val_result.errors,
            "warnings": val_result.warnings
        })

        if val_result.valid:
            valid_count += 1
            for target in SIEM_TARGETS:
                if target['name'] not in results["conversion"]:
                    results["conversion"][target['name']] = []
                conv = convert_rule(rule_file, target)
                results["conversion"][target['name']].append({
                    "path": str(rule_file.relative_to(rules_path)),
                    "success": conv.success,
                    "output": conv.output if conv.success else None,
                    "error": conv.error if not conv.success else None
                })
        else:
            invalid_count += 1
            print(f"INVALID: {rule_file.name}")
            for err in val_result.errors:
                print(f"  ERROR: {err}")

    results["summary"] = {
        "total": len(rule_files),
        "valid": valid_count,
        "invalid": invalid_count,
        "conversion_rate": valid_count / len(rule_files) * 100 if rule_files else 0
    }

    return results

if __name__ == "__main__":
    rules_dir = sys.argv[1] if len(sys.argv) > 1 else "./rules"
    results = process_repository(rules_dir)

    output_file = "sigma_report.json"
    with open(output_file, 'w') as f:
        json.dump(results, f, indent=2)

    summary = results["summary"]
    print(f"\n=== SIGMA VALIDATION REPORT ===")
    print(f"Total rules: {summary['total']}")
    print(f"Valid: {summary['valid']} ({summary['conversion_rate']:.1f}%)")
    print(f"Invalid: {summary['invalid']}")
    print(f"Full report: {output_file}")

    sys.exit(0 if summary['invalid'] == 0 else 1)

GitHub Actions per CI/CD delle Sigma Rules

Integra la validazione e la conversione delle regole Sigma nella tua pipeline CI/CD:

# .github/workflows/sigma-pipeline.yml
name: Sigma Rules CI/CD

on:
  push:
    paths:
      - 'rules/**/*.yml'
      - 'pipelines/**/*.yml'
  pull_request:
    paths:
      - 'rules/**/*.yml'

jobs:
  validate:
    name: Validate Sigma Rules
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.12'

      - name: Install dependencies
        run: |
          pip install sigma-cli pySigma-backend-splunk \
            pySigma-backend-elasticsearch \
            pySigma-backend-microsoft365defender \
            pyyaml

      - name: Run validation
        run: python scripts/validate_rules.py ./rules

      - name: Upload validation report
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: sigma-validation-report
          path: sigma_report.json

  convert-and-deploy:
    name: Convert and Deploy Rules
    needs: validate
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4

      - name: Install sigma-cli
        run: pip install sigma-cli pySigma-backend-splunk

      - name: Convert rules for Splunk
        run: |
          sigma convert \
            -t splunk \
            -p splunk_windows \
            -p pipelines/splunk_custom.yml \
            --format-output savedsearches \
            rules/ > converted/splunk_rules.conf

      - name: Deploy to Splunk
        env:
          SPLUNK_HOST: ${{ secrets.SPLUNK_HOST }}
          SPLUNK_TOKEN: ${{ secrets.SPLUNK_TOKEN }}
        run: |
          python scripts/deploy_to_splunk.py \
            --rules converted/splunk_rules.conf \
            --host "$SPLUNK_HOST" \
            --token "$SPLUNK_TOKEN"

Best Practice: Sigma Rule Lifecycle

  • Inizia sempre con status: experimental e level: low per una nuova regola
  • Documenta i false positive noti nel campo falsepositives
  • Promuovi a stable solo dopo almeno 2 settimane di test in ambiente di staging con dati reali
  • Usa related per linkare regole correlate che coprono la stessa tecnica con approcci diversi
  • Mantieni un CHANGELOG per ogni regola: data, autore, motivo modifica

Sigma e MITRE ATT&CK: Coverage Mapping

Un uso avanzato di Sigma e la mappatura automatica della copertura ATT&CK. Con un semplice script e possibile analizzare il repository e generare un heatmap della copertura per tattiche e tecniche:

import yaml
import json
from pathlib import Path
from collections import defaultdict

def build_attck_coverage(rules_dir: str) -> dict:
    """
    Analizza il repository Sigma e genera statistiche
    di copertura per tecnica MITRE ATT&CK.
    """
    coverage = defaultdict(list)

    for rule_file in Path(rules_dir).rglob("*.yml"):
        with open(rule_file) as f:
            rule = yaml.safe_load(f)

        tags = rule.get('tags', [])
        rule_info = {
            "title": rule.get('title', ''),
            "status": rule.get('status', ''),
            "level": rule.get('level', ''),
            "file": str(rule_file)
        }

        for tag in tags:
            # Estrae solo i tag di tecnica ATT&CK: attack.t1234.001
            if tag.startswith('attack.t') and len(tag) > 9:
                technique_id = tag.replace('attack.', '').upper()
                coverage[technique_id].append(rule_info)

    # Calcola statistiche per livello di severita
    stats = {}
    for technique, rules in coverage.items():
        level_counts = defaultdict(int)
        for r in rules:
            level_counts[r['level']] += 1

        stats[technique] = {
            "rule_count": len(rules),
            "stable_count": sum(1 for r in rules if r['status'] == 'stable'),
            "levels": dict(level_counts),
            "rules": [r['title'] for r in rules]
        }

    return {
        "total_techniques_covered": len(coverage),
        "total_rules": sum(len(r) for r in coverage.values()),
        "techniques": stats
    }

coverage = build_attck_coverage("./rules")
print(f"Tecniche coperte: {coverage['total_techniques_covered']}")
print(f"Regole totali: {coverage['total_rules']}")

with open("attck_coverage.json", "w") as f:
    json.dump(coverage, f, indent=2)

Anti-Pattern da Evitare

Scrivere Sigma rules efficaci richiede di evitare alcuni errori comuni che portano a falsi positivi eccessivi o detection inefficaci:

Anti-Pattern Comuni

  • Regex troppo permissive: CommandLine|re: '.*' matcha tutto. Usa regex specifiche e anchorate
  • Mancanza di filtri: senza filter_ selections per processi legittimi, genererai migliaia di falsi positivi al giorno
  • Usare solo il nome del processo: gli attaccanti rinominano i binari. Usa hash, path completo E argomenti della command line
  • Non versionare le regole: senza id UUID e modified date, non puoi tracciare l'evoluzione delle regole
  • Status always experimental: le regole non vengono promosse e rimangono in limbo senza un processo di review formale
  • Campo level troppo alto: non tutto e "critical". Usa i livelli con parsimonia per preservare la priorità degli alert

Conclusioni e Prossimi Passi

Sigma rappresenta oggi lo stato dell'arte per la scrittura di detection logic portabile e collaborativa. Padroneggiare la sua sintassi, i modifier avanzati, e la conversione automatica e una competenza fondamentale per qualsiasi detection engineer moderno.

I punti chiave da ricordare:

  • La struttura logsource e il cuore della portabilita: una regola, N piattaforme
  • I modifier permettono match flessibili senza sacrificare la precisione
  • Le aggregation conditions abilitano detection comportamentali e statistiche
  • Un repository ben organizzato con CI/CD e prerequisito per la scalabilità
  • La mappatura ATT&CK automatizzata permette di misurare la copertura oggettivamente

Continua la Serie Detection Engineering

Nel prossimo articolo vedremo come costruire una pipeline Detection-as-Code completa con Git e CI/CD, automatizzando test, conversione e deployment delle regole.

Domande frequenti

Cos'è Sigma e perchè è diventato lo standard per la scrittura di regole di detection?

Sigma è un formato open basato su YAML che descrive pattern di rilevamento su log di sicurezza in modo indipendente dalla piattaforma, pensalo come YARA per i log.

Quali sono i vantaggi principali di utilizzare Sigma?

I vantaggi principali sono tre: la portabilità delle regole tra diverse piattaforme SIEM, la possibilità di scrivere regole in modo indipendente dalla piattaforma e l'accesso a oltre 3.000 regole community coperte da continua manutenzione.

Come funziona la conversione automatica delle regole Sigma nei linguaggi di query dei SIEM?

La conversione è gestita dallo strumento ufficiale sigma-cli, che traduce i logsource astratti nei path concreti di ciascun SIEM.

Quali sono gli errori comuni da evitare quando si scrivono regole Sigma efficaci?

Gli errori comuni includono falsi positivi eccessivi o detection inefficaci, che possono essere evitati con la conoscenza della sintassi di Sigma e dei modifier avanzati.

Fonti e approfondimenti

Prova Questi Strumenti

Strumenti gratuiti correlati a questo argomento.

Commenti

Caricamento commenti...

Accedi per commentare

Discuti questo articolo nella community

Unisciti al gruppo Telegram per discutere con altri sviluppatori, fare domande e condividere le tue esperienze.

Ti è piaciuto questo articolo?

Esplora altri contenuti sul blog o scopri i miei progetti