Présentation du langage YARA-L 2.0

YARA-L 2.0 est un langage informatique utilisé pour la création de règles de recherche dans les données de journaux d'entreprise, qui sont ingérées dans votre compte Chronicle. La syntaxe YARA-L est dérivée du langage YARA développé par VirusTotal. Ce langage fonctionne en association avec le moteur de détection Chronicle et vous permet de rechercher des menaces et d'autres événements sur de grands volumes de données. Consultez également la page Syntaxe du langage YARA-L 2.0.

Structure de la règle

Pour YARA-L 2, vous devez spécifier des déclarations, des définitions et des utilisations de variables dans l'ordre suivant:

  1. Meta
  2. événement
  3. correspondance (facultatif)
  4. condition

Voici la structure générique d'une règle:

rule <rule Name>
{
  meta:
    // Stores arbitrary key-value pairs of rule details, such as who wrote
    // it, what it detects on, version control, etc.
    // Identical to the meta section in YARA-L.
    //
    // For example:
    // author = "Analyst #2112"
    // date = "08/09/2020"
    // description = "suspicious domain detected"

  events:
    // Conditions to filter events and the relationship between events.

  match:
    // Values to return when matches are found.

  condition:
    // Condition to check events and the variables used to find matches.
}

Exemples de règles YARA-L 2.0

Les exemples suivants présentent des règles écrites en YARA-L 2.0. Chacune montre comment mettre en corrélation les événements dans le langage de la règle.

Connexions depuis différentes villes

La règle suivante recherche les utilisateurs qui se sont connectés à votre entreprise depuis au moins deux villes en moins de 5 minutes:

rule DifferentCityLogin {
  meta:

  events:
    $udm.metadata.event_type = "USER_LOGIN"
    $udm.principal.user.userid = $user
    $udm.principal.location.city = $city

  match:
    $user over 5m

  condition:
    #city > 1
}

Variable de correspondance: $user

Variable d'événement:$udm

Variable d'espace réservé: $city $user

La règle suivante décrit le fonctionnement de cette règle:

  • Regroupe les événements avec le nom d'utilisateur ($user) et renvoie cette valeur ($user) lorsqu'une correspondance est trouvée.
  • La période est de 5 minutes, ce qui signifie que seuls les événements séparés par moins de cinq minutes sont corrélés.
  • Recherchez un groupe d'événements ($udm) dont le type d'événement est USER_LOGIN.
  • Pour ce groupe d'événements, la règle appelle l'ID utilisateur ($user) et la ville de connexion ($city.).
  • Renvoie une correspondance si le nombre distinct de valeurs $city est supérieur à 1 dans le groupe d'événements ($udm) pendant la période de cinq minutes.

Création et suppression rapides d'utilisateurs

La règle suivante recherche les utilisateurs qui ont été créés, puis supprimés dans un délai de quatre heures:

  rule UserCreationThenDeletion {
  meta:

  events:
    $create.target.user.userid = $user
    $create.metadata.event_type = "USER_CREATION"

    $delete.target.user.userid = $user
    $delete.metadata.event_type = "USER_DELETION"

    $create.metadata.event_timestamp.seconds <=
       $delete.metadata.event_timestamp.seconds

  match:
    $user over 4h

  condition:
    $create and $delete
}

Variables d'événements:$create et $delete

Variable de correspondance: $user

Variable d'espace réservé: N/A

La règle suivante décrit le fonctionnement de cette règle:

  • Regroupe les événements avec le nom d'utilisateur ($user) et renvoie cette valeur ($user) lorsqu'une correspondance est trouvée.
  • La période est de quatre heures, ce qui signifie que seuls les événements séparés par moins de quatre heures sont corrélés.
  • Recherche deux groupes d'événements ($create et $delete, où $create équivaut à #create >= 1).
  • $create correspond aux événements USER_CREATION et appelle l'ID utilisateur en tant que $user.
  • $user permet de joindre les deux groupes d'événements.
  • $delete correspond aux événements USER_DELETION et appelle l'ID utilisateur en tant que $user. Cette règle recherche une correspondance où l'identifiant utilisateur des deux groupes d'événements est identique.
  • Cette règle recherche les cas où l'événement $delete se produit après l'événement $create et renvoie une correspondance lorsqu'il est découvert.

Événement unique ou multi-événement

Les exemples de règles suivants montrent comment créer une règle pour rechercher un seul événement, puis la modifier afin de rechercher plusieurs événements.

Voici la version d'événement unique de la règle:

rule SingleEventRule {
  meta:
    author = "noone@altostrat.com"

  events:
    $e.metadata.event_type = "USER_LOGIN"

  condition:
    $e
}

Cette règle recherche simplement un événement de connexion utilisateur et renvoie le premier événement rencontré dans les données d'entreprise stockées dans votre compte Chronicle.

Voici une version à plusieurs événements de la règle:

rule MultiEventRule {
  meta:
    author = "noone@altostrat.com"

  events:
    $e.metadata.event_type = "USER_LOGIN"
    $e.principal.user.userid = $user

  match:
    $user over 10m

  condition:
    #e >= 10
}

