Problèmes connus de YARA-L 2.0

Ce document est destiné aux ingénieurs en détection qui souhaitent déboguer la logique des règles et optimiser l'exécution de YARA-L 2.0. Il explique comment gérer les comportements non standards du moteur, tels que la suppression de l'imbrication des champs, l'expansion du produit cartésien dans les agrégations et la cohérence à terme de l'enrichissement. En suivant ces méthodes, vous pouvez éviter les erreurs de logique qui entraînent des valeurs de résultat gonflées ou des détections manquées.

YARA-L 2.0 utilise un modèle d'exécution spécifique dans lequel les champs répétés sont développés en lignes d'événements individuelles lors de l'évaluation. Étant donné que cette transformation se produit au niveau du moteur, le référencement de plusieurs champs répétés ou l'exécution d'opérations arithmétiques sur des types UDM non signés nécessitent des solutions de contournement syntaxiques spécifiques pour éviter les erreurs de compilation ou les ensembles de résultats incorrects. Ce document décrit ces contraintes techniques et les modèles logiques requis pour les résoudre.

Avant de commencer

Assurez-vous que votre compte dispose des droits techniques suivants avant de tester ou de modifier les règles YARA-L 2.0 :

Rôles IAM requis

  • roles/chronicle.viewer (Lecteur Security Operations) : pour afficher les règles existantes et les métadonnées de détection.
  • roles/chronicle.editor (Éditeur Security Operations) : pour modifier la logique des règles et enregistrer les modifications.

Autorisations requises

  • chronicle.rules.runTest : obligatoire pour exécuter la fonctionnalité Exécuter le test sur les données historiques.

  • chronicle.detections.get : pour inspecter la sortie des événements non imbriqués dans le tableau de bord de détection.

Terminologie clé

  • UDM (Unified Data Model) : schéma normalisé utilisé pour structurer toutes les données de télémétrie de sécurité ingérées sur la plate-forme.
  • Suppression de l'imbrication : expansion au niveau du moteur d'un seul événement UDM contenant un champ répété (tableau) en plusieurs lignes. Chaque ligne représente un élément unique du tableau, ce qui peut entraîner une multiplication des lignes lors de l'évaluation des règles.
  • T₀ (exécution initiale) : première exécution d'une règle sur les données de télémétrie entrantes. Cela se produit pendant la phase de "streaming", souvent avant la finalisation des processus d'enrichissement en arrière-plan (tels que les régularisations GeoIP ou ASN).

Agrégations de résultats avec suppression de l'imbrication des champs répétés

Lorsqu'une règle référence un champ répété dans une variable d'événement comportant plusieurs éléments, chaque élément est divisé en une ligne d'événement distincte.

Par exemple, les deux adresses IP du champ répété target.ip de l'événement $e sont divisées en deux instances de $e, chacune avec une valeur target.ip différente.

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
}

Enregistrements d'événements : avant et après la suppression de l'imbrication

Les tableaux de cette section montrent comment un seul événement contenant un tableau d'adresses IP est transformé en deux enregistrements distincts.

Avant la suppression de l'imbrication

Le tableau suivant présente l'enregistrement d'événement avant la suppression de l'imbrication du champ répété :

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

Après la suppression de l'imbrication

Le tableau suivant présente l'enregistrement d'événement après la suppression de l'imbrication du champ répété :

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

Champs répétés imbriqués (produit cartésien)

Lorsqu'une règle référence un champ répété imbriqué dans un autre, comme security_results.action, la suppression de l'imbrication se produit simultanément aux deux niveaux (parent et enfant). Cela génère un produit cartésien de tous les éléments.

Dans l'exemple suivant, un événement $e avec deux valeurs répétées sur security_results et deux valeurs répétées sur security_results.actions sont non imbriquées en quatre instances.

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
}

Enregistrement d'événement avant la suppression de l'imbrication imbriquée

L'enregistrement d'origine stocke les actions dans une structure de tableau imbriquée.

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

Enregistrements d'événements après la suppression de l'imbrication imbriquée

Après l'expansion, chaque action unique devient sa propre ligne, ce qui peut entraîner des nombres inattendus dans les agrégations non distinctes.

metadata.id principal.application security_results.actions
aaaaaaaaa Google SecOps AUTORISER
aaaaaaaaa Google SecOps ÉCHEC
aaaaaaaaa Google SecOps DÉFI
aaaaaaaaa Google SecOps BLOQUER

Impact sur les champs non liés

Ce comportement de suppression de l'imbrication lors de l'évaluation des règles peut générer des agrégations de résultats inattendues lorsque la règle référence un ou plusieurs champs répétés avec un champ parent qui est également un champ répété. Les agrégations non distinctes telles que sum(), array() et count() ne peuvent pas tenir compte des valeurs en double sur d'autres champs du même événement généré par le comportement de suppression de l'imbrication.

Dans l'exemple suivant, l'événement $e ne comporte qu'un seul nom d'hôte (google.com), mais le résultat (hostnames) s'agrège sur quatre instances non imbriquées du même événement $e, chacune avec une valeur principal.hostname en double. Ce résultat génère quatre noms d'hôte (au lieu d'un) en raison de la suppression de l'imbrication des valeurs répétées sur 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
}

