Detection rules › YARA-L
Suspicious User Agent Strings associated withGraphRunner
GraphRunner contains a function that forges UA strings. The UA strings below are found in that function. Can be used for other UA strings if desired
References
Rule body yaral
/*
* Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
rule graphrunner_suspicious_user_agent_strings {
meta:
author = "Google Cloud Security"
description = "GraphRunner contains a function that forges UA strings. The UA strings below are found in that function. Can be used for other UA strings if desired"
rule_id = "mr_61809764-4da4-48dc-aa14-aa28c00be3fa"
rule_name = "Suspicious User Agent Strings associated withGraphRunner"
//Currently used by default in the following functions
//Get-GraphTokens, Invoke-RefreshGraphTokens, Invoke-RefreshToSharePointToken, Invoke-ImmersiveFileReader, Invoke-BruteClientIDAccess
assumption = "Function can be modified to change strings to more recent browser versions, upkeep and monitoring is required."
reference = "https://github.com/dafthack/GraphRunner/blob/main/GraphRunner.ps1"
type = "Hunt"
data_source = "Azure Activity, MS Graph Activity Logs"
platform = "Azure"
severity = "Low"
priority = "Low"
events:
//Focused on O365/Entra ID Logs - Could expand further for other use cases if desired
(
$web.metadata.product_name = "Azure Activity" OR
$web.metadata.product_name = "Office 365" OR
$web.metadata.product_name = "Azure AD" OR
$web.metadata.product_name = "Azure AD Directory Audit" OR
$web.metadata.product_event_type = "Microsoft Graph Activity"
)
//Displayed here as strings separated by OR statement
//Each line is commented with device or browser or combination as specified in GraphRunner
//Could also convert to regex to refine if desired or used with a reference list
(
$web.network.http.user_agent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36" nocase or // Mac/Chrome | Chrome
$web.network.http.user_agent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:70.0) Gecko/20100101 Firefox/70.0" nocase or // Mac/Firefox
$web.network.http.user_agent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/604.1 Edg/91.0.100.0" nocase or // Mac/Edge
$web.network.http.user_agent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Safari/605.1.15" nocase or // Mac/Safari | Mac | Safari
$web.network.http.user_agent = "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko" nocase or // Windows/IE | IE
$web.network.http.user_agent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36" nocase or // Windows/Chrome
$web.network.http.user_agent = "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:70.0) Gecko/20100101 Firefox/70.0" nocase or // Windows/Firefox | Firefox
$web.network.http.user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.19042" nocase or // Windows/Edge | Windows
$web.network.http.user_agent = "Mozilla/5.0 (Linux; U; Android 4.0.2; en-us; Galaxy Nexus Build/ICL53F) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30" nocase or // AndroidMobile/Android | AndroidMobile | Android
$web.network.http.user_agent = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Mobile Safari/537.36" nocase or // AndroidMobile/Chrome
$web.network.http.user_agent = "Mozilla/5.0 (Android 4.4; Mobile; rv:70.0) Gecko/70.0 Firefox/70.0" nocase or // AndroidMobile/Firefox
$web.network.http.user_agent = "Mozilla/5.0 (Linux; Android 8.1.0; Pixel Build/OPM4.171019.021.D1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36 EdgA/42.0.0.2057" nocase or // AndroidMobile/Edge
$web.network.http.user_agent = "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/91.0.4472.114 Mobile/15E148 Safari/604.1" nocase or // iPhone/Chrome
$web.network.http.user_agent = "Mozilla/5.0 (iPhone; CPU iPhone OS 8_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) FxiOS/1.0 Mobile/12F69 Safari/600.1.4" nocase or // iPhone/Firefox
$web.network.http.user_agent = "Mozilla/5.0 (iPhone; CPU iPhone OS 12_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1.1 EdgiOS/44.5.0.10 Mobile/15E148 Safari/604.1" nocase or // iPhone/Edge
$web.network.http.user_agent = "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1" nocase or // iPhone/Safari | iPhone
$web.network.http.user_agent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36" nocase // Edge
)
//assumes that every event would have either a principal.ip or principal.user.userid, could be modfied include other common value to aggregate detections
$identifier = strings.coalesce($web.principal.ip, $web.principal.user.userid)
match:
$identifier over 5m
outcome:
$risk_score = 35
$event_count = count_distinct($web.metadata.id)
$principal_email = array_distinct($web.principal.user.email_addresses)
$principal_ip = array_distinct($web.principal.ip)
$user_agent = array_distinct($web.network.http.user_agent)
$location = array_distinct(strings.concat("City: ", $web.principal.location.city, " State: ",
$web.principal.location.state, " Country: ", $web.principal.location.country_or_region))
$session_id = array_distinct(if($web.metadata.product_event_type = "Microsoft Graph Activity", $web.network.session_id, ""))
$login_detail = array_distinct(if($web.metadata.event_type = "USER_LOGIN", $web.security_result.category_details, ""))
$target_url = array_distinct(if($web.metadata.product_event_type = "Microsoft Graph Activity", $web.target.url, ""))
condition:
$web
}
Detection logic
Fires when at least one $web event in the 5m window.
Events
$web
metadata.product_event_type = "Microsoft Graph Activity"network.http.user_agent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36" or "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:70.0) Gecko/20100101 Firefox/70.0" or "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/604.1 Edg/91.0.100.0" or "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Safari/605.1.15" or "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko" or "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36" or "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:70.0) Gecko/20100101 Firefox/70.0" or "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.19042" or "Mozilla/5.0 (Linux; U; Android 4.0.2; en-us; Galaxy Nexus Build/ICL53F) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30" or "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Mobile Safari/537.36" or "Mozilla/5.0 (Android 4.4; Mobile; rv:70.0) Gecko/70.0 Firefox/70.0" or "Mozilla/5.0 (Linux; Android 8.1.0; Pixel Build/OPM4.171019.021.D1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36 EdgA/42.0.0.2057" or "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/91.0.4472.114 Mobile/15E148 Safari/604.1" or "Mozilla/5.0 (iPhone; CPU iPhone OS 8_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) FxiOS/1.0 Mobile/12F69 Safari/600.1.4" or "Mozilla/5.0 (iPhone; CPU iPhone OS 12_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1.1 EdgiOS/44.5.0.10 Mobile/15E148 Safari/604.1" or "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1" or "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36"
Correlation
Outcome
Fields the detection emits on a match. $risk_score drives alerting; Chronicle surfaces the rest on the detection.
| Field | Expression |
|---|---|
risk_score | 35 |
event_count | count_distinct($web.metadata.id) |
principal_email | array_distinct($web.principal.user.email_addresses) |
principal_ip | array_distinct($web.principal.ip) |
user_agent | array_distinct($web.network.http.user_agent) |
location | array_distinct(strings.concat("City: ", $web.principal.location.city, " State: ", $web.principal.location.state, " Country: ", $web.principal.location.country_or_region)) |
session_id | array_distinct(if($web.metadata.product_event_type = "Microsoft Graph Activity", $web.network.session_id, "")) |
login_detail | array_distinct(if($web.metadata.event_type = "USER_LOGIN", $web.security_result.category_details, "")) |
target_url | array_distinct(if($web.metadata.product_event_type = "Microsoft Graph Activity", $web.target.url, "")) |