Detection rules › YARA-L

YARA-L rules: 38

Hunt for Bad Request errors against the Groups endpoint in the Microsoft Graph API

#
Severity
low
Type
Hunt
Time window
5m
Match by
ip, session
Author
Google Cloud Security
Source
github.com/chronicle/detection-rules

Identify a 400 bad request to the groups endpoint in the MS Graph API. GraphRunner's Invoke-SecurityGroupCloner function will trigger this if it fails to duplicate a group.

References

Rule Body

// Copyright 2025 Google LLC. Licensed under Apache-2.0.

rule ms_graph_group_bad_request {

  meta:
    author = "Google Cloud Security"
    description = "Identify a 400 bad request to the groups endpoint in the MS Graph API. GraphRunner's Invoke-SecurityGroupCloner function will trigger this if it fails to duplicate a group."
    rule_id = "mr_09bafa2b-5131-452c-bf5a-021063cfd5c2"
    rule_name = "Hunt for Bad Request errors against the Groups endpoint in the Microsoft Graph API"
    assumption = "This detects all web activity associated with the groups endpoint with a response code 400, normal admin actions could trigger as well. Tune using IP address ranges for admins and user agents."
    reference = "https://github.com/dafthack/GraphRunner/blob/main/GraphRunner.ps1"
    type = "Hunt"
    data_source = "MS Graph Activity Logs"
    platform = "Azure"
    severity = "Low"
    priority = "Low"

  events:
    $api.metadata.event_type = "NETWORK_HTTP"
    $api.metadata.product_event_type = "Microsoft Graph Activity"
    $api.target.url = "https://graph.microsoft.com/v1.0/groups" nocase
    $api.network.http.method = "POST"
    $api.network.http.response_code = 400

    //Can be tuned for specific User Agent strings being used
    //$api.network.http.user_agent = /PowerShell/ nocase
    //SkypeSpaces triggered during testing so filtering this out
    $api.network.http.user_agent != "SkypeSpaces/1.0a$*+"

    $api.principal.ip = $ip
    $api.network.session_id = $session

  match:
    $ip, $session over 5m

  outcome:
    $risk_score = 35
    $event_count = count_distinct($api.metadata.id)
    $requesting_user_guid = array_distinct($api.principal.user.userid)
    $requesting_ip = array_distinct($api.principal.ip)
    $user_agent = array_distinct($api.network.http.user_agent)
    $location = array_distinct($api.principal.location.name)
    $target_application_id_guid = array_distinct($api.target.resource.product_object_id)
    $session_id = array_distinct($api.network.session_id)
    $target_url = array_distinct($api.target.url)

  condition:
    $api
}

YARA-L Rule Structure

Condition

Fires when at least one $api event in the 5m window.

Events

$api NETWORK_HTTP

  • metadata.product_event_type = "Microsoft Graph Activity"
  • target.url = "https://graph.microsoft.com/v1.0/groups"
  • network.http.method = "POST"
  • network.http.response_code = "400"
  • network.http.user_agent != "SkypeSpaces/1.0a$*+"

Match and Correlation

Match key
$ip (principal.ip), $session (network.session_id)
Within
5m

Outcome

Outcome variables add context to a detection. When the rule generates an alert, $risk_score is displayed with it.

FieldExpression
risk_score35
event_countcount_distinct($api.metadata.id)
requesting_user_guidarray_distinct($api.principal.user.userid)
requesting_iparray_distinct($api.principal.ip)
user_agentarray_distinct($api.network.http.user_agent)
locationarray_distinct($api.principal.location.name)
target_application_id_guidarray_distinct($api.target.resource.product_object_id)
session_idarray_distinct($api.network.session_id)
target_urlarray_distinct($api.target.url)

Hunt for the delete method in Microsoft Graph API calls

#
Severity
low
Type
Hunt
Time window
5m
Match by
ip, session
Author
Google Cloud Security
Source
github.com/chronicle/detection-rules

Identify when the http delete method is being called within the Microsoft Graph API.

Rule Body

// Copyright 2025 Google LLC. Licensed under Apache-2.0.

