Detection rules › YARA-L

YARA-L rules: 36

AWS EC2 User Data Modified

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

Detect modifications to user data script on an EC2 instance.

MITRE ATT&CK Coverage

TacticTechniques
Privilege Escalation

Telemetry Coverage

Rule Body

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

rule aws_ec2_user_data_modified {

  meta:
    author = "Google Cloud Security"
    description = "Detect modifications to user data script on an EC2 instance."
    rule_id = "mr_3167a29e-abbb-4d72-9f33-93df151d0224"
    rule_name = "AWS EC2 User Data Modified"
    mitre_attack_tactic = "Privilege Escalation"
    mitre_attack_technique = "Boot or Logon Initialization Scripts"
    mitre_attack_url = "https://attack.mitre.org/techniques/T1037/"
    mitre_attack_version = "v13.1"
    type = "Alert"
    data_source = "AWS CloudTrail"
    platform = "AWS"
    severity = "High"
    priority = "High"

  events:
    $cloudtrail.metadata.vendor_name = "AMAZON"
    $cloudtrail.metadata.product_name = "AWS CloudTrail"
    $cloudtrail.metadata.product_event_type = "ModifyInstanceAttribute"
    $cloudtrail.target.resource.attribute.labels["Request Parameters User Data"] != ""
    $cloudtrail.security_result.action = "ALLOW"
    $cloudtrail.target.resource_ancestors.product_object_id = $instanceId

  match:
    $instanceId over 1h

  outcome:
    $risk_score = max(75)
    $mitre_attack_tactic = "Privilege Escalation"
    $mitre_attack_technique = "Boot or Logon Initialization Scripts"
    $mitre_attack_technique_id = "T1037"
    $event_count = count_distinct($cloudtrail.metadata.id)
    $network_http_user_agent = array_distinct($cloudtrail.network.http.user_agent)
    $principal_ip = array_distinct($cloudtrail.principal.ip)
    $principal_ip_country = array_distinct($cloudtrail.principal.ip_geo_artifact.location.country_or_region)
    $principal_ip_state = array_distinct($cloudtrail.principal.ip_geo_artifact.location.state)
    $principal_user_display_name = array_distinct($cloudtrail.principal.user.user_display_name)
    $recipient_aws_account_id = array_distinct($cloudtrail.additional.fields["recipientAccountId"])
    $aws_region = array_distinct($cloudtrail.principal.location.name)
    $target_resource_name = array_distinct($cloudtrail.target.resource.name)
    $target_resource_product_object_id = array_distinct($cloudtrail.target.resource.product_object_id)

  condition:
    $cloudtrail
}

YARA-L Rule Structure

Condition

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

Events

$cloudtrail

  • metadata.product_event_type = "ModifyInstanceAttribute"
  • target.resource.attribute.labels["Request Parameters User Data"] is not null
  • security_result.action = "ALLOW"

Match and Correlation

Match key
$instanceId (target.resource_ancestors.product_object_id)
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(75)
event_countcount_distinct($cloudtrail.metadata.id)
network_http_user_agentarray_distinct($cloudtrail.network.http.user_agent)
principal_iparray_distinct($cloudtrail.principal.ip)
principal_ip_countryarray_distinct($cloudtrail.principal.ip_geo_artifact.location.country_or_region)
principal_ip_statearray_distinct($cloudtrail.principal.ip_geo_artifact.location.state)
principal_user_display_namearray_distinct($cloudtrail.principal.user.user_display_name)
recipient_aws_account_idarray_distinct($cloudtrail.additional.fields["recipientAccountId"])
aws_regionarray_distinct($cloudtrail.principal.location.name)
target_resource_namearray_distinct($cloudtrail.target.resource.name)
target_resource_product_object_idarray_distinct($cloudtrail.target.resource.product_object_id)

GitHub Access Granted To Personal Access Token Followed By High Number Of Cloned Non Public Repositories

#
Severity
high
Type
alert
Time window
30m
Match by
user_id
Author
Google Cloud Security
Source
github.com/chronicle/detection-rules

