Problemi noti di YARA-L 2.0

Supportata in:

Questo documento è rivolto ai detection engineer che vogliono eseguire il debug della logica delle regole e ottimizzare l'esecuzione di YARA-L 2.0. Spiega come gestire i comportamenti non standard del motore, come l'annullamento del nidificazione dei campi, l'espansione del prodotto cartesiano nelle aggregazioni e la coerenza finale dell'arricchimento. Seguendo questi metodi, puoi evitare errori logici che portano a valori dei risultati gonfiati o a mancate rilevazioni.

YARA-L 2.0 utilizza un modello di esecuzione che espande i campi ripetuti in singole righe di eventi durante la valutazione. Poiché questa trasformazione avviene a livello di motore, il riferimento a più campi ripetuti o l'esecuzione di operazioni aritmetiche su tipi di Unified Data Model (UDM) non firmati richiede soluzioni alternative di sintassi per evitare errori del compilatore, errori di runtime o set di risultati errati. Questo documento illustra questi vincoli tecnici e i pattern logici che li risolvono.

Prima di iniziare

Prima di testare o modificare le regole YARA-L 2.0, assicurati che il tuo account disponga dei seguenti diritti tecnici:

Ruoli IAM richiesti

  • roles/chronicle.viewer (Visualizzatore operazioni di sicurezza): per visualizzare le regole esistenti e i metadati di rilevamento.
  • roles/chronicle.editor (Editor operazioni di sicurezza): per modificare la logica delle regole e salvare le modifiche.

Autorizzazioni obbligatorie

  • chronicle.rules.runTest: obbligatorio per eseguire la funzionalità Esegui test sui dati storici.

  • chronicle.detections.get: per esaminare l'output degli eventi non nidificati nella dashboard di rilevamento.

Terminologia chiave

  • UDM (Unified Data Model): lo schema normalizzato utilizzato per strutturare tutta la telemetria di sicurezza importata nella piattaforma.
  • Unnesting: l'espansione a livello di motore di un singolo evento UDM contenente un campo ripetuto (array) in più righe. Ogni riga rappresenta un elemento univoco dell'array, il che può portare alla moltiplicazione delle righe durante la valutazione delle regole.
  • T₀ (esecuzione iniziale): la prima esecuzione di una regola sulla telemetria in entrata. Ciò avviene durante la fase di "flusso di dati", spesso prima che vengano finalizzati i processi di arricchimento in background (come i true-up GeoIP o ASN).

Aggregazioni dei risultati con unnesting dei campi ripetuti

Quando una regola fa riferimento a un campo ripetuto in una variabile evento con più elementi, ogni elemento viene suddiviso in una riga evento separata.

Ad esempio, i due indirizzi IP nel campo ripetuto target.ip dell'evento $e vengono suddivisi in due istanze di $e, ciascuna con un valore target.ip diverso.

rule outbound_ip_per_app {
  meta:

  events:
    $e.principal.application = $app

  match:
    $app over 10m

  outcome:
    $outbound_ip_count = count($e.target.ip) // yields 2.

  condition:
    $e
}

Record di eventi: prima e dopo l'un-nesting

Le tabelle in questa sezione mostrano come un singolo evento contenente un array di indirizzi IP viene trasformato in due record distinti.

Prima dell'annidamento

La tabella seguente mostra il record dell'evento prima di unnesting del campo ripetuto:

metadata.id principal.application target.ip
aaaaaaaaa Google SecOps [192.0.2.20, 192.0.2.28]

Dopo l'annullamento del nesting

La tabella seguente mostra il record dell'evento dopo l'annullamento del nidificazione del campo ripetuto:

metadata.id principal.application target.ip
aaaaaaaaa Google SecOps 192.0.2.20
aaaaaaaaa Google SecOps 192.0.2.28

Campi ripetuti nidificati (prodotto cartesiano)

Quando una regola fa riferimento a un campo ripetuto nidificato all'interno di un altro, ad esempio security_results.action, l'annullamento della nidificazione avviene contemporaneamente a entrambi i livelli (principale e secondario). In questo modo, viene generato un prodotto cartesiano di tutti gli elementi.

