Detection rules › YARA-L

Suspicious User Agent Strings associated withGraphRunner

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

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

Match key
$identifier
Within
5m

Outcome

Fields the detection emits on a match. $risk_score drives alerting; Chronicle surfaces the rest on the detection.

FieldExpression
risk_score35
event_countcount_distinct($web.metadata.id)
principal_emailarray_distinct($web.principal.user.email_addresses)
principal_iparray_distinct($web.principal.ip)
user_agentarray_distinct($web.network.http.user_agent)
locationarray_distinct(strings.concat("City: ", $web.principal.location.city, " State: ", $web.principal.location.state, " Country: ", $web.principal.location.country_or_region))
session_idarray_distinct(if($web.metadata.product_event_type = "Microsoft Graph Activity", $web.network.session_id, ""))
login_detailarray_distinct(if($web.metadata.event_type = "USER_LOGIN", $web.security_result.category_details, ""))
target_urlarray_distinct(if($web.metadata.product_event_type = "Microsoft Graph Activity", $web.target.url, ""))