Présentation du langage YARA-L 2.0

YARA-L 2.0 est un langage informatique utilisé pour créer des règles de recherche dans les données de journaux de votre entreprise lorsqu'elles sont ingérées dans votre instance Chronicle. La syntaxe YARA-L est dérivée du langage YARA développé par VirusTotal. Ce langage fonctionne avec le moteur de détection Chronicle et vous permet de traquer les menaces et autres événements sur d'importants volumes de données.

Pour en savoir plus, consultez les ressources suivantes :

Exemples de règles YARA-L 2.0

Les exemples suivants illustrent des règles écrites en YARA-L 2.0. Chacune d'elles montre comment mettre en corrélation des événements dans la langue de la règle.

Règles et réglages

La règle suivante recherche des modèles spécifiques dans les données d'événement et crée une détection si elle les trouve. Cette règle inclut une variable $e1 pour le type d'événement de suivi et un champ UDM metadata.event_type. La règle recherche des occurrences spécifiques de correspondances d'expression régulière avec e1. Lorsque l'événement $e1 se produit, une détection est créée. Une condition not est incluse dans la règle pour exclure certains chemins d'accès non malveillants. Vous pouvez ajouter des conditions not pour éviter les faux positifs.

rule suspicious_unusual_location_svchost_execution
{

 meta:
   author = "Google Cloud Security"
   description = "Windows 'svchost' executed from an unusual location"
   yara_version = "YL2.0"
   rule_version = "1.0"

 events:

   $e1.metadata.event_type = "PROCESS_LAUNCH"
   re.regex($e1.principal.process.command_line, `\bsvchost(\.exe)?\b`) nocase
   not re.regex($e1.principal.process.command_line, `\\Windows\\System32\\`) nocase

condition:

   $e1
}

Connexions depuis d'autres villes

La règle suivante recherche les utilisateurs qui se sont connectés à votre entreprise depuis deux villes ou plus en moins de cinq 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:
    $udm and #city > 1
}

Variable de correspondance: $user

Variable d'événement:$udm

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

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

  • Regroupe les événements avec le nom d'utilisateur ($user) et les renvoie ($user) lorsqu'une correspondance est trouvée.
  • La période est de cinq minutes, ce qui signifie que seuls les événements à moins de cinq minutes d'intervalle sont corrélés.
  • Recherche d'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 (signalé par #city) est supérieur à 1 dans le groupe d'événements ($udm) sur une période de cinq minutes.

Création et suppression rapides des utilisateurs

La règle suivante recherche les utilisateurs qui ont été créés, puis supprimés dans les 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énement:$create et $delete

Variable de correspondance: $user

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

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

  • Regroupe les événements avec le nom d'utilisateur ($user) et les renvoie ($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 de 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 comme $user.
  • $user permet de joindre les deux groupes d'événements.
  • $delete correspond aux événements USER_DELETION et appelle l'ID utilisateur comme $user. Cette règle recherche une correspondance lorsque l'identifiant de l'utilisateur dans les deux groupes d'événements est identique.
  • Cette règle recherche les cas où l'événement de $delete se produit plus tard que l'événement de $create, et renvoie une correspondance lorsqu'il est découvert.

Règle d'événement unique

Les règles à événement unique sont des règles qui s'appliquent à un seul événement. Une seule règle d'événement peut être:

  • Toute règle sans section de correspondance.
  • Règle avec une section match et une section condition qui vérifient uniquement l'existence d'un événement (par exemple, "$e", "#e > 0", "#e >= 1", "1 <= #e", "0 < #e").

Par exemple, la règle suivante recherche 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:

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

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

  condition:
    $e
}

Voici un autre exemple de règle d'événement unique comportant une section de correspondance. Cette règle recherche un utilisateur qui s'est connecté au moins une fois en moins de cinq minutes. Elle vérifie l'existence d'un événement de connexion utilisateur simple.

rule SingleEventRule {
  meta:
    author = "alice@example.com"
    description = "windowed single event example rule"

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

  match:
    $user over 5m

  condition:
    #e > 0
}
rule MultiEventRule{
  meta:
    author = "alice@example.com"
    description = "Rule with outcome condition and simple existence condition on one event variable"

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

  match:
    $user over 10m

  outcome:
    $num_events_in_match_window = count($e.metadata.id)

  condition:
    #e > 0 and $num_events_in_match_window >= 10 // Could be rewritten as #e >= 10
}

Règle pour les événements multiples

Utilisez plusieurs règles d'événement pour regrouper plusieurs événements sur une période donnée et essayez de trouver des corrélations entre les événements. En général, une règle multi-événements se présente comme suit:

  • Une section match qui spécifie la période sur laquelle les événements doivent être regroupés.
  • Une section condition spécifiant la condition qui doit déclencher la détection et vérifier l'existence de plusieurs événements.

Par exemple, la règle suivante recherche un utilisateur qui s'est connecté au moins 10 fois en moins de 10 minutes:

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
}

