Présentation du langage YARA-L 2.0
YARA-L 2.0 est un langage informatique qui permet de créer des règles de recherche dans les données des journaux de votre entreprise lorsqu'elles sont ingérées dans votre instance Google Security Operations. La syntaxe YARA-L est dérivée du langage YARA développé par VirusTotal. Ce langage fonctionne avec le moteur de détection des opérations de sécurité de Google et vous permet de traquer les menaces et d'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 montrent des règles écrites en YARA-L 2.0. Chacun d'eux montre comment corréler des événements dans le langage des règles.
Règles et réglage
La règle suivante recherche des schémas spécifiques dans les données d'événement et crée un
s'il trouve les modèles. Cette règle inclut une variable $e1
pour suivre le type d'événement et le champ UDM metadata.event_type
. La règle recherche des occurrences spécifiques de correspondances d'expressions régulières avec e1
. Lorsque l'événement $e1
a lieu, 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 à partir de différentes 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
Le fonctionnement de cette règle est décrit ci-dessous:
- Regroupe les événements avec le nom d'utilisateur (
$user
) et le renvoie ($user
) lorsqu'une correspondance est trouvée. - La période est de cinq minutes, ce qui signifie que seuls les événements espacés de moins de cinq minutes 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
(représenté par#city
) est supérieur à 1 dans le groupe d'événements ($udm
) au cours de la période de cinq minutes.
Création et suppression rapides de comptes utilisateur
La règle suivante recherche les comptes utilisateur 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
Le fonctionnement de cette règle est décrit ci-dessous:
- Regroupe les événements avec le nom d'utilisateur (
$user
) et le renvoie ($user
) lorsqu'une correspondance est trouvée. - La période est de quatre heures. Cela 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énementsUSER_CREATION
et appelle l'ID utilisateur sous le nom$user
.$user
permet de joindre les deux groupes d'événements.$delete
correspond aux événementsUSER_DELETION
et appelle l'ID utilisateur sous le nom$user
. Cette règle recherche une correspondance dans laquelle l'identifiant utilisateur est le même dans les deux groupes d'événements.- Cette règle recherche les cas où l'événement de
$delete
se produit plus tard que celui de$create
, et renvoie une correspondance lorsqu'elle est détectée.
Règle d'événement unique
Les règles d'événement unique sont des règles corrélées sur un seul événement. Une règle d'événement peut être :
- Toute règle sans section de correspondance.
- Règle comportant une section
match
et une sectioncondition
ne vérifiant que 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 qu'elle rencontre dans les données d'entreprise stockées dans votre compte Google Security Operations :
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 avec 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 s'il existe un événement de connexion utilisateur.
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 plusieurs événements
Utilisez plusieurs règles d'événement pour regrouper de nombreux événements sur une période spécifiée et essayer de trouver des corrélations entre eux. Une règle d'événement multiple type se présente comme suit :
- 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
}
Un seul événement 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
}
exemple de règle "any" et "all"
La règle suivante recherche les événements de connexion dont les adresses IP sources ne correspondent pas à une adresse IP considérée 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 associés à des e-mails provenant du domaine altostrat.com. Étant donné que 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 de
firewall_2
événements après firewall_1
événements. Le mot clé after
est utilisé avec
la variable d'événement de tableau croisé dynamique $e1
pour spécifier que les fenêtres de 10 minutes
L'événement firewall_1
doit être vérifié en cas de 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 valeurs nulles
Le moteur de règles filtre implicitement les valeurs zéro pour tous les espaces réservés
utilisées dans la section match
.
Pour en savoir plus, consultez la section Gestion des valeurs nulles dans la section match
.
Vous pouvez désactiver cette fonctionnalité en utilisant l'option allow_zero_values
décrit dans la section 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 ces 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 règle avec section outcome
Vous pouvez ajouter la section facultative outcome
dans la règle YARA-L 2.0 pour extraire
des informations supplémentaires sur chaque détection. Dans la section "Condition", vous pouvez également spécifier
des conditions sur les
variables de résultat. Vous pouvez utiliser la section outcome
d'une détection
afin de définir des variables pour la consommation en aval. Par exemple, vous pouvez définir
un score de gravité basé sur les données
des événements analysés.
Pour en savoir plus, consultez les ressources suivantes :
- Syntaxe de la section "Résultats"
- Syntaxe des conditions de résultat
- Présentation de la section
outcome
Règle multi-événement avec section "Résultat" :
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 cinq minutes,
puis un score de gravité est appliqué. Lorsque vous incluez une période dans la section match
,
la règle s'applique dans 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'événement unique avec section "Résultat" :
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énements en une règle de résultat unique.
Vous pouvez utiliser la section outcome
pour les règles à un seul événement (c'est-à-dire les règles sans élément
match
) et les règles multi-événements (règles comportant une section match
).
Si vous avez précédemment conçu une règle multi-événement afin de pouvoir utiliser la section "Résultat", vous pouvez éventuellement réorganiser ces règles en supprimant la section match
pour améliorer les performances. Étant donné que votre règle
comporte une section match
qui applique le regroupement,
vous pourriez recevoir
plus de détections. Cette refactorisation n'est
est possible pour les règles qui utilisent une variable d'événement, comme indiqué dans
dans l'exemple suivant.
Règle de résultat multi-événements qui n'utilise qu'une seule variable d'événement (une est 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 ne concernera désormais qu'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 règle de fonction vers 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 la section match
, la section outcome
ou la section 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'exemple de condition de résultat
Dans la section condition
, vous pouvez utiliser les variables de résultat qui ont été définies
dans la section outcome
. L'exemple suivant montre comment filtrer
des scores de risque pour réduire le bruit dans les détections en utilisant des conditions de résultat.
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
}