Enregistrement d'événement avant la suppression de l'imbrication avec des champs non liés

Le nom d'hôte est une valeur unique, mais il se trouve à côté des résultats de sécurité répétés.

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

Enregistrement d'événement après la suppression de l'imbrication avec des champs non liés

Le nom d'hôte est désormais dupliqué sur quatre lignes, ce qui permet à la fonction array() de le récupérer quatre fois.

metadata.id principal.application principal.hostname security_results.action
aaaaaaaaa Google SecOps google.com AUTORISER
aaaaaaaaa Google SecOps google.com ÉCHEC
aaaaaaaaa Google SecOps google.com DÉFI
aaaaaaaaa Google SecOps google.com BLOQUER

Solution de contournement pour le comportement de suppression de l'imbrication

Pour vous assurer que les valeurs de vos résultats sont exactes lorsque la suppression de l'imbrication se produit, utilisez la version distincte de l'agrégation sélectionnée. Les fonctions suivantes ignorent les lignes en double créées par la suppression de l'imbrication :

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

Agrégations de résultats avec plusieurs variables d'événement

Si une règle contient plusieurs variables d'événement, il existe un élément distinct dans l'agrégation pour chaque combinaison d'événements incluse dans la détection. Par exemple, si la règle d'exemple suivante est exécutée par rapport aux événements listés :

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 somme est calculée sur chaque combinaison d'événements, ce qui vous permet d'utiliser les deux variables d'événement dans les calculs de la valeur du résultat. Les éléments suivants sont utilisés dans le calcul :

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

Cela génère une somme maximale potentielle de 6, même si $e2 ne peut correspondre qu'à 3 événements distincts.

Cela affecte la somme, le nombre et le tableau. Pour le nombre et le tableau, l'utilisation de count_distinct ou array_distinct peut résoudre le problème, mais il n'existe aucune solution de contournement pour la somme.

Parenthèses au début d'une expression

Le fait de commencer une expression par des parenthèses n'est pas pris en charge et déclenche une erreur d'analyse dans l'éditeur de règles.

Syntaxe non valide

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

L'exemple suivant génère ce type d'erreur :

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

Variantes syntaxiques valides

Les variantes syntaxiques suivantes renvoient le même résultat, mais avec une syntaxe valide :

$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

Le tableau d'index dans le résultat nécessite une agrégation

L'indexation directe d'un tableau dans la section outcome pour les champs répétés n'est pas autorisée. Elle nécessite une variable d'espace réservé temporaire.

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

Solution

Capturez l'index de tableau spécifique dans une variable d'espace réservé dans la section events, puis référencez cet espace réservé dans votre résultat.

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

outcome:
  $principal_user_department = $principal_user_dept

Condition OR avec non-existence

Si vous appliquez une condition OR entre deux variables d'événement distinctes et que la règle correspond à une non-existence, la règle est compilée, mais peut générer des détections de faux positifs.

Par exemple, la syntaxe de règle suivante peut correspondre à des événements ayant $event_a.field = "something", même si ce n'est pas le cas :

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

Solution

Séparez les vérifications de non-existence en blocs individuels pour chaque variable afin de maintenir l'intégrité de la logique.

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

condition:
  $event_a and #event_b >= 0

Arithmétique avec des champs d'événements non signés

Si vous essayez d'utiliser une constante entière dans une opération arithmétique avec un champ UDM dont le type est un entier non signé, vous recevrez une erreur. Exemple :

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

Les constantes entières standards sont définies par défaut sur des entiers signés, qui sont incompatibles avec les champs UDM définis comme des entiers non signés, tels que network.received_bytes.

Solution

Vous pouvez contourner cette erreur en forçant la constante entière à se comporter comme un float via une opération de division.

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

Enrichissement GeoIP et cohérence à terme

Le système privilégie la vitesse par rapport à la précision immédiate lors des étapes d'enrichissement initiales (streaming et sensibilité à la latence), ce qui peut entraîner des données manquantes et des faux positifs potentiels. Le système continue d'enrichir les données en arrière-plan, mais les données peuvent ne pas être disponibles lorsque la règle est exécutée. Cela fait partie du processus normal de cohérence à terme.

Pour éviter les faux positifs causés par le délai d'enrichissement, vérifiez explicitement que le champ n'est pas vide avant d'évaluer sa valeur.

Prenons l'exemple de cet événement de règle :

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

La règle repose sur le fait que l'événement doit avoir $e.principal.ip_geo_artifact.network.asn = "16509" ET $e.principal.ip_geo_artifact.location.country_or_region = "United Kingdom", qui sont tous deux des champs enrichis. Si l'enrichissement n'est pas terminé à temps, la règle génère un faux positif.

Pour éviter cela, une meilleure vérification de cette règle serait la suivante :

$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"