Detects when a user grants access to a GitHub Personal Access Token prior to cloning several GitHub non-public GitHub repositories. An adversary may grant access to a Personal Access Token before attempting to steal the contents of several GitHub repositories using a an automated script or offensive tool.

MITRE ATT&CK Coverage

References

Telemetry Coverage

Rules Detecting the Same Action

These rules filter on the same operation.

Rule Body

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

rule github_access_granted_to_personal_access_token_followed_by_high_number_of_cloned_non_public_repositories {

  meta:
    author = "Google Cloud Security"
    description = "Detects when a user grants access to a GitHub Personal Access Token prior to cloning several GitHub non-public GitHub repositories. An adversary may grant access to a Personal Access Token before attempting to steal the contents of several GitHub repositories using a an automated script or offensive tool."
    rule_id = "mr_11aaa6f7-7fcc-42cb-af2e-42ed39226c43"
    rule_name = "GitHub Access Granted To Personal Access Token Followed By High Number Of Cloned Non Public Repositories"
    assumption = "Your GitHub enterprise audit log settings are configured to log the source IP address for events. Reference: https://docs.github.com/en/organizations/keeping-your-organization-secure/managing-security-settings-for-your-organization/displaying-ip-addresses-in-the-audit-log-for-your-organization"
    type = "alert"
    severity = "High"
    priority = "High"
    platform = "GitHub"
    data_source = "github"
    mitre_attack_tactic = "Collection"
    mitre_attack_technique = "Data from Information Repositories: Code Repositories"
    mitre_attack_url = "https://attack.mitre.org/versions/v14/techniques/T1213/003/"
    mitre_attack_version = "v14"
    reference = "https://docs.github.com/en/enterprise-cloud@latest/admin/monitoring-activity-in-your-enterprise/reviewing-audit-logs-for-your-enterprise/audit-log-events-for-your-enterprise"

  events:
    // GitHub Personal Access Token (PAT) access granted event
    $github_pat.metadata.vendor_name = "GITHUB" nocase
    $github_pat.metadata.product_name = "GITHUB"
    $github_pat.metadata.product_event_type = "personal_access_token.access_granted"

    // GitHub repository clone event
    $github_pat.metadata.vendor_name = "GITHUB" nocase
    $github_clone.metadata.product_name = "GITHUB"
    $github_clone.metadata.product_event_type = "git.clone"
    $github_clone.target.resource.name = $github_repo_name

    // Join GitHub PAT access granted event to GitHub repository clone event
    $github_pat.principal.user.userid = $github_clone.principal.user.userid

    // Placeholder for match section
    $github_pat.principal.user.userid = $user_id

    // Ensure PAT access granted event occurred before repository clone events
    $github_pat.metadata.event_timestamp.seconds < $github_clone.metadata.event_timestamp.seconds

  match:
    $user_id over 30m

  outcome:
    $github_repo_name_distinct_count = count_distinct($github_repo_name)
    $risk_score = max(85)
    $mitre_attack_tactic = "Collection"
    $mitre_attack_technique = "Data from Information Repositories: Code Repositories"
    $mitre_attack_technique_id = "T1213.003"
    $event_count = count_distinct($github_clone.metadata.id)
    $principal_ip = array_distinct($github_pat.principal.ip)
    $principal_user_userid = array_distinct($github_pat.principal.user.userid)
    $principal_ip_country = array_distinct($github_pat.principal.ip_geo_artifact.location.country_or_region)
    $principal_ip_state = array_distinct($github_pat.principal.ip_geo_artifact.location.state)
    $principal_ip_city = array_distinct($github_pat.principal.location.city)
    $security_result_summary = array_distinct($github_pat.security_result.summary)

  condition:
    // Customize GitHub repo count to fit your environment
    $github_pat and $github_clone and $github_repo_name_distinct_count > 5
}

YARA-L Rule Structure

Condition

Fires when at least one $github_pat event in the 30m window and at least one $github_clone event in the 30m window and $github_repo_name_distinct_count > 5.

Events

$github_pat

  • metadata.product_event_type = "personal_access_token.access_granted"
  • principal.user.userid cross_field_compare "github_clone.principal.user.userid"

