Detection rules › YARA-L

YARA-L rules: 0a

AWS IAM Access Denied Discovery Events

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

Detects excessive AccessDenied events within an hour timeframe from an IAM User

MITRE ATT&CK Coverage

TacticTechniques
Discovery

Rule Body

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

rule aws_iam_access_denied_discovery_events {

  meta:
    author = "Google Cloud Security"
    description = "Detects excessive AccessDenied events within an hour timeframe from an IAM User"
    rule_id = "mr_a175b0d9-4488-46cc-880a-2408cb301f41"
    rule_name = "AWS IAM Access Denied Discovery Events"
    mitre_attack_tactic = "Discovery"
    mitre_attack_technique = "Cloud Infrastructure Discovery"
    mitre_attack_url = "https://attack.mitre.org/techniques/T1580/"
    mitre_attack_version = "v13.1"
    type = "Alert"
    data_source = "AWS CloudTrail"
    platform = "AWS"
    severity = "Low"
    priority = "Low"

  events:
    $cloudtrail.metadata.vendor_name = "AMAZON"
    $cloudtrail.metadata.product_name = "AWS CloudTrail"
    $cloudtrail.security_result.rule_id = "AccessDenied"
    $cloudtrail.security_result.action = "BLOCK"
    $cloudtrail.principal.user.userid = $user_id
    $cloudtrail.target.application = $target_application
    $cloudtrail.metadata.product_event_type = $product_event_type

  match:
    $user_id over 1h

  outcome:
    $risk_score = max(35)
    $mitre_attack_tactic = "Discovery"
    $mitre_attack_technique = "Cloud Infrastructure Discovery"
    $mitre_attack_technique_id = "T1580"
    $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)
    $security_result_description = array_distinct($cloudtrail.security_result.description)
    $target_applications = array_distinct($cloudtrail.target.application)
    $product_event_types = array_distinct($cloudtrail.metadata.product_event_type)

  condition:
    #cloudtrail > 5 and #target_application > 1 and #product_event_type > 1
}

YARA-L Rule Structure

Condition

Fires when $cloudtrail occurs more than 5 times in the 1h window and $target_application occurs more than 1 times in the 1h window and $product_event_type occurs more than 1 times in the 1h window.

Events

$cloudtrail

  • security_result.rule_id = "AccessDenied"
  • security_result.action = "BLOCK"

Match and Correlation

Match key
$user_id (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)
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)
security_result_descriptionarray_distinct($cloudtrail.security_result.description)
target_applicationsarray_distinct($cloudtrail.target.application)
product_event_typesarray_distinct($cloudtrail.metadata.product_event_type)

GitHub Enterprise Audit Log Stream Destroyed

#
Severity
high
Type
alert
Author
Google Cloud Security
Source
github.com/chronicle/detection-rules

Detects when a GitHub audit log stream is destroyed. An adversary may attempt to destroy audit logs to erase their tracks.

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

  meta:
    author = "Google Cloud Security"
    description = "Detects when a GitHub audit log stream is destroyed. An adversary may attempt to destroy audit logs to erase their tracks."
    rule_id = "mr_f86cc19d-4cbb-4ba5-97ef-1d648d53d06a"
    rule_name = "GitHub Enterprise Audit Log Stream Destroyed"
    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 = "Defense Evasion"
    mitre_attack_technique = "Impair Defenses: Disable or Modify Cloud Logs"
    mitre_attack_url = "https://attack.mitre.org/versions/v14/techniques/T1562/008/"
    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.metadata.vendor_name = "GITHUB" nocase
    $github.metadata.product_name = "GITHUB"
    $github.metadata.product_event_type = "audit_log_streaming.destroy"

  outcome:
    $risk_score = max(85)
    $mitre_attack_tactic = "Defense Evasion"
    $mitre_attack_technique = "Impair Defenses: Disable or Modify Cloud Logs"
    $mitre_attack_technique_id = "T1562.008"
    $principal_ip = array_distinct($github.principal.ip)
    $principal_user_userid = array_distinct($github.principal.user.userid)
    $principal_ip_country = array_distinct($github.principal.ip_geo_artifact.location.country_or_region)
    $principal_ip_state = array_distinct($github.principal.ip_geo_artifact.location.state)
    $principal_ip_city = array_distinct($github.principal.location.city)
    $security_result_summary = array_distinct($github.security_result.summary)

  condition:
    $github
}