Événement unique dans une 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
}

exemple de règle "any and all"

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

rule SuspiciousIPLogins {
  meta:
    author = "alice@example.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 permet de rechercher des événements avec des e-mails provenant du domaine altostrat.com. Comme nocase a été ajouté à la comparaison regex de la variable $host et à la fonction regex, 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
}

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 d'événements.

rule SlidingWindowRuleExample {
  meta:
    author = "alice@example.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
}

Exemple d'exclusion de valeur nulle

Le moteur de règles filtre implicitement les valeurs nulles pour tous les espaces réservés utilisés dans la section match. Pour en savoir plus, consultez la section Gestion des valeurs nulles dans la section match. Cela peut être désactivé à l'aide de l'option allow_zero_values comme décrit dans allow_zero_values.

Toutefois, pour les autres champs d'événement référencés, les valeurs nulles ne sont pas exclues, sauf si vous spécifiez explicitement de telles conditions.

rule ExcludeZeroValues {
  meta:
    author = "alice@example.com"

  events:
    $e1.metadata.event_type = "NETWORK_DNS"
    $e1.principal.hostname = $hostname

    // $e1.principal.user.userid may be empty string.
    $e1.principal.user.userid != "Guest"

    $e2.metadata.event_type = "NETWORK_HTTP"
    $e2.principal.hostname = $hostname

    // $e2.target.asset_id cannot be empty string as explicitly specified.
    $e2.target.asset_id != ""

  match:
    // $hostname cannot be empty string. The rule behaves as if the
    // predicate, `$hostname != ""` was added to the events section, because
    // `$hostname` is used in the match section.
    $hostname over 1h

  condition:
    $e1 and $e2
}

Exemple de section de règle avec outcome

Vous pouvez ajouter la section outcome facultative dans la règle YARA-L 2.0 pour extraire des informations supplémentaires de chaque détection. Dans la section "Condition", vous pouvez aussi spécifier des conditions sur les variables de résultat. Vous pouvez utiliser la section outcome d'une règle de détection pour définir des variables de consommation en aval. Par exemple, vous pouvez définir un score de gravité en fonction des données des événements en cours d'analyse.

Pour en savoir plus, consultez les ressources suivantes :

Règle multi-événement avec une section "Résultats" :

La règle suivante examine deux événements pour obtenir la valeur de $hostname. Si la valeur de $hostname correspond sur une période de 5 minutes, un score de gravité est appliqué. Lorsque vous incluez une période dans la section match, la règle vérifie le délai spécifié.

rule OutcomeRuleMultiEvent {
    meta:
      author = "Google Cloud Security"
    events:
      $u.udm.principal.hostname = $hostname
      $asset_context.graph.entity.hostname = $hostname

      $severity = $asset_context.graph.entity.asset.vulnerabilities.severity

    match:
      $hostname over 5m

    outcome:
      $risk_score =
        max(
            100
          + if($hostname = "my-hostname", 100, 50)
          + if($severity = "HIGH", 10)
          + if($severity = "MEDIUM", 5)
          + if($severity = "LOW", 1)
        )

      $asset_id_list =
        array(
          if($u.principal.asset_id = "",
             "Empty asset id",
             $u.principal.asset_id
          )
        )

      $asset_id_distinct_list = array_distinct($u.principal.asset_id)

      $asset_id_count = count($u.principal.asset_id)

      $asset_id_distinct_count = count_distinct($u.principal.asset_id)

    condition:
      $u and $asset_context and $risk_score > 50 and not arrays.contains($asset_id_list, "id_1234")
}

rule OutcomeRuleMultiEvent {
    meta:
      author = "alice@example.com"
    events:
      $u.udm.principal.hostname = $hostname
      $asset_context.graph.entity.hostname = $hostname

      $severity = $asset_context.graph.entity.asset.vulnerabilities.severity

    match:
      $hostname over 5m

    outcome:
      $total_network_bytes = sum($u.network.sent_bytes) + sum($u.network.received_bytes)

      $risk_score = if(total_network_bytes > 1024, 100, 50) +
        max(
          if($severity = "HIGH", 10)
          + if($severity = "MEDIUM", 5)
          + if($severity = "LOW", 1)
        )

      $asset_id_list =
        array(
          if($u.principal.asset_id = "",
             "Empty asset id",
             $u.principal.asset_id
          )
        )

      $asset_id_distinct_list = array_distinct($u.principal.asset_id)

      $asset_id_count = count($u.principal.asset_id)

      $asset_id_distinct_count = count_distinct($u.principal.asset_id)

    condition:
      $u and $asset_context and $risk_score > 50 and not arrays.contains($asset_id_list, "id_1234")
}

Règle d'un seul événement avec une section "Résultats" :