$github_clone

  • metadata.product_event_type = "git.clone"

Match and Correlation

Order
$github_pat before $github_clone
Match key
$user_id (principal.user.userid)
Within
30m

Outcome

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

FieldExpression
github_repo_name_distinct_countcount_distinct($github_repo_name)
risk_scoremax(85)
event_countcount_distinct($github_clone.metadata.id)
principal_iparray_distinct($github_pat.principal.ip)
principal_user_useridarray_distinct($github_pat.principal.user.userid)
principal_ip_countryarray_distinct($github_pat.principal.ip_geo_artifact.location.country_or_region)
principal_ip_statearray_distinct($github_pat.principal.ip_geo_artifact.location.state)
principal_ip_cityarray_distinct($github_pat.principal.location.city)
security_result_summaryarray_distinct($github_pat.security_result.summary)

Hunt for Non-Anonymous Office 365 file downloads

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

Detects file downloads using O365 or Graph Activity logs, not including anonymous file links

MITRE ATT&CK Coverage

Telemetry Coverage

PlatformRecord / event type
Microsoft 365FileDownloaded

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_file_download {

  meta:
    author = "Google Cloud Security"
    description = "Detects file downloads using O365 or Graph Activity logs, not including anonymous file links"
    rule_id = "mr_0dfb4338-4b4c-4af1-82da-fd5221d611a0"
    rule_name = "Hunt for Non-Anonymous Office 365 file downloads"
    assumption = "Because file downloads occur all the time, additional criteria to narrow this rule is expected. Areas to filter include user agent, specific users, IPs, applications and folders or items in the directory structure."
    tactic = "TA0010"
    technique = "T1048.002"
    type = "hunt"
    platform = "azure"
    data_source = "o365, ms graph activity logs"
    severity = "Low"
    priority = "Low"

  events:
    (
        $file.metadata.event_type = "USER_RESOURCE_UPDATE_CONTENT" and
        $file.metadata.product_event_type = "FileDownloaded" and
        $file.metadata.product_name = "Office 365" and
        $file.metadata.vendor_name = "Microsoft" and
        //This could be modified to specify downloading only thorugh specific applications
        //$file.target.application = "OneDrive" and
        //Add folder or docs of interest to monitor for downloads like this - focus in example is pdf in R&D folder - could also use a list
        //re.regex($file.src.url, `^https://.*sharepoint.com/sites/.*/R&D/.*\.pdf$`) nocase and
        NOT (
            $file.principal.user.userid = /^urn:spo:anon#/ or
            $file.principal.user.userid = "anonymous"
        )
    )
    or
    (
        $file.metadata.event_type = "NETWORK_HTTP" and
        $file.metadata.product_event_type = "Microsoft Graph Activity" and
        $file.network.http.method = "GET" and
        $file.network.http.response_code = 302 //and
        //Could modify this to focus on a specific UA string or a UA strings not commonly used in environment
        //$file.network.http.user_agent = /PowerShell/ nocase
        //Could tighten to specify drives or items using an example like this
        //re.regex($file.target.url, `^https://graph.microsoft.com/.*/drives/.*/content$`) nocase
    )
    $file.principal.ip = $ip

  match:
    $ip over 5m

  outcome:
    $risk_score = 35
    $event_count = count_distinct($file.metadata.id)
    $referral_url = array_distinct($file.network.http.referral_url)
    $user_agent = array_distinct($file.network.http.user_agent)
    $principal_application = array_distinct($file.principal.application)
    $principal_ip = array_distinct($file.principal.ip)
    $target_application = array_distinct($file.target.application)
    //$principal_user_email_address = array_distinct(principal.user.email_addresses)
    $principal_user_userid = array_distinct($file.principal.user.userid)
    $src_file_full_path = array_distinct($file.src.file.full_path)
    $src_url = array_distinct($file.src.url)
    $session = array_distinct($file.network.session_id)
    $location = array_distinct($file.principal.location.name)
    $target_resource_guid = array_distinct($file.target.resource.product_object_id)
    $target_url = array_distinct($file.target.url)

  condition:
    $file
}