Nell'esempio seguente, un evento $e con due valori ripetuti su security_results e due valori ripetuti su security_results.actions viene nidificato in quattro istanze.

rule security_action_per_app {
  meta:

  events:
    $e.principal.application = $app

  match:
    $app over 10m

  outcome:
    $security_action_count = count($e.security_results.actions) // yields 4.

  condition:
    $e
}

Record di eventi prima dell'annullamento della nidificazione

Il record originale memorizza le azioni all'interno di una struttura di array nidificata.

metadata.id principal.application security_results
aaaaaaaaa Google SecOps [ { actions: [ ALLOW, FAIL ] }, { actions: [ CHALLENGE, BLOCK ] } ]

Record di eventi dopo l'annullamento della nidificazione

Dopo l'espansione, ogni azione univoca diventa una riga a sé stante, il che può portare a conteggi imprevisti nelle aggregazioni non distinte.

metadata.id principal.application security_results.actions
aaaaaaaaa Google SecOps CONSENTI
aaaaaaaaa Google SecOps ESITO NEGATIVO
aaaaaaaaa Google SecOps CHALLENGE
aaaaaaaaa Google SecOps BLOCCA

Impatto sui campi non correlati

Questo comportamento di unnesting nella valutazione delle regole può produrre aggregazioni di risultati impreviste quando la regola fa riferimento a uno o più campi ripetuti con un campo principale che è anche un campo ripetuto. Le aggregazioni non distinte come sum(), array() e count() non possono tenere conto dei valori duplicati in altri campi dello stesso evento prodotti dal comportamento di unnesting.

Nell'esempio seguente, l'evento $e ha un singolo nome host (google.com), ma il risultato (hostnames) aggrega quattro istanze non nidificate dello stesso evento $e, ciascuna con un valore principal.hostname duplicato. Questo risultato genera quattro nomi host (anziché uno) a causa dell'un-nesting dei valori ripetuti su security_results.actions.

rule security_action_per_app {
  meta:

  events:
    $e.principal.application = $app

  match:
    $app over 10m

  outcome:
    $hostnames = array($e.principal.hostname) // yields 4.
    $security_action_count = count($e.security_results.action) // yields 4.

  condition:
    $e
}

Record di eventi prima dell'annullamento della nidificazione con campi non correlati

Il nome host è un valore singolo, ma si trova accanto ai risultati di sicurezza ripetuti.

metadata.id principal.application principal.hostname security_results
aaaaaaaaa Google SecOps google.com [ { action: [ ALLOW, FAIL ] }, { action: [ CHALLENGE, BLOCK ] } ]

Record di eventi dopo l'annidamento con campi non correlati

Il nome host è ora duplicato in quattro righe, il che fa sì che la funzione array() lo rilevi quattro volte.

metadata.id principal.application principal.hostname security_results.action
aaaaaaaaa Google SecOps google.com CONSENTI
aaaaaaaaa Google SecOps google.com ESITO NEGATIVO
aaaaaaaaa Google SecOps google.com CHALLENGE
aaaaaaaaa Google SecOps google.com BLOCCA

Soluzione alternativa per il comportamento di unnesting

Per assicurarti che i valori dei risultati siano accurati quando si verifica l'un-nesting, utilizza la versione distinta dell'aggregazione selezionata. Le seguenti funzioni ignorano le righe duplicate create dall'annullamento del nesting:

  • max()
  • min()
  • array_distinct()
  • count_distinct()

Aggregazioni dei risultati con più variabili di evento

Se una regola contiene più variabili di evento, nell'aggregazione è presente un elemento separato per ogni combinazione di eventi inclusa nel rilevamento. Ad esempio, se la seguente regola di esempio viene eseguita sugli eventi elencati:

events:
  $e1.field = $e2.field
  $e2.somefield = $ph

match:
  $ph over 1h

outcome:
   $some_outcome = sum(if($e1.otherfield = "value", 1, 0))

condition:
  $e1 and $e2
