Perché conta
Con Suricata rispondi alla domanda “questo pacchetto corrisponde a una firma nota?”. È una domanda utile ma limitata: un C2 con un dominio nuovo, TLS valido e traffico a basso volume non ha firme. Quello che lo tradisce è il comportamento: connessioni a intervalli regolari, un client che parla con un solo host ogni 60 secondi per giorni, un certificato self-signed su una porta insolita.
Zeek (ex Bro) nasce per questo: non è un motore di firme ma un analizzatore di traffico che trasforma i pacchetti in log strutturati ed eventi programmabili. È la base del Network Security Monitoring (NSM): raccogliere sempre i metadati di rete, così quando arriva un indicatore (un IP, un hash, un dominio) puoi ricostruire retroattivamente chi ha parlato con chi. Zeek è complementare al SIEM: produce il log di rete che il SIEM correla con quelli degli host.
Come funziona
Zeek legge da un’interfaccia (o da un pcap), ricostruisce i flussi e fa il parsing dei protocolli in
un event engine. Ogni cosa riconosciuta genera un evento (connection_state_remove, dns_request,
ssl_established); gli script nel policy layer reagiscono agli eventi e scrivono nel Logging framework
o sollevano un Notice.
flowchart LR
P[Pacchetti / pcap] --> E[Event engine<br/>reassembly + parsing]
E -->|eventi| S[Script Zeek<br/>policy layer]
S --> L[Log TSV/JSON<br/>conn dns http ssl files]
S --> N[Notice framework<br/>alert]
L --> SIEM[(SIEM / data lake)]
N --> SIEM
Ogni connessione ha un uid che la lega a tutti gli altri log: da una riga di conn.log salti al
dns.log che ha risolto il nome e al ssl.log con il certificato. È questo, più dei singoli campi,
che rende Zeek uno strumento di investigazione.
| Log | Contenuto | Perché serve |
|---|---|---|
conn.log |
Ogni flusso L3/L4: IP, porte, durata, byte, conn_state |
Baseline, beaconing, exfiltration |
dns.log |
Query, risposte, rcode | DGA, DNS tunneling |
ssl.log |
SNI, versione TLS, cert chain | Cert anomali, ECH |
http.log |
Metodo, host, URI, user-agent | Downloader, user-agent sospetti |
files.log |
Hash (MD5/SHA1) dei file in transito | Malware noto, IOC retroattivi |
L’attacco
Un impianto C2 tipico fa beaconing: a intervalli fissi interroga il server per ricevere comandi. Per non essere banale aggiunge jitter, cioè un ritardo casuale. Simuliamo un beacon da 60 s con jitter del 10%:
|
|
Un analista umano non lo nota nel mare di traffico; un conteggio di byte nemmeno (sono pochi). Ma gli intervalli sono troppo regolari per essere traffico umano. Misuriamo la regolarità con il coefficiente di variazione degli intervalli $\Delta t_i$ tra connessioni successive della stessa coppia origine-destinazione:
$$ CV = \frac{\sigma(\Delta t)}{\mu(\Delta t)} $$
Per navigazione umana $CV$ è alto (> 1: raffiche e pause); per un beacon con jitter del 10% è circa $0{,}06$. Una soglia come $CV < 0{,}2$ con almeno 20 campioni isola i candidati con pochi falsi positivi (restano timer legittimi: NTP, update checker, monitoring, da mettere in allowlist).
La difesa
Prima il deployment: Zeek in modalità JSON, sulla porta mirror dello switch (vedi packet analysis) o su un TAP.
|
|
Poi lo script. Per ogni coppia orig/resp teniamo gli ultimi timestamp e, a ogni nuova connessione, calcoliamo $CV$ degli intervalli:
|
|
Le righe evidenziate sono quelle che contano: la tabella con &create_expire (la memoria è limitata, senza
scadenza lo stato crescerebbe all’infinito), il calcolo di $CV$, la NOTICE e la soppressione degli alert
duplicati con $suppress_for. Caricalo da local.zeek con @load ./beacon e inoltra notice.log al
SIEM. Zeek ha già pacchetti maturi per questo (vedi zkg nel link sopra): in produzione conviene partire da lì
e usare lo script come base didattica.
Tre accorgimenti operativi:
- Dimensiona l’hardware sul traffico: oltre ~1 Gbit/s serve un cluster con più worker e il load balancing per flusso (AF_PACKET).
- Cifratura: il payload TLS è opaco, ma
conn.log,ssl.loge le tempistiche restano visibili; per questo il beaconing si vede anche su HTTPS. - Retention: i metadati costano poco. Tenere 90 giorni di
conn.logvale più di 3 giorni di pcap completi.
Lab
Scarica un pcap di traffico con beacon (o genera il tuo con lo script curl sopra, catturando con
tcpdump -i br0 -w beacon.pcap) e rispondi:
- Quale comando estrae da
conn.logle coppie con più di 20 connessioni verso lo stesso host? - Perché un jitter del 50% rende più difficile rilevare il beacon con una soglia fissa su $CV$?
- Come distingui un beacon da un update checker legittimo?
Soluzione
1. Aggregazione con zeek-cut e sort:
zeek-cut id.orig_h id.resp_h < conn.log | sort | uniq -c | sort -rn | awk '$1 > 20'
2. Con jitter uniforme del ±50% gli intervalli variano tra 0,5μ e 1,5μ, quindi
CV ≈ 0,29: supera la soglia di 0,2. Si risolve alzando la soglia (più falsi positivi) o
usando metriche più robuste, come la mediana e la deviazione assoluta mediana, o un test sul
periodo dominante (autocorrelazione).
3. Dal contesto: destinazione (reputation, età del dominio, certificato in
ssl.log), user-agent in http.log, quantità di dati trasferiti e, soprattutto,
se un processo noto sull'host giustifica il traffico. Gli update checker legittimi vanno in allowlist.
Conclusione
Le firme dicono cosa è noto; i metadati dicono cosa è successo. Zeek ti dà una memoria di rete interrogabile: quando un IOC emerge a distanza di settimane, puoi chiederti chi ha contattato quell’IP e quando. Il beaconing con $CV$ è solo un esempio di detection comportamentale, ma mostra il metodo: scegliere un’invariante che l’attaccante fatica a nascondere e misurarla. Abbinalo a Suricata per le firme e al SIEM per la correlazione.
Prossimo nella serie: Port knocking e SPA · Torna alla roadmap