YARA-L Rule Structure

Condition

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

Events

$file USER_RESOURCE_UPDATE_CONTENT

  • metadata.product_event_type = "FileDownloaded"
  • principal.user.userid matches "^urn:spo:anon#"
  • principal.user.userid = "anonymous"
  • metadata.product_event_type = "Microsoft Graph Activity"
  • network.http.method = "GET"
  • network.http.response_code = "302"

Match and Correlation

Match key
$ip (principal.ip)
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($file.metadata.id)
referral_urlarray_distinct($file.network.http.referral_url)
user_agentarray_distinct($file.network.http.user_agent)
principal_applicationarray_distinct($file.principal.application)
principal_iparray_distinct($file.principal.ip)
target_applicationarray_distinct($file.target.application)
principal_user_useridarray_distinct($file.principal.user.userid)
src_file_full_patharray_distinct($file.src.file.full_path)
src_urlarray_distinct($file.src.url)
sessionarray_distinct($file.network.session_id)
locationarray_distinct($file.principal.location.name)
target_resource_guidarray_distinct($file.target.resource.product_object_id)
target_urlarray_distinct($file.target.url)

RDP Sensitive Settings Changed to Zero

#
Severity
medium
Type
Detection
Time window
5m
Match by
hostname
Author
Samir Bousseaden, David ANDRE, Roberto Rodriguez @Cyb3rWard0g, Nasreddine Bencherchali
Source
github.com/chronicle/detection-rules

Detects tampering of RDP Terminal Service/Server sensitive settings. Such as allowing unauthorized users access to a system via the 'fAllowUnsolicited' or enabling RDP via 'fDenyTSConnections', etc.

Known False Positives

  • Some of the keys mentioned here could be modified by an administrator while setting group policy

MITRE ATT&CK Coverage

TacticTechniques
Persistence
Defense Impairment

References

Telemetry Coverage

Rule Body

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

rule rdp_sensitive_settings_changed_to_zero {

  meta:
    author = "Samir Bousseaden, David ANDRE, Roberto Rodriguez @Cyb3rWard0g, Nasreddine Bencherchali"
    description = "Detects tampering of RDP Terminal Service/Server sensitive settings. Such as allowing unauthorized users access to a system via the 'fAllowUnsolicited' or enabling RDP via 'fDenyTSConnections', etc."
    reference = "https://github.com/SigmaHQ/sigma/blob/master/rules/windows/registry/registry_set/registry_set_terminal_server_suspicious.yml"
    license = "https://github.com/SigmaHQ/Detection-Rule-License/blob/main/LICENSE.Detection.Rules.md"
    rule_name = "RDP Sensitive Settings Changed to Zero"
    rule_id = "mr_553a08a3-f1b6-4962-9393-151b0fecdf55"
    sigma_uuid = "a2863fbc-d5cb-48d5-83fb-d976d4b1743b"
    sigma_status = "test"
    tactic = "TA0005"
    //tactic = "TA0003"
    technique = "T1112"
    type = "Detection"
    data_source = "Sysmon"
    platform = "Windows"
    severity = "Medium"
    priority = "Medium"
    false_positives = "Some of the keys mentioned here could be modified by an administrator while setting group policy"

  events:
    $reg.metadata.event_type = "REGISTRY_MODIFICATION"
    (
        re.regex($reg.target.registry.registry_key, `\\fDenyTSConnections$`) nocase or
        re.regex($reg.target.registry.registry_key, `\\fSingleSessionPerUser$`) nocase or
        re.regex($reg.target.registry.registry_key, `\\UserAuthentication$`) nocase
    )
    $reg.target.registry.registry_value_data = "DWORD (0x00000000)" nocase

    $reg.principal.hostname = $hostname

  match:
    $hostname over 5m

  outcome:
    //example usage of specifying test user and hostname to adjust risk score
    $risk_score = max(if($reg.principal.user.userid = "user" and $reg.principal.hostname = "hostname", 0, 15))
    $principal_hostname = array_distinct($reg.principal.hostname)
    $principal_process_pid = array_distinct($reg.principal.process.pid)
    $principal_process_file_full_path = array_distinct($reg.principal.process.file.full_path)
    $principal_process_product_specific_process_id = array_distinct($reg.principal.process.product_specific_process_id)
    $principal_user_userid = array_distinct($reg.principal.user.userid)
    $target_registry_key = array_distinct($reg.target.registry.registry_key)
    $target_registry_value_data = array_distinct($reg.target.registry.registry_value_data)
    $log_type = array_distinct(strings.concat($reg.metadata.log_type,"/",$reg.metadata.product_event_type))

  condition:
    $reg
}