YARA-L Rule Structure

Condition

Fires when at least one $github event.

Events

$github

  • metadata.product_event_type = "audit_log_streaming.destroy"

Outcome

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

FieldExpression
risk_scoremax(85)
principal_iparray_distinct($github.principal.ip)
principal_user_useridarray_distinct($github.principal.user.userid)
principal_ip_countryarray_distinct($github.principal.ip_geo_artifact.location.country_or_region)
principal_ip_statearray_distinct($github.principal.ip_geo_artifact.location.state)
principal_ip_cityarray_distinct($github.principal.location.city)
security_result_summaryarray_distinct($github.security_result.summary)

Low Prevalence Hash On Process Launch Low Prevalence Domain Accessed

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

Detects when a low prevalence hash is seen during a process launch event, and a low prevalence domain is accessed within 10m.

Telemetry Coverage

Rule Body

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

rule low_prevalence_hash_on_process_launch_low_prevalence_domain_accessed {

  meta:
    author = "Google Cloud Security"
    description = "Detects when a low prevalence hash is seen during a process launch event, and a low prevalence domain is accessed within 10m."
    rule_id = "mr_0624f9fb-8c73-4b8c-8651-b88ed736c862"
    rule_name = "Low Prevalence Hash On Process Launch Low Prevalence Domain Accessed"
    type = "alert"
    tags = "prevalence"
    data_source = "zscalar, microsoft sysmon"
    severity = "Low"
    priority = "Low"

  events:
    // Process Launch
    $process.metadata.event_type = "PROCESS_LAUNCH"
    $process.principal.ip = $ip
    $process.target.file.sha256 != ""
    $process.target.file.sha256 = $sha256

    // File Prevalence Criteria
    $fileprev.graph.metadata.entity_type = "FILE"
    $fileprev.graph.metadata.source_type = "DERIVED_CONTEXT"
    $fileprev.graph.entity.file.prevalence.day_count = 10
    $fileprev.graph.entity.file.prevalence.rolling_max > 0
    //Adjust rolling_max for a different threshold as needed
    $fileprev.graph.entity.file.prevalence.rolling_max <= 2
    //Join process event to file prevalence entity
    $fileprev.graph.entity.file.sha256 = $sha256

    // Network HTTP
    $http.metadata.event_type = "NETWORK_HTTP"
    $http.principal.ip = $ip
    $http.target.hostname = $hostname
    // Filter out URLs with RFC 1918 IP addresses
    not net.ip_in_range_cidr($http.target.ip, "127.0.0.1/32")
    not net.ip_in_range_cidr($http.target.ip, "10.0.0.0/8")
    not net.ip_in_range_cidr($http.target.ip, "172.16.0.0/12")
    not net.ip_in_range_cidr($http.target.ip, "192.168.0.0/16")
    // Only match valid FQDN, filter out background non-routable noise
    re.regex($http.target.hostname, `(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]`)

    // Domain Prevalence Criteria
    $domainprev.graph.metadata.entity_type = "DOMAIN_NAME"
    $domainprev.graph.metadata.source_type = "DERIVED_CONTEXT"
    $domainprev.graph.entity.domain.prevalence.day_count = 10
    $domainprev.graph.entity.domain.prevalence.rolling_max > 0
    // Adjust rolling_max for a different threshold as needed
    $domainprev.graph.entity.domain.prevalence.rolling_max < 2
    // Join network event to domain entity
    $domainprev.graph.entity.domain.name = $hostname

    // Apply timing element to force the process to occur before the http
    $process.metadata.event_timestamp.seconds <= $http.metadata.event_timestamp.seconds

  match:
    $ip over 10m

  outcome:
    $risk_score = max(
        // increment risk score based upon rolling_max prevalence
        if ( $domainprev.graph.entity.domain.prevalence.rolling_max >= 10, 10) +
        if ( $domainprev.graph.entity.domain.prevalence.rolling_max >= 2 and $domainprev.graph.entity.domain.prevalence.rolling_max <= 9 , 20) +
        if ( $domainprev.graph.entity.domain.prevalence.rolling_max = 1, 30)
    )
    // added to populate alert graph with additional context
    // Commented out principal.ip because it is already represented in graph as match variable. If match changes, can uncomment to add to results
    //$principal_ip = array_distinct($http.principal.ip)
    $target_ip = array_distinct($http.target.ip)
    $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)
    $target_url = array_distinct($http.target.url)

  condition:
    $process and $fileprev and $http and $domainprev
}