La règle recherche un utilisateur qui s'est connecté au moins 10 fois en moins de 10 minutes.

Événement unique dans la plage d'adresses IP

L'exemple suivant illustre une règle d'événement unique recherchant une correspondance entre deux utilisateurs spécifiques et une plage d'adresses IP spécifique:

rule OrsAndNetworkRange {
  meta:
    author = "noone@altostrat.com"

  events:
    // Checks CIDR ranges.
    net.ip_in_range_cidr($e.principal.ip, "203.0.113.0/24")

    // Detection when the hostname field matches either value using or.
    $e.principal.hostname = /pbateman/ or $e.principal.hostname = /sspade/

  condition:
    $e
}

Champs répétés

Dans YARA-L 2.0, les champs répétés sont représentés par des tableaux.

Par exemple, un hôte peut avoir plusieurs adresses IP:

principal.ip [192.168.1.2, 10.3.4.100, 192.168.12.16]

Une adresse e-mail peut également avoir plusieurs destinataires:

network.email.to ["a@google.com", "b@google.com", "c@google.com"]

Syntaxe

Les champs répétés peuvent être référencés de la même manière que les champs non répétés. Dans ce cas, elles sont automatiquement ambigu Ins, ce qui signifie que les conditions sont vérifiées par rapport aux éléments individuels du champ répété.

Par exemple, si vous incluez l'instruction suivante dans une règle:

$e.principal.ip = "192.168.12.16"

Chronicle recherche une adresse IP dans le tableau qui correspond à "192.168.12.16". Dans cet exemple, une adresse correspondante est trouvée et une détection est renvoyée.

Par exemple, si vous incluez l'instruction suivante dans une règle:

$e.principal.ip = "192.168.12.16" and $e.principal.ip = "10.3.4.100"

Chronicle recherche une adresse IP dans le tableau qui correspond à la fois à "192.168.12.16" et "10.3.4.100". Dans cet exemple, aucune adresse correspondante n'est trouvée et aucune détection n'est renvoyée.

Exemple de champs répétés

La règle suivante recherche les événements où une adresse IP source s'est connectée à une adresse IP cible tout en envoyant des requêtes à plus de 50 ports cibles différents dans un délai inférieur à une minute. Il s'agit probablement d'une entité malveillante qui recherche un port réseau non sécurisé.

rule RepeatedFieldsRuleExample {
  meta:
    author = "noone@google.com"

  events:
    $e.principal.ip = $source_ip
    $e.target.ip = $target_ip
    $e.target.port = $target_port

  match:
    $source_ip, $target_ip over 1m

  condition:
    #target_port > 50
}

tous les opérateurs

Les champs répétés peuvent également être référencés avec les opérateurs any et all. Si tel est le cas, elles ne sont pas ambigu,s, ce qui signifie que les conditions sont vérifiées par rapport à tous les éléments du champ répété.

Par exemple, si vous incluez l'instruction suivante dans une règle:

any $e.principal.ip = "192.168.12.16"

Chronicle vérifie si une adresse IP du tableau correspond à "192.168.12.16". Dans cet exemple, le tableau satisfait à la vérification et renvoie une détection.

Si vous incluez la déclaration suivante dans la règle:

all $e.principal.ip = "192.168.12.16"

Chronicle vérifie si toutes les adresses IP du tableau correspondent à "192.168.12.16". Dans cet exemple, le tableau ne satisfait pas à la vérification et ne renvoie pas de détection.

Si vous incluez la déclaration suivante dans la règle:

any $e.principal.ip = "192.168.12.16" and any $e.principal.ip = "10.3.4.100"

Chronicle vérifie si une adresse IP du tableau correspond à "192.168.12.16" et si une adresse IP du tableau correspond à "10.3.4.100". Dans cet exemple, le tableau satisfait à la vérification et renvoie une détection.

Voici des exemples de prédicats valides qui utilisent les opérateurs any et all:

  • any $e.principal.ip = "192.168.12.16"
  • net.ip_in_range_cidr(any $e.principal.ip, "192.168.12.16/24")
  • all $e.network.email.to = /.*@google\.com/
  • re.regex(all $e.network.email.to, `.*google\.com`)

Voici des exemples de prédicats non valides qui utilisent les opérateurs any et all:

  • any $ip = "192.168.12.16"
  • any $e.principal.ip = all $e.target.ip
  • any $e.principal.ip in %reference_list

Limites de tous les opérateurs

Les opérateurs any et all ne peuvent être utilisés qu'avec des champs répétés. En outre, elles ne peuvent pas être utilisées lors de l'attribution d'un champ répété à une variable d'espace réservé ou lors de l'association avec un champ d'un autre événement.

Par exemple, any $e.principal.ip = $ip et any $e1.principal.ip = $e2.principal.ip ne sont pas des syntaxes valides. Pour mettre en correspondance un champ répété ou le joindre, utilisez $e.principal.ip = $ip. Il existe une valeur de variable de correspondance ou une jointure pour chaque élément du champ répété.