YARA-L Rule Structure

Condition

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

Events

$reg REGISTRY_MODIFICATION (13, 4657)

  • target.registry.registry_key matches "\\fDenyTSConnections$"
  • target.registry.registry_key matches "\\fSingleSessionPerUser$"
  • target.registry.registry_key matches "\\UserAuthentication$"
  • target.registry.registry_value_data = "DWORD (0x00000000)"

Match and Correlation

Match key
$hostname (principal.hostname)
Within
5m

Outcome

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

FieldExpression
risk_scoremax(if($reg.principal.user.userid = "user" and $reg.principal.hostname = "hostname", 0, 15))
principal_hostnamearray_distinct($reg.principal.hostname)
principal_process_pidarray_distinct($reg.principal.process.pid)
principal_process_file_full_patharray_distinct($reg.principal.process.file.full_path)
principal_process_product_specific_process_idarray_distinct($reg.principal.process.product_specific_process_id)
principal_user_useridarray_distinct($reg.principal.user.userid)
target_registry_keyarray_distinct($reg.target.registry.registry_key)
target_registry_value_dataarray_distinct($reg.target.registry.registry_value_data)
log_typearray_distinct(strings.concat($reg.metadata.log_type,"/",$reg.metadata.product_event_type))

Recon Environment Enumeration System CISA Report

#
Severity
low
Type
hunt
Time window
15m
Match by
hostname
Author
Google Cloud Security
Source
github.com/chronicle/detection-rules

Detects system enumeration events as identified in CISA Living off the Land pdf. Alone they may be normal but in concert, they may be worth looking into

MITRE ATT&CK Coverage

TacticTechniques
Discovery

References

Telemetry Coverage

Rule Body

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