event1:
  // UDM event 1
  field="a"
  somefield="d"

event2:
  // UDM event 2
  field="b"
  somefield="d"

event3:
  // UDM event 3
  field="c"
  somefield="d"

La somma viene calcolata su ogni combinazione di eventi, consentendoti di utilizzare entrambe le variabili di evento nei calcoli del valore del risultato. Nel calcolo vengono utilizzati i seguenti elementi:

1: $e1 = event1, $e2 = event2
2: $e1 = event1, $e2 = event3
3: $e1 = event2, $e2 = event1
4: $e1 = event2, $e2 = event3
5: $e1 = event3, $e2 = event1
5: $e1 = event3, $e2 = event2

Ciò si traduce in una somma massima potenziale di 6, anche se $e2 può corrispondere solo a 3 eventi distinti.

Questo influisce su somma, conteggio e array. Per count e array, l'utilizzo di count_distinct o array_distinct può risolvere il problema, ma non esiste una soluzione alternativa per sum.

Parentesi all'inizio di un'espressione

L'inizio di un'espressione con parentesi non è supportato e attiva un errore di analisi nell'editor delle regole.

Sintassi non valida

parsing: error with token: ")"
invalid operator in events predicate

L'esempio seguente genera questo tipo di errore:

($event.metadata.ingested_timestamp.seconds -
$event.metadata.event_timestamp.seconds) / 3600 > 1

Varianti di sintassi valide

Le seguenti varianti di sintassi restituiscono lo stesso risultato, ma con una sintassi valida:

$event.metadata.ingested_timestamp.seconds / 3600 -
$event.metadata.event_timestamp.seconds / 3600 > 1
    1 / 3600 * ($event.metadata.ingested_timestamp.seconds -
$event.metadata.event_timestamp.seconds) > 1
    1 < ($event.metadata.ingested_timestamp.seconds -
$event.metadata.event_timestamp.seconds) / 3600

L'array di indici nel risultato richiede l'aggregazione

L'indicizzazione diretta di un array all'interno della sezione outcome per i campi ripetuti non è consentita. Richiede una variabile segnaposto temporanea.

outcome:
  $principal_user_dept = $suspicious.principal.user.department[0]

Soluzione alternativa

Acquisisci l'indice dell'array specifico in una variabile segnaposto all'interno della sezione events, quindi fai riferimento a quel segnaposto nel risultato.

events:
  $principal_user_dept = $suspicious.principal.user.department[0]

outcome:
  $principal_user_department = $principal_user_dept

OR condizione con non esistenza

Se applichi una condizione OR tra due variabili di evento separate e se la regola corrisponde alla non esistenza, la regola viene compilata correttamente, ma può produrre rilevamenti di falsi positivi.

Ad esempio, la seguente sintassi della regola può trovare corrispondenze con eventi con $event_a.field = "something" anche se non dovrebbe:

events:
     not ($event_a.field = "something" **or** $event_b.field = "something")
condition:
     $event_a and #event_b >= 0

Soluzione alternativa

Separa i controlli di non esistenza in blocchi singoli per ogni variabile per mantenere l'integrità logica.

events:
  not ($event_a.field = "something")
  not ($event_b.field = "something")

condition:
  $event_a and #event_b >= 0

Aritmetica con campi di eventi non firmati

Se utilizzi un valore letterale intero in un'operazione aritmetica (+, -, *) o modulo (%) con un campo UDM intero senza segno, viene visualizzato un errore. I valori letterali interi standard vengono impostati per impostazione predefinita su numeri interi con segno a 64 bit (INT64), che non sono compatibili con i campi UDM definiti come numeri interi senza segno a 64 bit (UINT64), ad esempio network.received_bytes, network.sent_bytes e principal.file.size.

Questo vincolo di tipizzazione rigoroso si applica sia alle sezioni events che outcome, incluse le aggregazioni sum() o max() e le espressioni del divisore. Il controllo della sintassi YARA-L tratta sia i numeri interi con segno che quelli senza segno come un tipo int generico. Di conseguenza, una regola che combina campi UDM UINT64 e valori letterali interi INT64 potrebbe superare la convalida della sintassi al momento del salvataggio, ma non riuscire durante l'esecuzione della regola o quando fai clic su Esegui test. Quando la regola non va a buon fine, genera un "Errore regola" generico (cannot complete [arithmetic/mod] operation between unsigned and signed integer).