Cette règle élimine la possibilité que l'événement soit déclenché par des adresses IP avec l'ASN 16509, mais situées en dehors du Royaume-Uni. Cela améliore la précision globale de la règle.

Découvrez comment résoudre les problèmes liés au délai d'enrichissement.

Dépannage

Cette section décrit les attentes en termes de performances et fournit des solutions en libre-service pour les problèmes courants où le comportement de détection en direct diffère des résultats des tests.

Événements futurs

Les règles multi-événements sont conçues pour traiter les événements dans l'ordre chronologique par rapport à l'ingestion. Si vous spécifiez et activez une règle multi-événements, elle ne crée pas de détections pour les événements avec des horodatages futurs, par exemple lorsque event.timestamp comporte une date et une heure définies après ingest.timestamp.

Délai d'enrichissement

Google SecOps privilégie la vitesse d'ingestion pour exposer les alertes initiales le plus rapidement possible. Toutefois, les processus d'enrichissement en arrière-plan, tels que la résolution des métadonnées GeoIP, ASN ou UDM, suivent un modèle de cohérence à terme.

Exécution initiale (T₀)

Le moteur en direct peut évaluer une règle avant la fin de l'enrichissement en arrière-plan. Selon que votre logique repose sur des champs enrichis pour les détections ou les exclusions, cela peut entraîner les écarts temporaires suivants :

  • Faux négatifs (délai de détection) : il s'agit d'un résultat courant. Si une règle dépend d'un champ enrichi pour se déclencher (par exemple, target.user.department == "Finance") et que ce champ est null, la règle ne correspond pas lors de l'exécution initiale.

  • Faux positifs (exclusion manquée) : si votre règle utilise des champs enrichis pour filtrer les activités connues (par exemple, NOT target.ip_geo_country == "US"), la règle peut déclencher un faux positif, car les données d'"exclusion" n'ont pas encore été appliquées.

Exécutions de régularisation

Ces exécutions en arrière-plan réévaluent les données après un délai (par exemple, 45 minutes ou 30 heures). Cela "régularise" les états de détection comme suit :

  • Détections tardives : les événements qui étaient des "faux négatifs" à T₀ génèrent désormais une détection une fois l'enrichissement finalisé.

  • Correction : tous les faux positifs T₀ restent dans le système, mais les données entièrement enrichies sont visibles dans le visualiseur UDM pour le tri manuel.

Écart entre les tests

L'outil Exécuter le test fonctionne sur des données historiques déjà réconciliées. Étant donné que les données sont entièrement enrichies au moment où vous exécutez un test manuel, vous pouvez voir immédiatement les résultats de la "régularisation". Cela signifie que vous ne verrez pas les faux négatifs T₀ ni les faux positifs basés sur l'exclusion qui se sont produits lors de l'exécution initiale en direct.

Correction des erreurs

Utilisez le tableau suivant pour résoudre les écarts entre les alertes en direct et les résultats des tests.

Problème Description Solution exploitable
Échec de l'exclusion Une règle se déclenche malgré une exclusion (par exemple, != "ASN_123"), car le champ était nul lors de l'exécution initiale. Ajoutez une vérification non nulle à la section des événements pour vous assurer que les données sont enrichies avant l'évaluation, par exemple :

$e.principal.ip_geo_artifact.network.asn != ""
Correspondance en direct par rapport au test Les règles en direct déclenchent des alertes, mais l'exécution du test sur les mêmes données affiche "No Results". Ajoutez $e.field != "" qui vérifie tous les champs enrichis (GeoIP, ASN, File Path) pour synchroniser le comportement en direct et historique.
Métadonnées manquantes Les détections apparaissent dans le tableau de bord avec des champs GeoIP ou File Path vides. Ce comportement est normal pour les exécutions T0. Pour résoudre ce problème, incluez une vérification field != "" ou augmentez le décalage de la première exécution dans votre calendrier d'exécution pour laisser plus de temps à l'ingestion.

Validation et test

Pour vérifier qu'une règle gère correctement l'enrichissement différé, procédez comme suit :

  1. Identifier le délai : recherchez une détection que vous pensez être un faux positif. Dans la colonne Type de détection, recherchez l'icône <span class="material-icons">lightbulb</span>. Les alertes sans cette icône proviennent de l'exécution initiale où le délai d'enrichissement est le plus courant.

  2. Mettre à jour la logique des règles : ajoutez une vérification field != "" pour tous les points de données enrichis utilisés dans votre logique.
    Exemple (chemin d'accès au fichier) :
    $e.target.process.parent_process.file.full_path != ""

  3. Tester et vérifier :

    • Utilisez la fonctionnalité Exécuter le test pour vous assurer que votre logique correspond toujours aux données historiques prévues.
    • Vérifiez que la règle ne se déclenche (ou exclut correctement) que lors des exécutions de régularisation une fois les champs d'enrichissement renseignés.

Pour en savoir plus, consultez Gérer votre calendrier d'exécution des règles et Configurer des calendriers personnalisés pour les règles.

Vous avez encore besoin d'aide ? Obtenez des réponses auprès des membres de la communauté et des professionnels Google SecOps.