YARA-L Rule Structure

Condition

Fires when at least one $process event in the 10m window and $fileprev matches entity context and at least one $http event in the 10m window and $domainprev matches entity context.

Events

$domainprev entity context (DOMAIN_NAME)

  • graph.metadata.entity_type = "DOMAIN_NAME"
  • graph.metadata.source_type = "DERIVED_CONTEXT"
  • graph.entity.domain.prevalence.day_count = "10"
  • graph.entity.domain.prevalence.rolling_max > "0"
  • graph.entity.domain.prevalence.rolling_max < "2"

$fileprev entity context (FILE)

  • graph.metadata.entity_type = "FILE"
  • graph.metadata.source_type = "DERIVED_CONTEXT"
  • graph.entity.file.prevalence.day_count = "10"
  • graph.entity.file.prevalence.rolling_max > "0"
  • graph.entity.file.prevalence.rolling_max <= "2"

$process PROCESS_LAUNCH (1, 4688)

  • target.file.sha256 is not null

$http NETWORK_HTTP

  • target.ip cidr_match "127.0.0.1/32"
  • target.ip cidr_match "10.0.0.0/8"
  • target.ip cidr_match "172.16.0.0/12"
  • target.ip cidr_match "192.168.0.0/16"
  • target.hostname matches "(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]"

Match and Correlation

Order
$process before $http
Match key
$ip (principal.ip)
Within
10m

Outcome

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

FieldExpression
risk_scoremax( if ( $domainprev.graph.entity.domain.prevalence.rolling_max >= 10, 10) + if ( $domainprev.graph.entity.domain.prevalence.rolling_max >= 2 and $domainprev.graph.entity.domain.prevalence.rolling_max <= 9 , 20) + if ( $domainprev.graph.entity.domain.prevalence.rolling_max = 1, 30) )
target_iparray_distinct($http.target.ip)
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)
target_urlarray_distinct($http.target.url)

sap multi terminal logon

#
Severity
medium
Time window
15m
Match by
user
Author
Google Cloud Security
Source
github.com/chronicle/detection-rules

Identifies successful logons for the same User ID from multiple different terminal IDs or client hostnames in a short timeframe, indicating potential credential sharing or session theft.

MITRE ATT&CK Coverage

TacticTechniques
Initial Access
Persistence
Privilege Escalation
Stealth

Telemetry Coverage

Rule Body

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

