Detection rules › YARA-L
YARA-L rules: 14
GCP Service Account Key Used From Multiple Countries
#Detects usage of service account key from multiple countries using Chronicle GeoIP enrichment.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Credential Access |
Rule Body
// Copyright 2024 Google LLC. Licensed under Apache-2.0.
rule gcp_service_account_key_used_from_multiple_countries {
meta:
author = "Google Cloud Security"
description = "Detects usage of service account key from multiple countries using Chronicle GeoIP enrichment."
rule_id = "mr_dbc9cf09-7c2d-4c9e-b9d4-60df60f360a1"
rule_name = "GCP Service Account Key Used From Multiple Countries"
mitre_attack_tactic = "Credential Access"
mitre_attack_technique = "Unsecured Credentials: Private Keys"
mitre_attack_url = "https://attack.mitre.org/techniques/T1552/004/"
mitre_attack_version = "v14.1"
type = "Alert"
data_source = "GCP Cloud Audit"
platform = "GCP"
severity = "Low"
priority = "Low"
events:
$gcp.metadata.log_type = "GCP_CLOUDAUDIT"
$gcp.security_result.action = "ALLOW"
$gcp.principal.ip_geo_artifact.location.country_or_region != ""
$gcp.principal.ip_geo_artifact.network.organization_name != /google/
$gcp.security_result.detection_fields["key_id"] = $sa_key_id
match:
$sa_key_id over 1h
outcome:
$risk_score = max(35)
$mitre_attack_tactic = "Credential Access"
$mitre_attack_technique = "Unsecured Credentials: Private Keys"
$mitre_attack_technique_id = "T1552.004"
$event_count = count_distinct($gcp.metadata.id)
$network_http_user_agent = array_distinct($gcp.network.http.user_agent)
$principal_ip = array_distinct($gcp.principal.ip)
$principal_ip_country = array_distinct($gcp.principal.ip_geo_artifact.location.country_or_region)
$dc_principal_ip_country = count_distinct($gcp.principal.ip_geo_artifact.location.country_or_region)
$principal_ip_state = array_distinct($gcp.principal.ip_geo_artifact.location.state)
$principal_user_display_name = array_distinct($gcp.principal.user.user_display_name)
$target_resource_name = array_distinct($gcp.target.resource.name)
$sa_key_name = array_distinct($gcp.security_result.detection_fields["service_account_key_name"])
condition:
$gcp and $dc_principal_ip_country > 2
}
YARA-L Rule Structure
Condition
Fires when at least one $gcp event in the 1h window and $dc_principal_ip_country > 2.
Events
$gcp
metadata.log_type = "GCP_CLOUDAUDIT"security_result.action = "ALLOW"principal.ip_geo_artifact.location.country_or_region is not nullprincipal.ip_geo_artifact.network.organization_name matches "google"
Match and Correlation
Outcome
Outcome variables add context to a detection. When the rule generates an alert, $risk_score is displayed with it.
| Field | Expression |
|---|---|
risk_score | max(35) |
event_count | count_distinct($gcp.metadata.id) |
network_http_user_agent | array_distinct($gcp.network.http.user_agent) |
principal_ip | array_distinct($gcp.principal.ip) |
principal_ip_country | array_distinct($gcp.principal.ip_geo_artifact.location.country_or_region) |
dc_principal_ip_country | count_distinct($gcp.principal.ip_geo_artifact.location.country_or_region) |
principal_ip_state | array_distinct($gcp.principal.ip_geo_artifact.location.state) |
principal_user_display_name | array_distinct($gcp.principal.user.user_display_name) |
target_resource_name | array_distinct($gcp.target.resource.name) |
sa_key_name | array_distinct($gcp.security_result.detection_fields["service_account_key_name"]) |
Google Workspace Alerts Aggregated By Severity
#Generates alerts based on Google Workspace alerts center and aggregates them based on severity.
Rule Body
// Copyright 2023 Google LLC. Licensed under Apache-2.0.
rule google_workspace_alerts_aggregated_by_severity {
meta:
author = "Google Cloud Security"
description = "Generates alerts based on Google Workspace alerts center and aggregates them based on severity."
rule_id = "mr_311cc4ab-627b-43a1-a744-8d7aa5e44fbf"
rule_name = "Google Workspace Alerts Aggregated By Severity"
type = "Alert"
data_source = "Workspace Alerts"
events:
$ws.metadata.vendor_name = "Google Workspace"
$ws.metadata.product_name = "Google Workspace Alerts"
$ws.security_result.severity = $severity
match:
$severity over 1h
outcome:
$risk_score = max(30 +
if($ws.security_result.severity = "LOW", 10)+
if($ws.security_result.severity = "MEDIUM", 30)+
if($ws.security_result.severity = "HIGH", 50)
)
$event_count = count_distinct($ws.metadata.id)
$event_type = array_distinct($ws.metadata.event_type)
$product_event_type = array_distinct($ws.metadata.product_event_type)
$security_category_details = array_distinct($ws.security_result.category_details)
$security_category = array_distinct($ws.security_result.category)
$security_investigation_tool_link = array_distinct($ws.security_result.detection_fields["security_investigation_tool_link"])
$security_summary = array_distinct($ws.security_result.summary)
$alert_severity = array_distinct($ws.security_result.severity)
condition:
$ws
}
YARA-L Rule Structure
Condition
Fires when at least one $ws event in the 1h window.
Events
$ws
Match and Correlation
Outcome
Outcome variables add context to a detection. When the rule generates an alert, $risk_score is displayed with it.
| Field | Expression |
|---|---|
risk_score | max(30 + if($ws.security_result.severity = "LOW", 10)+ if($ws.security_result.severity = "MEDIUM", 30)+ if($ws.security_result.severity = "HIGH", 50) ) |
event_count | count_distinct($ws.metadata.id) |
event_type | array_distinct($ws.metadata.event_type) |
product_event_type | array_distinct($ws.metadata.product_event_type) |
security_category_details | array_distinct($ws.security_result.category_details) |
security_category | array_distinct($ws.security_result.category) |
security_investigation_tool_link | array_distinct($ws.security_result.detection_fields["security_investigation_tool_link"]) |
security_summary | array_distinct($ws.security_result.summary) |
alert_severity | array_distinct($ws.security_result.severity) |
O365 Recently Created Entra ID User Assigned Roles
#Detects when a user is created in Entra ID and assigned roles within a defined time window.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Persistence |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Microsoft 365 | Add member to role. |
| Microsoft 365 | Add user. |
Rules Detecting the Same Action
These rules filter on the same operation.
- M365 Identity Global Administrator Role Assigned (Elastic)
- O365 Add User To Admin Role (YARA-L)
Rule Body
// Copyright 2023 Google LLC. Licensed under Apache-2.0.
rule o365_recently_created_entra_id_user_assigned_roles {
meta:
author = "Google Cloud Security"
description = "Detects when a user is created in Entra ID and assigned roles within a defined time window."
rule_id = "mr_c0406a96-4ed1-4dd2-9629-aa5a2c881222"
rule_name = "O365 Recently Created Entra ID User Assigned Roles"
tactic = "TA0003"
technique = "T1098.003"
assumption = "The list msgraph_watchlist_roles is populated with role names, ie Application Administrator"
type = "alert"
platform = "azure"
data_source = "o365"
severity = "Medium"
priority = "Medium"
events:
(
$create.metadata.event_type = "USER_CREATION" and
$create.metadata.product_event_type = "Add user." and
$create.metadata.product_name = "Office 365" and
$create.security_result.action = "ALLOW" and
$create.target.user.userid = $userid
)
$create.metadata.event_timestamp.seconds < $role.metadata.event_timestamp.seconds
(
$role.metadata.event_type = "USER_UNCATEGORIZED" and
$role.metadata.product_event_type = "Add member to role." and
$role.metadata.product_name = "Office 365" and
$role.security_result.action = "ALLOW" and
//The reference list msgraph_watchlist_roles matches on the role name. List contents example row: Global Administrator //manage all aspects of Azure AD and Microsoft services that use Azure AD identities 62e90394-69f5-4237-9190-012177145e10
//If you wanted to detect on specific roles, they could be added to a reference list and the following line uncommented
//$role.target.resource.attribute.roles.name in %msgraph_watchlist_roles and
$role.target.user.userid = $userid
)
match:
$userid over 90m
outcome:
$risk_score = max(if($role.target.resource.attribute.roles.name = /Administrator/ nocase, 85, 35))
$security_summary = array_distinct($role.security_result.summary)
$user_agent = array_distinct($role.network.http.user_agent)
$assigned_role = array_distinct($role.target.resource.attribute.roles.name)
//added to populate alert graph with additional context
$principal_user_userid = array_distinct($create.principal.user.userid)
$target_user_userid = array_distinct($create.target.user.userid)
condition:
$create and $role
}
YARA-L Rule Structure
Condition
Fires when at least one $create event in the 90m window and at least one $role event in the 90m window.
Events
$create
metadata.product_event_type = "Add user."security_result.action = "ALLOW"
$role
metadata.product_event_type = "Add member to role."security_result.action = "ALLOW"
Match and Correlation
Outcome
Outcome variables add context to a detection. When the rule generates an alert, $risk_score is displayed with it.
| Field | Expression |
|---|---|
risk_score | max(if($role.target.resource.attribute.roles.name = /Administrator/ nocase, 85, 35)) |
security_summary | array_distinct($role.security_result.summary) |
user_agent | array_distinct($role.network.http.user_agent) |
assigned_role | array_distinct($role.target.resource.attribute.roles.name) |
principal_user_userid | array_distinct($create.principal.user.userid) |
target_user_userid | array_distinct($create.target.user.userid) |