rule ms_graph_delete_method {

  meta:
    author = "Google Cloud Security"
    description = "Identify when the http delete method is being called within the Microsoft Graph API."
    rule_id = "mr_9e5f6adc-84f9-46f3-bf9e-abe38e14a77b"
    rule_name = "Hunt for the delete method in Microsoft Graph API calls"
    assumption = "Tuning is needed to identify administrative activities as general maintenance that may be logged"
    type = "Hunt"
    data_source = "MS Graph Activity Logs"
    platform = "Azure"
    severity = "Low"
    priority = "Low"

  events:
    $api.metadata.event_type = "NETWORK_HTTP"
    $api.metadata.product_event_type = "Microsoft Graph Activity"
    $api.network.http.method = "DELETE"
    //Can be tuned for specific APIs being used in delete operations if desired
    //$api.target.url = /https:\/\/graph.microsoft.com\/v1.0\/groups\/.*\/members/ nocase
    //Can be tuned for specific User Agent strings being used
    //$api.network.http.user_agent = /PowerShell/ nocase
    //Can be tuned to eliminate Azure IP ranges or other IP addresses
    NOT net.ip_in_range_cidr($api.principal.ip, "20.151.0.0/16")
    $api.principal.ip = $ip
    $api.network.session_id = $session

  match:
    $ip, $session over 5m

  outcome:
    $risk_score = 15
    $event_count = count($api.metadata.id)
    $requesting_user_guid = array_distinct($api.principal.user.userid)
    $requesting_ip = array_distinct($api.principal.ip)
    $user_agent = array_distinct($api.network.http.user_agent)
    $location = array_distinct($api.principal.location.name)
    $target_application_id_guid = array_distinct($api.target.resource.product_object_id)
    $session_id = array_distinct($api.network.session_id)
    $target_url = array_distinct($api.target.url)

  condition:
    $api
}

YARA-L Rule Structure

Condition

Fires when at least one $api event in the 5m window.

Events

$api NETWORK_HTTP

  • metadata.product_event_type = "Microsoft Graph Activity"
  • network.http.method = "DELETE"
  • principal.ip cidr_match "20.151.0.0/16"

Match and Correlation

Match key
$ip (principal.ip), $session (network.session_id)
Within
5m

Outcome

Outcome variables add context to a detection. When the rule generates an alert, $risk_score is displayed with it.

FieldExpression
risk_score15
event_countcount($api.metadata.id)
requesting_user_guidarray_distinct($api.principal.user.userid)
requesting_iparray_distinct($api.principal.ip)
user_agentarray_distinct($api.network.http.user_agent)
locationarray_distinct($api.principal.location.name)
target_application_id_guidarray_distinct($api.target.resource.product_object_id)
session_idarray_distinct($api.network.session_id)
target_urlarray_distinct($api.target.url)

O365 Entra ID App Client Secret Added, Updated or Deleted

#
Severity
medium
Type
alert
Time window
5m
Match by
userid
Author
Google Cloud Security
Source
github.com/chronicle/detection-rules

Secrets added to applications have legitimate purposes, but can also be a method of persistence. This alert will trigger on creation, modification or delete of a client secret

MITRE ATT&CK Coverage

Telemetry Coverage

Rules Detecting the Same Action

These rules filter on the same operation.

Rule Body

// Copyright 2025 Google LLC. Licensed under Apache-2.0.

rule o365_entra_id_client_secret_add_update_delete_in_app {

  meta:
    author = "Google Cloud Security"
    description = "Secrets added to applications have legitimate purposes, but can also be a method of persistence. This alert will trigger on creation, modification or delete of a client secret"
    rule_id = "mr_24ac7907-9d86-4089-901c-61f8ff1e7730"
    rule_name = "O365 Entra ID App Client Secret Added, Updated or Deleted"
    tactic = "TA0003"
    technique = "T1098.001"
    type = "alert"
    platform = "azure"
    data_source = "o365"
    severity = "Medium"
    priority = "Medium"

  events:
    $app.metadata.event_type = "USER_RESOURCE_UPDATE_CONTENT"
    $app.metadata.product_name = "Office 365"
    $app.metadata.product_event_type = /Update application.*Certificates and secrets management/
    $app.metadata.vendor_name = "Microsoft"
    $app.security_result.action = "ALLOW"
    $app.principal.user.userid = $userid

  match:
    $userid over 5m

  outcome:
    $risk_score = 65
    $event_count = count_distinct($app.metadata.id)
    $security_summary = array_distinct($app.security_result.summary)
    $user_agent = array_distinct($app.network.http.user_agent)
    $target_entra_id_application = array_distinct(re.capture($app.network.http.user_agent,`\"AppId\":\"(.*)`))
    //added to populate alert graph with additional context
    $principal_user_userid = array_distinct($app.principal.user.userid)

  condition:
    $app
}