Ad esempio, il seguente confronto events supera la convalida della sintassi quando viene salvato, ma non viene eseguito perché $e.network.received_bytes (UINT64) viene moltiplicato per il valore letterale intero con segno 2 (INT64):

events:
  $total_bytes = $e.network.total_bytes
  $total_bytes = $e.network.received_bytes * 2

Soluzioni alternative

Puoi risolvere questa mancata corrispondenza del tipo utilizzando uno dei seguenti metodi:

  • Cast esplicito di numeri interi (cast.as_int() o cast.as_uint()): converti il campo UDM non firmato in un numero intero firmato utilizzando cast.as_int() o converti il valore letterale intero in un numero intero non firmato utilizzando cast.as_uint(). Utilizza questo metodo quando hai bisogno di un risultato intero o quando utilizzi l'operatore modulo (%), che accetta solo operandi interi.
  • Coercizione in rappresentazione in virgola mobile: forza la costante intera a comportarsi come un float utilizzando un valore letterale in rappresentazione in virgola mobile, ad esempio 2.0 o 100.0. Nelle espressioni senza altri operatori di divisione sulla stessa riga, puoi anche utilizzare un'operazione di divisione, ad esempio (2/1). Nelle espressioni che contengono già operatori di divisione (/), utilizza valori letterali in rappresentazione in virgola mobile o cast.as_int() anziché la coercizione della divisione (N/1). Più caratteri / sulla stessa riga possono essere interpretati come un valore letterale di espressione regolare, causando un errore di analisi durante la compilazione o interrompendo l'evidenziazione della sintassi nell'editor delle regole.

Soluzione alternativa nella sezione events

Utilizza cast.as_int(), una rappresentazione in virgola mobile, o la coercizione della divisione per correggere l'errore nella sezione events:

  • Utilizza cast.as_int():

    events:
      $total_bytes = $e.network.total_bytes
      $total_bytes = cast.as_int($e.network.received_bytes) * 2
    
  • Utilizza un valore letterale in rappresentazione in virgola mobile:

    events:
      $total_bytes = $e.network.total_bytes
      $total_bytes = $e.network.received_bytes * 2.0
    
  • Utilizza la coercizione della divisione:

    events:
      $total_bytes = $e.network.total_bytes
      $total_bytes = $e.network.received_bytes * (2/1)
    

Soluzione alternativa nella sezione outcome

La seguente espressione outcome viene salvata senza errori di sintassi, ma non riesce in fase di runtime perché sum($e.network.sent_bytes) e sum($e.network.received_bytes) restituiscono valori UINT64 che vengono combinati con i valori letterali INT64 con segno 100 e 1:

outcome:
  // Saves, but fails at runtime:
  $upload_ratio_pct = sum($e.network.sent_bytes) * 100 / (sum($e.network.received_bytes) + 1)

Riscrivi l'espressione utilizzando valori letterali in rappresentazione in virgola mobile o cast.as_int() in modo che venga salvata ed eseguita senza errori:

  • Utilizza valori letterali in virgola mobile:

    outcome:
      $upload_ratio_pct = sum($e.network.sent_bytes) * 100.0 / (sum($e.network.received_bytes) + 1.0)
    
  • Utilizza cast.as_int():

    outcome:
      $upload_ratio_pct = sum(cast.as_int($e.network.sent_bytes)) * 100 / (sum(cast.as_int($e.network.received_bytes)) + 1)
    

Variabili di ricerca e corrispondenza di stringhe senza distinzione tra maiuscole e minuscole

In Google Security Operations Ricerca, per impostazione predefinita le query non fanno distinzione tra maiuscole e minuscole. Quando esegui una query statistica (utilizzando match: e outcome:) con la ricerca senza distinzione tra maiuscole e minuscole attivata, le variabili di stringa nella sezione match: vengono convertite automaticamente in minuscolo (strings.to_lower()) per il raggruppamento durante la compilazione della query.