Lorsque vous écrivez une condition avec any ou all, sachez que la spécification de la condition avec not peut ne pas avoir la même signification que l'utilisation de l'opérateur inversé.

Exemple :

  • not all $e.principal.ip = "192.168.12.16" vérifie si toutes les adresses IP ne correspondent pas à "192.168.12.16", ce qui signifie que la règle vérifie si une adresse IP ne correspond pas à "192.168.12.16".
  • all $e.principal.ip != "192.168.12.16" vérifie si toutes les adresses IP ne correspondent pas à "192.168.12.16", ce qui signifie que la règle vérifie qu'aucune adresse IP ne correspond à "192.168.12.16".

exemple de règle applicable à tous

La règle suivante recherche les événements de connexion pour lesquels toutes les adresses IP sources ne correspondent pas à une adresse IP connue pour être sécurisée dans un délai de 5 minutes.

rule SuspiciousIPLogins {
  meta:
    author = "noone@google.com"

  events:
    $e.metadata.event_type = "USER_LOGIN"

    // Detects if all source IP addresses in an event do not match "100.97.16.0"
    // For example, if an event has source IP addresses
    // ["100.97.16.1", "100.97.16.2", "100.97.16.3"],
    // it will be detected since "100.97.16.1", "100.97.16.2",
    // and "100.97.16.3" all do not match "100.97.16.0".

    all $e.principal.ip != "100.97.16.0"

    // Assigns placeholder variable $ip to the $e.principal.ip repeated field.
    // There will be one detection per source IP address.
    // For example, if an event has source IP addresses
    // ["100.97.16.1", "100.97.16.2", "100.97.16.3"],
    // there will be one detection per address.

    $e.principal.ip = $ip

  match:
    $ip over 5m

  condition:
    $e
}

Expressions régulières dans une règle

L'exemple d'expression régulière YARA-L 2.0 suivant recherche les événements avec des e-mails provenant du domaine altostrat.com. Depuisnocase a été ajouté au$host variableregex comparaison et laregex Ces deux comparaisons ne sont pas sensibles à la casse.

rule RegexRuleExample {
  meta:
    author = "noone@altostrat.com"

  events:
    $e.principal.hostname = $host
    $host = /.*HoSt.*/ nocase
    re.regex($e.network.email.from, `.*altostrat\.com`) nocase

  match:
    $host over 10m

  condition:
    #e > 10
}

Fenêtres coulissantes YARA-L

Par défaut, les règles YARA-L 2.0 sont évaluées à l'aide des fenêtres de saut. Une période de données d'événement d'entreprise est divisée en un ensemble de fenêtres de saut qui se chevauchent, chacune ayant la durée spécifiée dans la section match. Les événements sont ensuite corrélés à l'intérieur de chaque fenêtre de saut. Avec les fenêtres de saut, il n'est pas possible de rechercher des événements qui se produisent dans un ordre spécifique (par exemple, e1 se produit jusqu'à deux minutes après e2). Une occurrence de l'événement e1 et d'une occurrence e2 sont corrélées tant qu'elles se situent dans la durée de la période de saut entre elles.

Les règles peuvent également être évaluées à l'aide de fenêtres glissantes. Avec les fenêtres coulissantes, les fenêtres glissantes avec la durée spécifiée dans la section match sont générées au début ou à la fin d'une variable d'événement de tableau croisé dynamique spécifiée. Les événements sont ensuite corrélés au sein de chaque fenêtre glissante. Cela permet de rechercher des événements qui se produisent dans un ordre spécifique (par exemple, e1 se produit dans les deux minutes suivant e2). Une occurrence de l'événement e1 et d'une occurrence e2 est corrélée si l'événement e1 se produit pendant la période de glissement qui suit l'événement e2.

Syntaxe des règles de fenêtre glissante

Spécifiez les fenêtres coulissantes dans la section de correspondance d'une règle comme suit:

<match-variable-name-1>, <match-variable-name-2>, ... over <sliding-window- duration> before|after <pivot-event-variable-name>

La variable d'événement de pivotement est la variable d'événement sur laquelle les fenêtres glissantes sont basées. Si vous utilisez le mot clé before, des fenêtres glissantes sont générées, se terminant par chaque occurrence de l'événement de tableau croisé dynamique. Si le mot clé after est utilisé, les fenêtres glissantes sont générées à chaque occurrence de l'événement de tableau croisé dynamique.

Exemple de règle de fenêtre glissante

L'exemple de fenêtre glissante YARA-L 2.0 suivant recherche l'absence d'événements firewall_2 après les événements firewall_1. Le mot clé after est utilisé avec la variable d'événement de tableau croisé dynamique $e1 pour spécifier que seules les fenêtres de 10 minutes après chaque événement firewall_1 doivent être vérifiées lors de la corrélation des événements.

rule SlidingWindowRuleExample {
  meta:
    author = "noone@google.com"

  events:
    $e1.metadata.product_name = "firewall_1"
    $e1.principal.hostname = $host

    $e2.metadata.product_name = "firewall_2"
    $e2.principal.hostname = $host

  match:
    $host over 10m after $e1

  condition:
    $e1 and !$e2
}