rule recon_environment_enumeration_system_cisa_report {

  meta:
    author = "Google Cloud Security"
    description = "Detects system enumeration events as identified in CISA Living off the Land pdf. Alone they may be normal but in concert, they may be worth looking into"
    rule_id = "mr_086dede6-33ba-42df-b001-5595ceb0d589"
    rule_name = "Recon Environment Enumeration System CISA Report"
    type = "hunt"
    platform = "Windows"
    data_source = "microsoft sysmon, windows event logs"
    tactic = "TA0007"
    technique = "T1082"
    reference = "https://media.defense.gov/2023/May/24/2003229517/-1/-1/0/CSA_Living_off_the_Land.PDF"
    severity = "Low"
    priority = "Low"

  events:
    $process.metadata.event_type = "PROCESS_LAUNCH"
    $process.principal.hostname = $hostname
    $process.target.process.command_line = $command_line

    re.regex($process.target.process.command_line, `wevtutil.*qe.*security.*\/rd:true.*\/f:text.*\/q:.*\[System\[\(EventID`) nocase
    // below is the more specific command down to the event id, could comment out the about and use this instead if desired
    //re.regex($process.target.process.command_line, `wevtutil.*qe.*security.*\/rd:true.*\/f:text.*\/q:\*\[System\[\(EventID=4624\).*TimeCreated\[@SystemTime.*\]\].*EventData\[Data.*\]\]`) nocase

    or

    // cisa report referenced cmd /c in their report throughout, can filter this in/out for tuning as desired
    // other wmic switches like /user and /password, these have been excluded to focus on the commands being issued since local access does not require these
    (
        re.regex($process.target.process.command_line, `(|cmd.*/c).*ldifde.exe.*-f.*-p.*subtree`) nocase or
        re.regex($process.target.process.command_line, `(|cmd.*/c).*reg.*query.*hklm\\software\\`) nocase or
        re.regex($process.target.process.command_line, `(|cmd.*/c).*systeminfo`) nocase or
        re.regex($process.target.process.command_line, `(|cmd.*/c).*tasklist.*\/v`) nocase or
        re.regex($process.target.process.command_line, `(|cmd.*/c).*whoami`) nocase or
        re.regex($process.target.process.command_line, `(|cmd.*/c).*wmic.*volume.*list.*brief`) nocase or
        // cisa report called out wmic volume list brief, below is alternate that removed brief to widen criteria
        //re.regex($process.target.process.command_line, `(|cmd.*/c).*wmic.*volume.*list`) nocase or
        re.regex($process.target.process.command_line, `(|cmd.*/c).*wmic.*service.*brief`) nocase or
        re.regex($process.target.process.command_line, `(|cmd.*/c).*wmic.*product.*list.*brief`) nocase or
        re.regex($process.target.process.command_line, `(|cmd.*/c).*wmic.*baseboard.*list.*full`) nocase or
        re.regex($process.target.process.command_line, `(|cmd.*/c).*wmic.*path.*win32_logicaldisk.*get.*(caption|filesystem|freespace|size|volumename)`) nocase
    )

  match:
    $hostname over 15m

  outcome:
    $risk_score = 35
    $event_count = count_distinct($process.metadata.id)
    $unique_command_line_threshold = max(5)
    // added to populate alert graph with additional context
    // Commented out principal.hostname because it is already represented in graph as match variable. If match changes, can uncomment to add to results
    //$principal_hostname = array_distinct($process.principal.hostname)
    $principal_process_pid = array_distinct($process.principal.process.pid)
    $principal_process_command_line = array_distinct($process.principal.process.command_line)
    $principal_process_file_sha256 = array_distinct($process.principal.process.file.sha256)
    $principal_process_file_full_path = array_distinct($process.principal.process.file.full_path)
    $principal_process_product_specific_process_id = array_distinct($process.principal.process.product_specific_process_id)
    $principal_process_parent_process_product_specific_process_id = array_distinct($process.principal.process.parent_process.product_specific_process_id)
    $target_process_pid = array_distinct($process.target.process.pid)
    $target_process_command_line = array_distinct($process.target.process.command_line)
    $target_process_file_sha256 = array_distinct($process.target.process.file.sha256)
    $target_process_file_full_path = array_distinct($process.target.process.file.full_path)
    $target_process_product_specific_process_id = array_distinct($process.target.process.product_specific_process_id)
    $principal_user_userid = array_distinct($process.principal.user.userid)

  condition:
    // modify the condition value for command line to throttle how many of these commands can be issued until the rule is triggered
    $process and #command_line > 5
}

YARA-L Rule Structure

Condition

Fires when at least one $process event in the 15m window and $command_line occurs more than 5 times in the 15m window.

Events

$process PROCESS_LAUNCH (1, 4688)

  • target.process.command_line matches "wevtutil.*qe.*security.*\/rd:true.*\/f:text.*\/q:.*\[System\[\(EventID"
  • target.process.command_line matches "(|cmd.*/c).*ldifde.exe.*-f.*-p.*subtree"
  • target.process.command_line matches "(|cmd.*/c).*reg.*query.*hklm\\software\\"
  • target.process.command_line matches "(|cmd.*/c).*systeminfo"
  • target.process.command_line matches "(|cmd.*/c).*tasklist.*\/v"
  • target.process.command_line matches "(|cmd.*/c).*whoami"
  • target.process.command_line matches "(|cmd.*/c).*wmic.*volume.*list.*brief"
  • target.process.command_line matches "(|cmd.*/c).*wmic.*service.*brief"
  • target.process.command_line matches "(|cmd.*/c).*wmic.*product.*list.*brief"
  • target.process.command_line matches "(|cmd.*/c).*wmic.*baseboard.*list.*full"
  • target.process.command_line matches "(|cmd.*/c).*wmic.*path.*win32_logicaldisk.*get.*(caption|filesystem|freespace|size|volumename)"