rule OutcomeRuleSingleEvent {
    meta:
        author = "alice@example.com"
    events:
        $u.metadata.event_type = "FILE_COPY"
        $u.principal.file.size = $file_size
        $u.principal.hostname = $hostname

    outcome:
        $suspicious_host = $hostname
        $admin_severity = if($u.principal.userid in %admin_users, "SEVERE", "MODERATE")
        $severity_tag = if($file_size > 1024, $admin_severity, "LOW")

    condition:
        $u
}

Refactorisation d'une règle de résultat multi-événement en une règle de résultat à un seul événement.

Vous pouvez utiliser la section outcome pour les règles d'événement unique (règles sans section match) et pour les règles multi-événements (règles avec une section match). Si vous avez précédemment conçu une règle pour qu'elle soit multi-événements afin de pouvoir utiliser la section des résultats, vous pouvez éventuellement refactoriser ces règles en supprimant la section match pour améliorer les performances. Sachez que, comme votre règle ne comporte plus de section match qui applique le regroupement, il se peut que vous receviez davantage de détections. Cette refactorisation n'est possible que pour les règles qui utilisent une seule variable d'événement, comme illustré dans l'exemple suivant.

Règle de résultat multi-événement qui n'utilise qu'une seule variable d'événement (un bon candidat pour une refactorisation):

rule OutcomeMultiEventPreRefactor {
    meta:
      author = "alice@example.com"
      description = "Outcome refactor rule, before the refactor"

    events:
      $u.udm.principal.hostname = $hostname

    match:
      $hostname over 5m

    outcome:
      $risk_score = max(if($hostname = "my-hostname", 100, 50))

    condition:
      $u
}

Vous pouvez refactoriser la règle en supprimant la section match. Notez que vous devez également supprimer l'agrégation dans la section outcome, car la règle sera désormais associée à un seul événement. Pour en savoir plus sur les agrégations, consultez la section Agrégations des résultats.

rule OutcomeSingleEventPostRefactor {
    meta:
      author = "alice@example.com"
      description = "Outcome refactor rule, after the refactor"

    events:
      $u.udm.principal.hostname = $hostname

    // We deleted the match section.

    outcome:
      // We removed the max() aggregate.
      $risk_score = if($hostname = "my-hostname", 100, 50)

    condition:
      $u
}

Exemple de fonction de règle d'espace réservé

Vous pouvez attribuer une variable d'espace réservé au résultat d'un appel de fonction et l'utiliser dans d'autres sections de la règle, telles que match, outcome ou condition. Consultez l'exemple ci-dessous :

rule FunctionToPlaceholderRule {
    meta:
      author = "alice@example.com"
      description = "Rule that uses function to placeholder assignments"

    events:
        $u.metadata.event_type = "EMAIL_TRANSACTION"

        // Use function-placeholder assignment to extract the
        // address from an email.
        // address@website.com -> address
        $email_to_address_only = re.capture($u.network.email.from , "(.*)@")

        // Use function-placeholder assignment to normalize an email:
        // uid@??? -> uid@company.com
        $email_from_normalized = strings.concat(
            re.capture($u.network.email.from , "(.*)@"),
            "@company.com"
        )

        // Use function-placeholder assignment to get the day of the week of the event.
        // 1 = Sunday, 7 = Saturday.
        $dayofweek = timestamp.get_day_of_week($u.metadata.event_timestamp.seconds)

    match:
        // Use placeholder (from function-placeholder assignment) in match section.
        // Group by the normalized from email, and expose it in the detection.
        $email_from_normalized over 5m

    outcome:
        // Use placeholder (from function-placeholder assignment) in outcome section.
        // Assign more risk if the event happened on weekend.
        $risk_score = max(
            if($dayofweek = 1, 10, 0) +
            if($dayofweek = 7, 10, 0)
        )

    condition:
        // Use placeholder (from function-placeholder assignment) in condition section.
        // Match if an email was sent to multiple addresses.
        #email_to_address_only > 1
}

Exemple de règle d'expressions conditionnelles au résultat

Dans la section condition, vous pouvez utiliser des variables de résultat définies dans la section outcome. L'exemple suivant montre comment filtrer les scores de risque pour réduire le bruit dans les détections à l'aide d'expressions conditionnelles aux résultats.

rule OutcomeConditionalRule {
    meta:
        author = "alice@example.com"
        description = "Rule that uses outcome conditionals"

    events:
        $u.metadata.event_type = "FILE_COPY"
        $u.principal.file.size = $file_size
        $u.principal.hostname = $hostname

        // 1 = Sunday, 7 = Saturday.
        $dayofweek = timestamp.get_day_of_week($u.metadata.collected_timestamp.seconds)

    outcome:
        $risk_score =
            if($file_size > 500*1024*1024, 2) + // Files 500MB are moderately risky
            if($file_size > 1024*1024*1024, 3) + // Files over 1G get assigned extra risk
            if($dayofweek=1 or $dayofweek=7, 4) + // Events from the weekend are suspicious
            if($hostname = /highly-privileged/, 5) // Check for files from highly privileged devices

    condition:
        $u and $risk_score >= 10
}