YARA-L Rule Structure

Condition

Fires when at least one $app event in the 5m window.

Events

$app USER_RESOURCE_UPDATE_CONTENT

  • metadata.product_event_type matches "Update application.*Certificates and secrets management"
  • security_result.action = "ALLOW"

Match and Correlation

Match key
$userid (principal.user.userid)
Within
5m

Outcome

Outcome variables add context to a detection. When the rule generates an alert, $risk_score is displayed with it.

FieldExpression
risk_score65
event_countcount_distinct($app.metadata.id)
security_summaryarray_distinct($app.security_result.summary)
user_agentarray_distinct($app.network.http.user_agent)
target_entra_id_applicationarray_distinct(re.capture($app.network.http.user_agent,`\"AppId\":\"(.*)`))
principal_user_useridarray_distinct($app.principal.user.userid)

Okta ThreatInsight Targeted Bruteforce Attack

#
Severity
medium
Type
Alert
Time window
1h
Match by
userid
Author
Google Cloud Security
Source
github.com/chronicle/detection-rules

Okta ThreatInsight detects access requests from known malicious IPs targeting a specific org.

MITRE ATT&CK Coverage

TacticTechniques
Credential Access

References

Telemetry Coverage

Rules Detecting the Same Action

These rules filter on the same operation.

Rule Body

// Copyright 2023 Google LLC. Licensed under Apache-2.0.

rule okta_threatinsight_targeted_brute_force_attack {

  meta:
    author = "Google Cloud Security"
    description = "Okta ThreatInsight detects access requests from known malicious IPs targeting a specific org."
    rule_id = "mr_ce576f12-ee6d-4282-9f7b-f955af183eb7"
    rule_name = "Okta ThreatInsight Targeted Bruteforce Attack"
    reference = "https://help.okta.com/en-us/Content/Topics/Security/threat-insight/configure-threatinsight-system-log.htm"
    mitre_attack_tactic = "Credential Access"
    mitre_attack_technique = "Brute Force"
    mitre_attack_url = "https://attack.mitre.org/techniques/T1110/"
    mitre_attack_version = "v13.1"
    type = "Alert"
    data_source = "Okta"
    severity = "Medium"
    priority = "Medium"

  events:
    $bruteforce.metadata.product_name = "Okta"
    $bruteforce.metadata.vendor_name = "Okta"
    $bruteforce.metadata.event_type = "USER_UNCATEGORIZED"
    $bruteforce.metadata.product_event_type = "security.attack.start"
    $bruteforce.principal.user.userid = $userid

  match:
    $userid over 1h

  outcome:
    $risk_score = max(35)
    $mitre_attack_tactic = "Credential Access"
    $mitre_attack_technique = "Brute Force"
    $principal_user_userid = array_distinct($bruteforce.principal.user.userid)
    $principal_user_email_addresses = array_distinct($bruteforce.principal.user.email_addresses)
    $security_result_summary = array_distinct($bruteforce.security_result.summary)
    $security_result_severity = array_distinct($bruteforce.security_result.severity)

  condition:
    $bruteforce
}

YARA-L Rule Structure

Condition

Fires when at least one $bruteforce event in the 1h window.

Events

$bruteforce USER_UNCATEGORIZED

  • metadata.product_event_type = "security.attack.start"

Match and Correlation

Match key
$userid (principal.user.userid)
Within
1h

Outcome

Outcome variables add context to a detection. When the rule generates an alert, $risk_score is displayed with it.

FieldExpression
risk_scoremax(35)
principal_user_useridarray_distinct($bruteforce.principal.user.userid)
principal_user_email_addressesarray_distinct($bruteforce.principal.user.email_addresses)
security_result_summaryarray_distinct($bruteforce.security_result.summary)
security_result_severityarray_distinct($bruteforce.security_result.severity)

Back to all YARA-L rules