Match and Correlation

Match key
$hostname (principal.hostname)
Within
15m

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($process.metadata.id)
unique_command_line_thresholdmax(5)
principal_process_pidarray_distinct($process.principal.process.pid)
principal_process_command_linearray_distinct($process.principal.process.command_line)
principal_process_file_sha256array_distinct($process.principal.process.file.sha256)
principal_process_file_full_patharray_distinct($process.principal.process.file.full_path)
principal_process_product_specific_process_idarray_distinct($process.principal.process.product_specific_process_id)
principal_process_parent_process_product_specific_process_idarray_distinct($process.principal.process.parent_process.product_specific_process_id)
target_process_pidarray_distinct($process.target.process.pid)
target_process_command_linearray_distinct($process.target.process.command_line)
target_process_file_sha256array_distinct($process.target.process.file.sha256)
target_process_file_full_patharray_distinct($process.target.process.file.full_path)
target_process_product_specific_process_idarray_distinct($process.target.process.product_specific_process_id)
principal_user_useridarray_distinct($process.principal.user.userid)

sap critical role assigned to new user

#
Severity
critical
Time window
1h
Match by
target_user
Author
Google Cloud Security
Source
github.com/chronicle/detection-rules

Detects the assignment of high-privilege roles by correlating Change Documents (PFCG) with Security Audit logs (AUD) for IP attribution.

MITRE ATT&CK Coverage

TacticTechniques
Privilege Escalation

Rule Body

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

rule sap_critical_role_assigned_to_new_user {

  meta:
    author = "Google Cloud Security"
    description = "Detects the assignment of high-privilege roles by correlating Change Documents (PFCG) with Security Audit logs (AUD) for IP attribution."
    severity = "Critical"
    tactic = "TA0004"
    technique = "T1098"

  events:
    $change.metadata.log_type = "SAP_CHANGE_DOCUMENT"
    $change.target.resource.attribute.labels["TABNAME"] = "AGR_USERS"
    $change.target.resource.attribute.labels["CHNGIND"] = "I"

    $role = $change.target.resource.product_object_id

    $audit.metadata.log_type = "SAP_SECURITY_AUDIT"
    $audit.additional.fields["msg_1"] = "AU7"

    //join
    $target_user = re.capture($change.target.resource.attribute.labels["TABKEY"], "^.{33}\\s*(\\S+)\\s*\\d{16}$")
    $target_user = $audit.additional.fields["param1_1"]

    $role in %sap_sensitive_roles.role

  match:
    $target_user over 1h

  outcome:
    $user_that_created_account = array_distinct($audit.principal.user.userid)
    $user_that_assigned_role = array_distinct($change.principal.user.userid)
    $source_ip = array_distinct($audit.principal.ip)
    $assigned_role = array_distinct($role)
    $system_id = array_distinct($audit.target.application)
    $risk_score = 95

  condition:
    $change and $audit
}

YARA-L Rule Structure

Condition

Fires when at least one $change event in the 1h window and at least one $audit event in the 1h window.

Events

$audit

  • metadata.log_type = "SAP_SECURITY_AUDIT"
  • additional.fields["msg_1"] = "AU7"
  • additional.fields["param1_1"] macro "re.capture($change.target.resource.attribute.labels["TABKEY"], "^.{33}\\s*(\\S+)\\s*\\d{16}$")"

$change

  • metadata.log_type = "SAP_CHANGE_DOCUMENT"
  • target.resource.attribute.labels["TABNAME"] = "AGR_USERS"
  • target.resource.attribute.labels["CHNGIND"] = "I"
  • target.resource.product_object_id in "%sap_sensitive_roles.role"

Match and Correlation

Match key
$target_user
Within
1h

Outcome

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

FieldExpression
user_that_created_accountarray_distinct($audit.principal.user.userid)
user_that_assigned_rolearray_distinct($change.principal.user.userid)
source_iparray_distinct($audit.principal.ip)
assigned_rolearray_distinct($role)
system_idarray_distinct($audit.target.application)
risk_score95

Back to all YARA-L rules