Di conseguenza, le colonne match: nei risultati delle statistiche contengono valori tutti in minuscolo anziché con l'uso di maiuscole e minuscole originale. Questo comportamento può essere distruttivo per i campi di stringa sensibili alle maiuscole, come righe di comando con codifica Base64, token, URL o percorsi sensibili alle maiuscole, impedendo la decodifica o la valutazione corretta.

Per risolvere il problema, esegui una delle seguenti operazioni:

  • Proiezione dei campi non elaborati nei risultati: i campi proiettati nella sezione outcome: utilizzando aggregazioni come array_distinct(...), max(...) o min(...) non vengono convertiti in minuscolo e conservano le lettere maiuscole originali. Se devi visualizzare l'uso delle maiuscole originale per le stringhe raggruppate, proietta il campo non elaborato nella sezione outcome: utilizzando array_distinct(...).
  • Utilizza la ricerca sensibile alle maiuscole: in alternativa, puoi impostare Cerca sulla modalità Sensibile alle maiuscole. Tieni presente che in questo modo anche il raggruppamento match: diventa sensibile alle maiuscole.

Arricchimento GeoIP e coerenza finale

Il sistema dà priorità alla velocità rispetto all'accuratezza immediata nelle fasi iniziali di arricchimento (Streaming e Sensibile alla latenza), il che può portare a dati mancanti e potenziali falsi positivi. Il sistema continua ad arricchire i dati in background, ma i dati potrebbero non essere disponibili quando viene eseguita la regola. Questo fa parte del normale processo di coerenza finale.

Per evitare falsi positivi causati dal ritardo nell'arricchimento, verifica esplicitamente che il campo non sia vuoto prima di valutarne il valore.

Ad esempio, considera questo evento della regola:

$e.principal.ip_geo_artifact.network.asn = "16509" AND
$e.principal.ip_geo_artifact.location.country_or_region = "United Kingdom"

La regola si basa sul fatto che l'evento deve avere $e.principal.ip_geo_artifact.network.asn = "16509" E $e.principal.ip_geo_artifact.location.country_or_region = "United Kingdom", che sono entrambi campi arricchiti. Se l'arricchimento non viene completato in tempo, la regola produrrà un falso positivo.

Per evitare questo problema, un controllo migliore per questa regola sarebbe:

$e.principal.ip_geo_artifact.network.asn != "" AND
$e.principal.ip_geo_artifact.network.asn = "16509" AND
$e.principal.ip_geo_artifact.location.country_or_region != "" AND
$e.principal.ip_geo_artifact.location.country_or_region = "United Kingdom"

Questa regola elimina la possibilità che l'evento venga attivato da IP con ASN 16509, ma situati al di fuori del Regno Unito. In questo modo, la precisione complessiva della regola viene migliorata.

Scopri come risolvere i problemi relativi al ritardo di arricchimento.

Risoluzione dei problemi

Questa sezione illustra le aspettative sul rendimento e fornisce correzioni self-service per i problemi comuni in cui il comportamento di rilevamento in tempo reale differisce dai risultati dei test.

Eventi con data futura

Le regole multi-evento sono progettate per elaborare gli eventi in ordine cronologico rispetto all'importazione. Se specifichi e attivi una regola per più eventi, non vengono create rilevazioni per gli eventi con timestamp futuri, ad esempio quando event.timestamp ha una data e un'ora impostate dopo ingest.timestamp.

Ritardo di arricchimento

Google SecOps dà la priorità alla velocità di importazione per mostrare gli avvisi iniziali il più rapidamente possibile. Tuttavia, i processi di arricchimento in background, come la risoluzione dei metadati GeoIP, ASN o UDM, seguono un modello di coerenza finale.

Esecuzione iniziale (T₀)