rule sap_multi_terminal_logon {

  meta:
    author = "Google Cloud Security"
    description = "Identifies successful logons for the same User ID from multiple different terminal IDs or client hostnames in a short timeframe, indicating potential credential sharing or session theft."
    severity = "medium"
    tactic = "TA0006"
    technique = "T1078"

  events:
    $e.metadata.log_type = "SAP_SECURITY_AUDIT"
    (
        $e.metadata.event_type = "USER_LOGIN" or
        $e.additional.fields["msg_1"] = /^AU1$|^AU5$/
    )


    // Ensure we only check events that actually have a terminal/hostname recorded
    $e.principal.hostname != ""

    $terminal = $e.principal.hostname
    $user = $e.principal.user.userid

  match:
    // You can reduce this window to 15m or 30m if 1h is too broad for direct terminal switches
    $user over 15m

  outcome:
    $terminals = array_distinct($terminal)
    $count_of_terminals = count_distinct($terminal)
    // Give a high risk score if they switch terminals
    $risk_score = 60
    $sap_instance = array_distinct($e.target.resource.name)

  condition:
    // Trigger if the user is seen on 2 or more distinct terminals
    #terminal >= 2
}

YARA-L Rule Structure

Condition

Fires when $terminal occurs at least 2 times in the 15m window.

Events

$e USER_LOGIN (4624, 4625, 4648)

  • metadata.log_type = "SAP_SECURITY_AUDIT"
  • additional.fields["msg_1"] matches "^AU1$|^AU5$"
  • principal.hostname is not null

Match and Correlation

Match key
$user
Within
15m

Outcome

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

FieldExpression
terminalsarray_distinct($terminal)
count_of_terminalscount_distinct($terminal)
risk_score60
sap_instancearray_distinct($e.target.resource.name)

sap security audit log user created deleted or unlocked

#
Severity
medium
Time window
59m
Match by
sid, user
Author
Google Cloud Security
Source
github.com/chronicle/detection-rules

Detects when an SAP user is created, deleted, or unlocked

MITRE ATT&CK Coverage

TacticTechniques
Persistence

Rule Body

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

rule sap_security_audit_log_user_created_deleted_or_unlocked {

  meta:
    author = "Google Cloud Security"
    description = "Detects when an SAP user is created, deleted, or unlocked"
    severity = "Medium"
    tactic = "TA0003"
    technique = "T1136"

  events:
    $e.metadata.log_type = "SAP_SECURITY_AUDIT"

    $e.additional.fields["msg_1"] = /^AU7$|^AU8$|^AU9$|^AUA$/ nocase

    $user = $e.principal.user.userid
    $sid = $e.target.application

    //exclusions
    not $user in %sap_admin_users.user

  match:
    $user, $sid over 59m

  outcome:
    $risk_score = 75
    $target_sid = array_distinct($sid)
    $description = array_distinct($e.metadata.description)
    $terminal = array_distinct($e.principal.hostname)
    $message_ids = array_distinct($e.additional.fields["msg_1"])
    $target_user = array_distinct($e.additional.fields["param1_1"])
    $t_code = array_distinct($e.security_result.detection_fields["slgtc_1"])
    $TXSUBCLSID = array_distinct($e.security_result.summary)
    $system = array_distinct($e.target.application)
    $instance = array_distinct($e.target.resource.name)

  condition:
    $e
}

YARA-L Rule Structure

Condition

Fires when at least one $e event in the 59m window.

Events

$e

  • metadata.log_type = "SAP_SECURITY_AUDIT"
  • additional.fields["msg_1"] matches "^AU7$|^AU8$|^AU9$|^AUA$"
  • principal.user.userid in "%sap_admin_users.user"

Match and Correlation

Match key
$sid, $user
Within
59m

Outcome

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

FieldExpression
risk_score75
target_sidarray_distinct($sid)
descriptionarray_distinct($e.metadata.description)
terminalarray_distinct($e.principal.hostname)
message_idsarray_distinct($e.additional.fields["msg_1"])
target_userarray_distinct($e.additional.fields["param1_1"])
t_codearray_distinct($e.security_result.detection_fields["slgtc_1"])
TXSUBCLSIDarray_distinct($e.security_result.summary)
systemarray_distinct($e.target.application)
instancearray_distinct($e.target.resource.name)

Back to all YARA-L rules