Rilevamento e blue team
Che cos'è un SIEM? Log, query e alert
Un SIEM raccoglie i log, li normalizza, applica regole di correlazione e genera alert per il triage. Segui la pipeline con un esempio che puoi eseguire.
Scrivi una regola Sigma per i logon Windows falliti, validala, convertila per Splunk e provala su eventi known-good e known-bad.
Sigma è un formato aperto e indipendente dai vendor per descrivere un rilevamento. Scrivi la logica una volta sola, in un piccolo file YAML, e un convertitore la traduce nel linguaggio di query del SIEM o della piattaforma di log che usi davvero. Splunk, Elastic, Microsoft Sentinel e altri backend hanno tutti un convertitore, e la stessa regola può puntare a più di uno.
Il formato è mantenuto dal progetto SigmaHQ. La specifica sta nel repository sigma-specification, e la documentazione delle regole su sigmahq.io spiega i campi uno per uno. Se sai leggere un evento Windows, la parte difficile la conosci già. Una regola Sigma è solo un modo per dire "questo evento, con questi valori nei campi" in una forma che altre persone e altri tool possono leggere.
La maggior parte della logica di rilevamento si scrive direttamente nel linguaggio di query di un singolo prodotto. Una ricerca Splunk non gira in Sentinel e una query KQL non gira in Splunk. Quando un team cambia piattaforma, o quando una community condivide un rilevamento, la logica va riscritta da zero. È un lavoro lento, e la riscrittura introduce errori.
Sigma separa la logica di rilevamento dal linguaggio di query. La regola descrive la sorgente dei log e la condizione. Il backend la trasforma in una query. Ne derivano due conseguenze:
Questo articolo parla del secondo punto. Una regola Sigma che passa il parsing e si converte non è finita: è solo sintatticamente corretta. Diventa utile quando puoi dimostrare che scatta sugli eventi giusti e resta muta su quelli da ignorare.
Questa è la regola che costruirai nel lab, con la spiegazione di ogni campo.
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.t1110Il tuo UUID sarà diverso. Generane uno con una qualsiasi libreria UUID, per esempio python -c "import uuid; print(uuid.uuid4())", e conservalo quando modifichi la regola in seguito. L'id è il modo in cui gli altri tool seguono la stessa regola da una versione all'altra.
stable, test, experimental, deprecated e unsupported. Una regola nuova, mai provata in un ambiente reale, va sotto experimental.product: windows e service: security puntano al registro eventi Security di Windows. Altri campi, come category, ti permettono di descrivere una classe di log, per esempio la creazione di processi, senza nominare il canale esatto.selection, è un insieme di condizioni sui campi. I nomi dei campi sono quelli della sorgente dei log, e i valori si confrontano con quei campi.selection da solo significa "gli eventi che corrispondono al blocco selection". Più avanti aggiungerai blocchi di filtro e li combinerai con and e not.informational, low, medium, high e critical. Scegli il livello in base a che cosa significa un riscontro nel tuo ambiente, non a quanto sembra spettacolare la tecnica.attack. punta a una tattica MITRE ATT&CK, e attack.t1110 punta alla tecnica T1110, Brute Force.Due note su questa regola. Primo, EventID è il nome del campo nel mondo Sigma, e si riferisce all'Event ID che leggi in Event Viewer. Secondo, level: low è una scelta. Un singolo logon fallito è comune. Così com'è scritta, la regola scatta su ogni 4625, quindi un livello basso è il punto di partenza onesto finché non aggiungi una soglia.
Sigma non conosce il tuo SIEM. Il backend sì. Il convertitore legge il rilevamento, applica una pipeline di elaborazione che rinomina i campi e aggiunge restrizioni di indice o di sorgente, e scrive una query nel linguaggio di destinazione.
Una pipeline di elaborazione è un insieme di regole di mappatura. Risponde a domande come: qual è il nome del campo Splunk per l'Event ID, quale indice contiene gli eventi Security di Windows, quale sourcetype deve cercare la query. Senza pipeline, un convertitore può restituire il nome del campo Sigma così com'è scritto. Spesso quell'output non è utilizzabile sulla piattaforma che usi.
Ogni backend ha le sue pipeline. Alcune sono obbligatorie, e il convertitore si rifiuta di continuare senza, a meno che tu non chieda esplicitamente di saltare la pipeline. Lo vedrai nel lab.
L'idea è semplice: la regola resta la stessa e la pipeline la adatta alla piattaforma. Quando passi da Splunk a un altro SIEM, cambi il backend e la pipeline, e il rilevamento resta com'è.
Il lab gira sulla tua macchina. Non ti servono un dominio, un domain controller né alcun sistema bersaglio. Stai scrivendo e convertendo una regola. Non stai generando logon falliti contro qualcosa, e non dovresti provarci contro un sistema che non è tuo o che non hai il permesso scritto di testare.
Questo lab è stato eseguito su Windows 11 con Git Bash, Python 3.12 e il registro Security predefinito di Windows. I comandi sono gli stessi su Linux e macOS, a parte il percorso dell'ambiente virtuale.
Crea una cartella per il lab, poi esegui:
python3 -m venv .venv
. .venv/bin/activate
pip install sigma-cliSu Windows con Git Bash, python3 potrebbe non essere nel path. Usa il percorso completo della tua installazione di Python 3.12, oppure py -3.12. L'ambiente virtuale mette poi i suoi script in .venv/Scripts invece che in .venv/bin, quindi attivalo con:
. .venv/Scripts/activateControlla l'installazione:
sigma versionSulla macchina usata per questo articolo, sigma-cli 4.0.0 si è installato con pysigma 2.0.2 e Python 3.12.10. Le tue versioni potrebbero essere più recenti. Nei tuoi appunti registra l'output della versione, non i numeri qui sopra.
Crea un file chiamato failed_logon.yml con il contenuto mostrato nella sezione precedente. Genera un UUID tuo per il campo id. Salva il file in UTF-8, senza tabulazioni nell'indentazione YAML.
sigma check failed_logon.ymlsigma check analizza il file ed esegue i validatori. Trova un campo mancante, un tag malformato, uno status o un level sconosciuto e diversi problemi di stile.
Sulla macchina usata per questo articolo, il controllo non è arrivato in fondo. Il validatore dei tag carica i dati di MITRE ATT&CK dalla rete. La richiesta ha restituito un HTTP 504 gateway timeout, e l'errore si è ripetuto a ogni tentativo. L'output era un traceback che terminava con RuntimeError: Failed to load MITRE ATT&CK data, e il codice di uscita era 1.
Il problema è una dipendenza di rete, la regola non c'entra. Una volta caricati i dati dovresti vedere un esito positivo o un elenco di problemi dei validatori. Se il controllo fallisce con lo stesso messaggio su MITRE, rilancialo più tardi o da una rete che raggiunge i dati a monte. Non segnare la regola come validata finché il controllo non finisce.
Se il controllo segnala problemi, leggili uno per uno. Correggi la regola, non il validatore. Un problema su un tag di solito indica un refuso, come attack.t1100 al posto di attack.t1110.
sigma plugin install splunkSulla macchina usata per questo articolo, il comando ha stampato Successfully installed plugin 'splunk' e pySigma version is compatible with sigma-cli.
sigma convert -t splunk --without-pipeline failed_logon.ymlL'output è stato:
Parsing Sigma rules
EventID=4625Questa è la regola prima di qualsiasi mappatura per Splunk. Il nome del campo è ancora quello Sigma, EventID. Una ricerca Splunk sugli eventi Windows di solito usa EventCode e una source, quindi questa query non troverebbe gli eventi che vuoi su una configurazione standard con l'add-on per Windows.
Prova la stessa conversione senza --without-pipeline:
sigma convert -t splunk failed_logon.ymlIl convertitore si è fermato spiegando che il backend Splunk richiede una pipeline di elaborazione. Il messaggio diceva di aggiungere --without-pipeline solo se sai quello che stai facendo. Qui la pipeline è obbligatoria, quindi il convertitore si rifiuta di produrre una query senza. Leggi quel messaggio come una protezione.
Ora aggiungi la pipeline per Windows:
sigma list pipelines
sigma convert -t splunk -p splunk_windows failed_logon.ymlL'elenco mostrava tre pipeline Splunk: splunk_windows, splunk_sysmon_acceleration e splunk_cim. La conversione con splunk_windows ha stampato:
Parsing Sigma rules
source="WinEventLog:Security" EventCode=4625La pipeline ha cambiato due cose. Ha mappato EventID su EventCode e ha aggiunto una restrizione di source su WinEventLog:Security. Il risultato è una query che un'istanza Splunk con l'add-on per Windows può eseguire. Indice e sourcetype potrebbero essere diversi nel tuo ambiente, quindi prendila come punto di partenza e verificala sui tuoi dati.
Anche il tentativo con la pipeline CIM è fallito, con Rule type not yet supported by the Splunk data model CIM pipeline!. Non tutte le regole si convertono con ogni pipeline. Un fallimento del genere è un'informazione utile: la regola o il backend non si adatta alla mappatura che hai chiesto.
Nell'articolo sul registro eventi di Windows hai guardato un evento in Event Viewer. Riapri quell'evento e confrontalo con la query:
Event ID. Nell'output di Splunk compare come EventCode, perché la pipeline lo mappa sul nome usato dall'add-on per Windows.source nella query, WinEventLog:Security, corrisponde al canale Security che hai letto in Event Viewer.Se il tuo evento in Event Viewer ha un Event ID diverso da 4625, la regola non lo intercetta, ed è il comportamento corretto. La regola riguarda i logon falliti, non tutti gli eventi del registro.
Una regola che si converte resta un'ipotesi finché non la provi. Il test minimo ha due metà:
Senza i negativi non hai prove che la regola sia specifica. Senza i positivi non hai prove che funzioni.
Per questo lab il test usa un piccolo file di fixture con eventi sintetici, events.json, con cinque voci: due eventi 4625 e tre eventi che non devono corrispondere. Lo script carica il blocco selection della regola e controlla ogni evento. È un test semplificato. Mostra che la logica della selection fa quello che hai scritto, e non sostituisce la prova della query convertita su dati reali.
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)Il file di fixture ha questo aspetto:
[
{"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"}
]Eseguilo:
python test_failed_logon.pySulla macchina usata per questo articolo, l'output è stato:
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 passedNota che cosa mostra questo test e che cosa no. Mostra che la regola corrisponde agli eventi giusti e ignora quelli da ignorare. Non mostra che la regola sia buona. Una regola che intercettasse ogni 4625 passerebbe questo test, perché ogni 4625 nella fixture deve corrispondere. Il test è utile, ma solo come soglia minima.
Il passo successivo, in un ambiente reale, è eseguire la query Splunk convertita su un periodo di log Security di Windows che sai contenere logon falliti e attività ordinaria. Conta i risultati e aprine un campione. Ogni riscontro dovrebbe essere un evento 4625. Se la query restituisce riscontri per altri Event ID, la pipeline o la mappatura dei campi è sbagliata.
Questa regola scatta su ogni 4625. Una sola password digitata male produce un riscontro, e lo stesso fa un account di servizio con la password scaduta che riprova ogni minuto. Un tentativo di brute force è una serie di fallimenti sullo stesso account in poco tempo, e la prima versione non può esprimerlo.
Sigma gestisce questo caso con le regole di correlazione, definite in una specifica separata. Una regola di correlazione non intercetta eventi da sola. Punta a una o più regole di base tramite name, raggruppa le loro corrispondenze per un campo e applica un conteggio su una finestra temporale. Il tipo event_count conta le corrispondenze, e condition: gte: 5 significa cinque o più. Metti entrambe le regole in un solo file, separate da ---, e dai un name alla regola di 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: mediumSalvalo come multi.yml e convertilo con la stessa pipeline:
sigma convert -t splunk -p splunk_windows multi.ymlL'output è stato:
Parsing Sigma rules
source="WinEventLog:Security" EventCode=4625
| bin _time span=10m
| stats count as event_count by _time TargetUserName
| search event_count >= 5La prima riga è la regola di base. Le tre righe successive sono la correlazione: raggruppa gli eventi in finestre di dieci minuti, li conta per TargetUserName, tiene i gruppi con cinque o più. I valori 5 e 10 minuti sono segnaposto. Sceglili in base ai tuoi dati e prova il risultato con gli stessi eventi known-good e known-bad. Non tutti i backend gestiscono tutti i tipi di correlazione, quindi controlla l'output del convertitore prima di farci affidamento.
Conserva la prima versione della regola. È la baseline, e il confronto con la versione correlata mostra se la soglia aiuta.
EventID. Splunk usa EventCode dopo la pipeline. Mescolare i due nomi in una regola provoca mancate corrispondenze silenziose.--without-pipeline è un flag da usare di proposito, non una scorciatoia. L'output potrebbe non girare sulla tua piattaforma.level: high per una regola rumorosa. La gravità deve riflettere che cosa significa un riscontro. Un evento comune e senza contesto dovrebbe partire basso.sigma check verifica la struttura del file. Non verifica se il rilevamento trova gli eventi giusti.Quando hai una regola che supera il controllo, si converte e passa i test, i passi successivi sono semplici:
|contains e |endswith, e il campo category.La versione breve: una regola è un'affermazione sugli eventi. Scrivi l'affermazione, convertila e poi dimostrala con eventi che devono corrispondere ed eventi che non devono.
Rilevamento e blue team
Un SIEM raccoglie i log, li normalizza, applica regole di correlazione e genera alert per il triage. Segui la pipeline con un esempio che puoi eseguire.
Rilevamento e blue team
Leggi il log Security di Windows: policy di audit, Event ID 4624, 4625, 4634, 4672, 4688 e 1102, cosa aggiunge Sysmon e un logon fallito da trovare da solo.