Creare query in più fasi in YARA-L
Questo documento descrive come le query in più fasi in YARA-L consentono di inserire l'output di una fase della query direttamente nell'input di una fase successiva. Questo processo ti offre un maggiore controllo sulla trasformazione dei dati rispetto a una singola query monolitica.
Integrare le query in più fasi con le funzionalità esistenti
Le query in più fasi funzionano in combinazione con le seguenti funzionalità esistenti in Google Security Operations:
Regole di rilevamento composito: le query in più fasi integrano le regole di rilevamento composito. A differenza delle regole composite, le query in più fasi che utilizzano la ricerca possono restituire risultati in tempo reale.
Intervalli di tempo e regole multi-evento:puoi utilizzare query in più fasi per rilevare anomalie confrontando diverse finestre temporali all'interno dei tuoi dati. Ad esempio, puoi utilizzare le fasi iniziali della query per stabilire una base di riferimento in un periodo di tempo prolungato e poi utilizzare una fase successiva per valutare l'attività recente rispetto a questa base di riferimento. Puoi anche utilizzare le regole multi-evento per creare un tipo di confronto simile.
Le query in più fasi in YARA-L sono supportate sia in Dashboard sia in Ricerca.
Le unioni aiutano a correlare i dati provenienti da più fonti per fornire un contesto più ampio per un'indagine. Collegando eventi, entità e altri dati correlati, puoi analizzare scenari di attacco complessi. Per saperne di più, consulta Utilizzare i join nella ricerca.
Definisci la sintassi YARA-L in più fasi
Quando configuri una query in più fasi, tieni presente quanto segue:
- Fase di limite: le query in più fasi devono contenere da 1 a 4 fasi denominate, oltre alla fase radice.
- Sintassi dell'ordine: definisci sempre la sintassi della fase denominata prima di definire la sintassi della fase radice.
Creare una query YARA-L in più fasi
Per creare una query YARA-L in più fasi, completa i seguenti passaggi.
Struttura e sintassi delle fasi
Vai a Indagine > Ricerca. Segui questi requisiti strutturali quando definisci le fasi della query:
Sintassi: utilizza la seguente sintassi per denominare ogni fase e separarla dalle altre fasi:
stage <stage name> { }
Parentesi graffe: inserisci tutta la sintassi dello stage tra parentesi graffe {}.
Order: definisci la sintassi per tutte le fasi denominate prima di definire la fase radice.
Riferimento: ogni fase può fare riferimento alle fasi definite in precedenza nella query.
Fase principale: una query deve avere una fase principale, che viene elaborata dopo tutte le fasi denominate.
La seguente fase di esempio, daily_stats, raccoglie le statistiche di rete giornaliere:
stage daily_stats {
metadata.event_type = "NETWORK_CONNECTION"
$source = principal.hostname
$target = target.ip
$source != ""
$target != ""
$total_bytes = cast.as_int(network.sent_bytes + network.received_bytes)
match:
$source, $target by day
outcome:
$exchanged_bytes = sum($total_bytes)
}
Output della fase di accesso
L'output di una fase denominata è accessibile alle fasi successive utilizzando i campi della fase. I campi della fase corrispondono alle variabili match e outcome della fase e possono essere utilizzati in modo simile ai campi Unified Data Model (UDM).
Utilizza la seguente sintassi per accedere a un campo di fase:
$<stage name>.<variable name>
Timestamp della finestra di accesso (facoltativo)
Se una fase denominata utilizza una finestra di salto, scorrevole o a cascata, accedi all'inizio e alla fine della finestra per ogni riga di output utilizzando questi campi riservati:
$<stage name>.window_start$<stage name>.window_end
window_start e window_end sono campi interi espressi in secondi
dall'epoca Unix. Le finestre nelle diverse fasi possono variare di dimensioni.
Limitazioni
Le query in più fasi presentano i seguenti vincoli funzionali e strutturali:
Limiti strutturali e di palcoscenico
Fase principale: è consentita una sola fase principale per query.
Fasi denominate: sono supportate al massimo quattro fasi denominate.
Riferimento alle fasi: una fase può fare riferimento solo alle fasi definite logicamente prima di essa nella stessa query.
Join: sono consentiti un massimo di quattro join non di tabelle di dati in tutte le fasi.
Requisito di risultato: ogni fase denominata (esclusa la fase principale) deve includere una sezione
matcho una sezioneoutcome. La sezioneoutcomenon richiede l'aggregazione.
Limiti di finestre e compatibilità
Supporto delle funzionalità: le query in più fasi sono supportate in Ricerca e Dashboard, ma non in Regole.
Tipi di finestre: evita di combinare diversi tipi di finestre in una singola query.
Dipendenza dalla finestra: una fase che utilizza una finestra di salto o scorrevole non può dipendere da un'altra fase che utilizza anche una finestra di salto o scorrevole.
Dimensione della finestra temporale: mentre le finestre temporali in fasi diverse possono variare di dimensioni, la differenza di dimensioni deve essere inferiore a 720x.
Esempio: Differenza di aggregazione dello stato
La seguente configurazione della finestra di esempio non è consentita:
stage monthly_stats {
metadata.event_type = "NETWORK_CONNECTION"
$source = principal.hostname
$target = target.ip
$source != ""
$target != ""
$total_bytes = cast.as_int(network.sent_bytes + network.received_bytes)
match:
$source, $target by month
outcome:
$exchanged_bytes = sum($total_bytes)
}
$source = $monthly_stats.source
$target = $monthly_stats.target
match:
$source, $target by minute
Se la fase monthly_stats aggrega i dati per mese e la fase principale
aggrega l'output di monthly_stats per minuto, ogni riga di
monthly_stats corrisponde a 43.200 righe nella fase principale (perché ci sono 43.200
minuti in un mese).
Limitazioni di fase e query
Ogni singola fase di una query in più fasi presenta i seguenti vincoli:
La maggior parte delle limitazioni che si applicano a una query a una sola fase si applicano anche a ogni singola fase:
Requisito di output: ogni fase deve restituire almeno una variabile di corrispondenza o risultato (campo della fase).
Finestra nel join: la dimensione massima della finestra (hop, tumbling o scorrevole) utilizzata in un join è di 2 giorni.
Numero massimo di variabili di risultato:
20 per i clienti che non hanno attivato l'opzione per consentire un limite più elevato per la variabile di risultato
50 per i clienti che hanno attivato l'opzione per consentire un limite più elevato per la variabile di risultato
Numero massimo di elementi in una variabile di risultato con valori di array.
Le query in più fasi sono soggette agli stessi limiti delle query statistiche:
Query statistiche: 120 QPH (API e UI)
Visualizzazioni di ricerca da Google SecOps: 100 visualizzazioni al minuto
I join in più fasi sono supportati nell'interfaccia utente e nell'API
EventService.UDMSearch, ma non nell'APISearchService.UDMSearch. Anche le query in più fasi senza join sono supportate nell'interfaccia utente.
Limitazioni relative agli eventi e globali
Numero massimo di eventi:
Il numero di eventi che possono essere elaborati contemporaneamente dalle query in più fasi è strettamente limitato:
Eventi UDM: sono consentiti al massimo 2 eventi UDM.
Eventi Entity Context Graph (ECG): è consentito un massimo di un evento ECG.
Limitazioni delle query globali:
Questi limiti sono vincoli a livello di piattaforma che controllano quanto indietro nel tempo e quanti dati può restituire una query in più fasi.
Per un intervallo di tempo della query, l'intervallo di tempo massimo per una query standard è di 30 giorni.
La dimensione massima del set di risultati totale è di 10.000 risultati.
Esempi di query multistadio
Gli esempi in questa sezione illustrano come creare una query YARA-L multistadio completa.
Esempio: cerca connessioni di rete insolitamente attive (ore)
Questo esempio YARA-L in più fasi identifica coppie di indirizzi IP con
un'attività di rete superiore al normale, prendendo di mira le coppie che mantengono un'attività elevata
per più di tre ore. La query include due componenti obbligatori: lo stage denominato hourly_stats e lo stage root.
La fase hourly_stats cerca coppie principal.ip e target.ip con livelli elevati di attività di rete.
Questa fase restituisce un singolo valore orario per i seguenti campi:
Statistiche per l'IP di origine (stringa):
$hourly_stats.src_ipStatistiche per l'IP di destinazione (stringa):
$hourly_stats.dst_ipStatistiche per il conteggio degli eventi (numero intero):
$hourly_stats.countDeviazione standard dei byte ricevuti (float):
$hourly_stats.std_recd_bytesByte medi ricevuti (float):
$hourly_stats.avg_recd_bytesOra di inizio del bucket orario in secondi a partire dal tempo Unix (numero intero):
$hourly_stats.window_startOra di fine del bucket in secondi a partire dall'epoca Unix (numero intero):
$hourly_stats.window_end
La fase principale elabora l'output della fase hourly_stats. Calcola
le statistiche per le coppie principal.ip e target.ip con attività che superano la
soglia specificata da $hourly_stats. A questo punto, filtra le coppie con più di
tre ore di attività elevata.
stage hourly_stats {
metadata.event_type = "NETWORK_CONNECTION"
$src_ip = principal.ip
$dst_ip = target.ip
$src_ip != ""
$dst_ip != ""
match:
$src_ip, $dst_ip by hour
outcome:
$count = count(metadata.id)
$avg_recd_bytes = avg(network.received_bytes)
$std_recd_bytes = stddev(network.received_bytes)
condition:
$avg_recd_bytes > 100 and $std_recd_bytes > 50
}
$src_ip = $hourly_stats.src_ip
$dst_ip = $hourly_stats.dst_ip
$time_bucket_count = strings.concat(timestamp.get_timestamp($hourly_stats.window_start), "|", $hourly_stats.count)
match:
$src_ip, $dst_ip
outcome:
$list = array_distinct($time_bucket_count)
$count = count_distinct($hourly_stats.window_start)
condition:
$count > 3
Se modifichi la condizione di corrispondenza nella fase principale come segue, puoi introdurre un'aggregazione in finestra per giorno per la query in più fasi.
match:
$src_ip, $dst_ip by day
Esempio: cerca connessioni di rete insolitamente attive (utilizzando lo Z-score)
Questa query in più fasi confronta l'attività di rete media giornaliera con l'attività odierna utilizzando un calcolo del punteggio Z (che misura il numero di deviazioni standard dalla media). Questa query cerca in modo efficace attività di rete insolitamente elevata tra asset interni e sistemi esterni.
Prerequisito: la finestra temporale della query deve essere maggiore o uguale a 2 giorni e includere il giorno corrente affinché lo Z-score calcolato sia efficace.
Questa query in più fasi include la fase daily_stats e la fase root,
che lavorano insieme per calcolare lo Z-score per l'attività di rete:
La fase
daily_statsesegue l'aggregazione giornaliera iniziale. Calcola il totale dei byte scambiati ogni giorno per ogni coppia di IP (sourceetarget) e restituisce i seguenti campi di fase (corrispondenti alle colonne nelle righe di output):$daily_stats.source: singolare, stringa$daily_stats.target: singolare, stringa$daily_stats.exchanged_bytes: singolare, numero intero$daily_stats.window_start: singolare, numero intero$daily_stats.window_end: singolare, numero intero
La fase principale aggrega l'output della fase
daily_statsper ogni coppia di IP. Calcola la media e la deviazione standard dei byte giornalieri scambiati nell'intero intervallo di ricerca, insieme ai byte scambiati oggi. Utilizza questi tre valori calcolati per determinare lo Z-score.L'output elenca gli Z-score per tutte le coppie di IP di oggi, ordinati in ordine decrescente.
// Calculate the total bytes exchanged per day by source and target
stage daily_stats {
metadata.event_type = "NETWORK_CONNECTION"
$source = principal.hostname
$target = target.ip
$source != ""
$target != ""
$total_bytes = cast.as_int(network.sent_bytes + network.received_bytes)
match:
$source, $target by day
outcome:
$exchanged_bytes = sum($total_bytes)
}
// Calculate the average per day over the time window and compare with the bytes
exchanged today
$source = $daily_stats.source
$target = $daily_stats.target
$date = timestamp.get_date($daily_stats.window_start)
match:
$source, $target
outcome:
$today_bytes = sum(if($date = timestamp.get_date(timestamp.current_seconds()), $daily_stats.exchanged_bytes, 0))
$average_bytes = window.avg($daily_stats.exchanged_bytes)
$stddev_bytes = window.stddev($daily_stats.exchanged_bytes)
$zscore = ($today_bytes - $average_bytes) / $stddev_bytes
order:
$zscore desc
Esportare variabili non aggregate dalle fasi
Le fasi denominate possono includere una sezione outcome non aggregata. Ciò significa che le variabili definite all'interno della sezione outcome vengono generate direttamente dalla fase, consentendo alle fasi successive di accedervi come campi della fase senza richiedere un'aggregazione raggruppata.
Esempio: esportare una variabile non aggregata
Questo esempio mostra come esportare le variabili non aggregate. Tieni presente la seguente logica:
top_5_bytes_sentesegue la ricerca di staging per i cinque eventi con la maggiore attività di rete.La fase
top_5_bytes_sentrestituisce i seguenti campi della fase corrispondenti alle colonne nelle righe di output:$top_5_bytes_sent.bytes_sent: singolare, numero intero$top_5_bytes_sent.timestamp_seconds: singolare, numero intero
La fase
rootcalcola i timestamp più recenti e meno recenti per i cinque eventi con l'attività di rete più elevata.
stage top_5_bytes_sent {
metadata.event_type = "NETWORK_CONNECTION"
network.sent_bytes > 0
outcome:
$bytes_sent = cast.as_int(network.sent_bytes)
$timestamp_seconds = metadata.event_timestamp.seconds
order:
$bytes_sent desc
limit:
5
}
outcome:
$latest_timestamp = timestamp.get_timestamp(max($top_5_bytes_sent.timestamp_seconds))
$earliest_timestamp = timestamp.get_timestamp(min($top_5_bytes_sent.timestamp_seconds))
Implementa il windowing nelle query in più fasi
Le query in più fasi supportano tutti i tipi di finestre (hop, scorrevole e sequenziale) nelle fasi denominate. Se una fase denominata include una finestra, l'inizio e la fine della finestra per ogni riga di output sono accessibili utilizzando i seguenti campi riservati:
$<stage name>.window_start$<stage name>.window_end
Esempio: finestra di hop
L'esempio seguente mostra come potresti utilizzare le finestre di hop in una query in più fasi:
hourly_statsesegue ricerche di coppie di IP con un'attività di rete elevata nella stessa ora.hourly_statsrestituisce i seguenti campi di fase corrispondenti alle colonne nelle righe di output:$hourly_stats.src_ip: singolare, stringa$hourly_stats.dst_ip: singolare, stringa$hourly_stats.count: singolare, numero intero$hourly_stats.std_recd_bytes: singolare, float$hourly_stats.avg_recd_bytes: singolare, float$hourly_stats.window_start: singolare, numero intero$hourly_stats.window_end: singolare, numero intero
Il filtro della fase radice esclude le coppie di IP con più di 3 ore di attività elevata. Le ore potrebbero sovrapporsi a causa dell'utilizzo di una finestra di hop nella fase
hourly_stats.
stage hourly_stats {
metadata.event_type = "NETWORK_CONNECTION"
$src_ip = principal.ip
$dst_ip = target.ip
$src_ip != ""
$dst_ip != ""
match:
$src_ip, $dst_ip over 1h
outcome:
$count = count(metadata.id)
$avg_recd_bytes = avg(network.received_bytes)
$std_recd_bytes = stddev(network.received_bytes)
condition:
$avg_recd_bytes > 100 and $std_recd_bytes > 50
}
$src_ip = $hourly_stats.src_ip
$dst_ip = $hourly_stats.dst_ip
$time_bucket_count = strings.concat(timestamp.get_timestamp($hourly_stats.window_start), "|", $hourly_stats.count)
match:
$src_ip, $dst_ip
outcome:
$list = array_distinct($time_bucket_count)
$count = count_distinct($hourly_stats.window_start)
condition:
$count > 3
Problemi noti
Ti consigliamo di esaminare le seguenti limitazioni e soluzioni alternative consigliate quando implementi query in più fasi:
Tutte le query in più fasi si comportano come le query di ricerca delle statistiche (l'output è costituito da statistiche aggregate anziché da eventi o righe di tabelle di dati non aggregati).
Le prestazioni dei join con UDM e gli eventi entità su un lato possono registrare prestazioni basse a causa delle dimensioni del set di dati. Ti consigliamo vivamente di filtrare gli eventi UDM e delle entità del lato di unione il più possibile (ad esempio, filtrare in base al tipo di evento).
Per indicazioni generali sulle pratiche consigliate, consulta le best practice di Yara-L e per informazioni specifiche sui join, consulta le best practice.
Hai bisogno di ulteriore assistenza? Ricevi risposte dai membri della community e dai professionisti di Google SecOps.