Il motore live potrebbe valutare una regola prima che l'arricchimento in background sia completato. A seconda che la logica si basi su campi arricchiti per i rilevamenti o le esclusioni, ciò può portare alle seguenti discrepanze temporanee:

  • Falsi negativi (ritardo nel rilevamento): si tratta di un risultato comune. Se una regola dipende da un campo arricchito per l'attivazione (ad esempio, target.user.department == "Finance") e questo campo è null, la regola non corrisponde durante l'esecuzione iniziale.

  • Falsi positivi (mancata esclusione): se la regola utilizza campi arricchiti per filtrare le attività note come valide (ad esempio NOT target.ip_geo_country == "US"), la regola potrebbe attivare un falso positivo perché i dati di "esclusione" non sono ancora stati applicati.

Esecuzioni di allineamento

Queste esecuzioni in background rivalutano i dati dopo un ritardo (ad esempio, 4 ore o 30 ore). In questo modo, gli stati di rilevamento vengono "corretti" come segue:

  • Rilevamenti tardivi: gli eventi che erano "falsi negativi" al momento T₀ ora producono un rilevamento una volta finalizzato l'arricchimento.

  • Correzione: eventuali falsi positivi T₀ rimangono nel sistema, ma i dati completamente arricchiti sono visibili nel visualizzatore UDM per la valutazione manuale.

Discrepanza del test di esecuzione

Lo strumento Esegui test opera su dati storici già riconciliati. Poiché i dati sono completamente arricchiti al momento dell'esecuzione di un test manuale, puoi visualizzare immediatamente i risultati di "conguaglio". Ciò significa che non vedrai i falsi negativi T₀ o i falsi positivi basati sull'esclusione che si sono verificati durante l'esecuzione iniziale in tempo reale.

Correzione degli errori

Utilizza la seguente tabella per risolvere le discrepanze tra gli avvisi in tempo reale e i risultati dei test.

Problema Descrizione Correzione applicabile
Errore di esclusione Una regola viene attivata nonostante un'esclusione (ad esempio != "ASN_123") perché il campo era nullo durante l'esecuzione iniziale. Aggiungi un controllo non null alla sezione degli eventi per assicurarti che i dati vengano arricchiti prima della valutazione, ad esempio:

$e.principal.ip_geo_artifact.network.asn != ""
Confronto tra test in tempo reale e test di corrispondenza Le regole attive attivano gli avvisi, ma l'esecuzione del test sugli stessi dati mostra "No Results". Aggiungi $e.field != "", che controlla tutti i campi con informazioni aggiuntive (GeoIP, ASN, File Path) per sincronizzare il comportamento in tempo reale e storico.
Metadati mancanti I rilevamenti vengono visualizzati nella dashboard con i campi GeoIP o File Path vuoti. Questo è il comportamento previsto per le esecuzioni T0. Per risolvere il problema, includi un controllo field != "" o configura un ritardo di liquidazione nella pianificazione delle regole per concedere più tempo per l'importazione.

Convalida e test

Per verificare che una regola gestisca correttamente l'arricchimento ritardato, segui questi passaggi:

  1. Identifica il ritardo: individua un rilevamento che ritieni sia un falso positivo. Nella colonna Tipo di rilevamento, cerca l'icona <span class="material-icons">lightbulb</span>. Gli avvisi senza questa icona provengono dall'esecuzione principale, in cui il ritardo di arricchimento è più comune.

  2. Aggiorna la logica della regola: aggiungi un controllo field != "" per tutti i punti dati arricchiti utilizzati nella logica.
    Esempio (percorso file):
    $e.target.process.parent_process.file.full_path != ""

  3. Testa e verifica:

    • Utilizza la funzionalità Esegui test per assicurarti che la logica corrisponda ancora ai dati storici previsti.
    • Verifica che la regola venga attivata (o esclusa correttamente) solo durante le esecuzioni di true-up una volta compilati i campi di arricchimento.

Per saperne di più, consulta Informazioni sulla pianificazione dell'esecuzione delle regole e Configura pianificazioni personalizzate per le regole.

Hai bisogno di ulteriore assistenza? Ricevi risposte dai membri della community e dai professionisti di Google SecOps.