Detection rules › YARA-L
YARA-L rules: 0c
| Rule | Severity |
|---|---|
| GitHub High Number Of Non Public GitHub Repositories Cloned | high |
| Hacktool - IronSharpPack Execution | |
| Okta User Account Lockout | medium |
| sap change documents sensitive profile assignment | critical |
GitHub High Number Of Non Public GitHub Repositories Cloned
#Detects when a user clones a high number of non-public GitHub repositories. An adversary may attempt to steal the contents of several GitHub repositories after compromising a user account.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Collection |
References
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| GitHub | Audit log action git.clone: Repository cloned |
Rules Detecting the Same Action
These rules filter on the same operation.
- GitHub Access Granted To Personal Access Token Followed By High Number Of Cloned Non Public Repositories (YARA-L)
- Github Activity on a Private Repository from an Unusual IP (Elastic)
- GitHub Exfiltration via High Number of Repository Clones by User (Elastic)
- GitHub User Initial Access to Private Repo (Panther)
- High Number of Cloned GitHub Repos From PAT (Elastic)
Rule Body
// Copyright 2024 Google LLC. Licensed under Apache-2.0.
rule github_high_number_of_non_public_github_repositories_cloned {
meta:
author = "Google Cloud Security"
description = "Detects when a user clones a high number of non-public GitHub repositories. An adversary may attempt to steal the contents of several GitHub repositories after compromising a user account."
rule_id = "mr_9063e681-ac7b-4fad-8bcf-08ed1ae367da"
rule_name = "GitHub High Number Of Non Public GitHub Repositories Cloned"
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.metadata.vendor_name = "GITHUB" nocase
$github.metadata.product_name = "GITHUB"
$github.metadata.product_event_type = "git.clone"
$github.extracted.fields["repository_public"] = "false"
$github.principal.user.userid = $user_id
$github.target.resource.name = $github_repo_name
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.metadata.id)
$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:
// Customize GitHub repo count to fit your environment
$github and $github_repo_name_distinct_count > 5
}
YARA-L Rule Structure
Condition
Fires when at least one $github event in the 30m window and $github_repo_name_distinct_count > 5.
Events
$github
metadata.product_event_type = "git.clone"extracted.fields["repository_public"] = "false"
Match and Correlation
Outcome
Outcome variables add context to a detection. When the rule generates an alert, $risk_score is displayed with it.
| Field | Expression |
|---|---|
github_repo_name_distinct_count | count_distinct($github_repo_name) |
risk_score | max(85) |
event_count | count_distinct($github.metadata.id) |
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) |
Hacktool - IronSharpPack Execution
#Detects the execution of known attacker tools, including but not limited to those in the IronSharpPack toolset. These tools are commonly used for offensive security operations and may indicate malicious activity if observed in unauthorized environments.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Execution |
References
Telemetry Coverage
| Provider | Record / event type |
|---|---|
| Sysmon | Event ID 1: Process creation |
| Security-Auditing | Event ID 4688: A new process has been created. |
Rule Body
// Copyright 2025 Google LLC. Licensed under Apache-2.0.
rule hacktool_ironsharp_pack_execution {
meta:
author = "Georg Lauenstein - suresecure GmbH"
description = "Detects the execution of known attacker tools, including but not limited to those in the IronSharpPack toolset. These tools are commonly used for offensive security operations and may indicate malicious activity if observed in unauthorized environments."
rule_id = "mr_34f2ecef-cd3e-4dee-9c83-b7a9ec34becc"
rule_name = "Hacktool - IronSharpPack Execution"
tactic = "TA0002"
technique = "T1059"
references = "https://github.com/BC-SECURITY/IronSharpPack"
type = "alert"
platform = "Linux, Windows, EDR"
data_source = "Sysmon for Linux, Microsoft Sysmon, Windows Event Logs"
severity = "Medium" // Adjust based on your risk assessment
priority = "Medium" // Adjust based on your incident response process
events:
$ironsharp_execution.metadata.event_type = "PROCESS_LAUNCH"
$ironsharp_execution.target.process.file.full_path = /cmd\.exe|python.*\.exe|ipy\.exe|powershell\.exe|pwsh\.exe|wsl\.exe/ nocase and
$ironsharp_execution.target.process.command_line = /IronADCSPwn\.py|IronADFSDump\.py|IronBetterSafetyKatz\.py|IronCertify\.py|IronDeployPrinterNightmare\.py|IronEmbed\.py|IronEDD\.py|IronGrouper2\.py|IronInveigh\.py|IronLockLess\.py|IronPassTheCert\.py|IronRubeus\.py|IronSafetyKatz\.py|IronSearchOutlook\.py|IronSeatbelt\.py|IronSharPersist\.py|IronSharp-SMBExec\.py|IronSharpAllowedToAct\.py|IronSharpBypassUAC\.py|IronSharpCOM\.py|IronSharpChisel\.py|IronSharpChrome\.py|IronSharpChromium\.py|IronSharpCloud\.py|IronSharpCookieMonster\.py|IronSharpCrashEventLog\.py|IronSharpDPAPI\.py|IronSharpDir\.py|IronSharpDoor\.py|IronSharpDump\.py|IronSharpEDRChecker\.py|IronSharpExec\.py|IronSharpGPOAbuse\.py|IronSharpHandler\.py|IronSharpKatz\.py|IronSharpLAPS\.py|IronSharpMapExec\.py|IronSharpMiniDump\.py|IronSharpMove\.py|IronSharpNamedPipePTH\.py|IronSharpReg\.py|IronSharpSQLPwn\.py|IronSharpSearch\.py|IronSharpSecDump\.py|IronSharpSniper\.py|IronSharpSpray\.py|IronSharpStay\.py|IronSharpTask\.py|IronSharpUp\.py|IronSharpWMI\.py|IronSharpWebServer\.py|IronSharpWifiGrabber\.py|IronSharpZeroLogon\.py|IronShhmon\.py|IronSqlClient\.py|IronStandIn\.py|IronStickyNotesExtract\.py|IronThunderFox\.py|IronTokenStomp\.py|IronWMIReg\.py|IronWatson\.py|Iron_RunasCs\.py|Ironscout\.py|Ironsharpfiles\.py|Ironsharpshares\.py/ nocase
// Capture the hostname where the event occurred
$ironsharp_execution.principal.hostname = $hostname
match:
$hostname over 15m
outcome:
$risk_score = max(65)
$event_count = count_distinct($ironsharp_execution.metadata.id)
$principal_process_pid = array_distinct($ironsharp_execution.principal.process.pid)
$principal_process_command_line = array_distinct($ironsharp_execution.principal.process.command_line)
$principal_process_file_sha256 = array_distinct($ironsharp_execution.principal.process.file.sha256)
$principal_process_file_full_path = array_distinct($ironsharp_execution.principal.process.file.full_path)
$principal_process_product_specific_process_id = array_distinct($ironsharp_execution.principal.process.product_specific_process_id)
$principal_process_parent_process_product_specific_process_id = array_distinct($ironsharp_execution.principal.process.parent_process.product_specific_process_id)
$target_process_pid = array_distinct($ironsharp_execution.target.process.pid)
$target_process_command_line = array_distinct($ironsharp_execution.target.process.command_line)
$target_process_file_sha256 = array_distinct($ironsharp_execution.target.process.file.sha256)
$target_process_file_full_path = array_distinct($ironsharp_execution.target.process.file.full_path)
$target_process_product_specific_process_id = array_distinct($ironsharp_execution.target.process.product_specific_process_id)
$principal_user_userid = array_distinct($ironsharp_execution.principal.user.userid)
condition:
$ironsharp_execution
}
YARA-L Rule Structure
Condition
Fires when at least one $ironsharp_execution event in the 15m window.
Events
$ironsharp_execution
target.process.file.full_path matches "cmd\.exe|python.*\.exe|ipy\.exe|powershell\.exe|pwsh\.exe|wsl\.exe"target.process.command_line matches "IronADCSPwn\.py|IronADFSDump\.py|IronBetterSafetyKatz\.py|IronCertify\.py|IronDeployPrinterNightmare\.py|IronEmbed\.py|IronEDD\.py|IronGrouper2\.py|IronInveigh\.py|IronLockLess\.py|IronPassTheCert\.py|IronRubeus\.py|IronSafetyKatz\.py|IronSearchOutlook\.py|IronSeatbelt\.py|IronSharPersist\.py|IronSharp-SMBExec\.py|IronSharpAllowedToAct\.py|IronSharpBypassUAC\.py|IronSharpCOM\.py|IronSharpChisel\.py|IronSharpChrome\.py|IronSharpChromium\.py|IronSharpCloud\.py|IronSharpCookieMonster\.py|IronSharpCrashEventLog\.py|IronSharpDPAPI\.py|IronSharpDir\.py|IronSharpDoor\.py|IronSharpDump\.py|IronSharpEDRChecker\.py|IronSharpExec\.py|IronSharpGPOAbuse\.py|IronSharpHandler\.py|IronSharpKatz\.py|IronSharpLAPS\.py|IronSharpMapExec\.py|IronSharpMiniDump\.py|IronSharpMove\.py|IronSharpNamedPipePTH\.py|IronSharpReg\.py|IronSharpSQLPwn\.py|IronSharpSearch\.py|IronSharpSecDump\.py|IronSharpSniper\.py|IronSharpSpray\.py|IronSharpStay\.py|IronSharpTask\.py|IronSharpUp\.py|IronSharpWMI\.py|IronSharpWebServer\.py|IronSharpWifiGrabber\.py|IronSharpZeroLogon\.py|IronShhmon\.py|IronSqlClient\.py|IronStandIn\.py|IronStickyNotesExtract\.py|IronThunderFox\.py|IronTokenStomp\.py|IronWMIReg\.py|IronWatson\.py|Iron_RunasCs\.py|Ironscout\.py|Ironsharpfiles\.py|Ironsharpshares\.py"
Match and Correlation
Outcome
Outcome variables add context to a detection. When the rule generates an alert, $risk_score is displayed with it.
| Field | Expression |
|---|---|
risk_score | max(65) |
event_count | count_distinct($ironsharp_execution.metadata.id) |
principal_process_pid | array_distinct($ironsharp_execution.principal.process.pid) |
principal_process_command_line | array_distinct($ironsharp_execution.principal.process.command_line) |
principal_process_file_sha256 | array_distinct($ironsharp_execution.principal.process.file.sha256) |
principal_process_file_full_path | array_distinct($ironsharp_execution.principal.process.file.full_path) |
principal_process_product_specific_process_id | array_distinct($ironsharp_execution.principal.process.product_specific_process_id) |
principal_process_parent_process_product_specific_process_id | array_distinct($ironsharp_execution.principal.process.parent_process.product_specific_process_id) |
target_process_pid | array_distinct($ironsharp_execution.target.process.pid) |
target_process_command_line | array_distinct($ironsharp_execution.target.process.command_line) |
target_process_file_sha256 | array_distinct($ironsharp_execution.target.process.file.sha256) |
target_process_file_full_path | array_distinct($ironsharp_execution.target.process.file.full_path) |
target_process_product_specific_process_id | array_distinct($ironsharp_execution.target.process.product_specific_process_id) |
principal_user_userid | array_distinct($ironsharp_execution.principal.user.userid) |
Okta User Account Lockout
#Detects when a user's account is locked out or a user account has reached the lockout limit.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access | |
| Persistence | |
| Privilege Escalation | |
| Stealth |
References
Telemetry Coverage
Rules Detecting the Same Action
These rules filter on the same operation.
- Attempts to Brute Force an Okta User Account (Elastic)
- Okta Multiple Accounts Locked Out (Splunk)
- Okta User Account Locked (Panther)
Rule Body
// Copyright 2023 Google LLC. Licensed under Apache-2.0.
rule okta_user_account_lockout {
meta:
author = "Google Cloud Security"
description = "Detects when a user's account is locked out or a user account has reached the lockout limit."
rule_id = "mr_b7d1d908-77db-4217-a170-44e0423c7fbe"
rule_name = "Okta User Account Lockout"
reference = "https://www.okta.com/resources/whitepaper/how-adaptive-mfa-helps-mitigate-brute-force-attacks/"
mitre_attack_tactic = "Defense Evasion, Persistence, Privilege Escalation, Initial Access"
mitre_attack_technique = "Valid Accounts"
mitre_attack_url = "https://attack.mitre.org/techniques/T1078/"
mitre_attack_version = "v13.1"
type = "Alert"
data_source = "Okta"
severity = "Medium"
priority = "Medium"
events:
$login.metadata.product_name = "Okta"
$login.metadata.vendor_name = "Okta"
(
$login.metadata.product_event_type = "user.account.lock.limit" or
$login.metadata.product_event_type = "user.account.lock"
)
$login.security_result.action = "BLOCK"
$login.principal.user.userid = $userid
match:
$userid over 1h
outcome:
$risk_score = max(35)
$mitre_attack_tactic = "Defense Evasion, Persistence, Privilege Escalation, Initial Access"
$mitre_attack_technique = "Valid Accounts"
$target_user_agent = array_distinct($login.network.http.user_agent)
$principal_ip = array_distinct($login.principal.ip)
$principal_ip_country = array_distinct($login.principal.ip_geo_artifact.location.country_or_region)
$principal_ip_state = array_distinct($login.principal.ip_geo_artifact.location.state)
$principal_ip_city = array_distinct($login.principal.location.city)
$principal_user_email_addresses = array_distinct ($login.principal.user.email_addresses)
$security_result_summary = array_distinct($login.security_result.summary)
$security_result_category_details = array_distinct($login.security_result.category_details)
condition:
$login
}
YARA-L Rule Structure
Condition
Fires when at least one $login event in the 1h window.
Events
$login
metadata.product_event_type = "user.account.lock.limit" or "user.account.lock"security_result.action = "BLOCK"
Match and Correlation
Outcome
Outcome variables add context to a detection. When the rule generates an alert, $risk_score is displayed with it.
| Field | Expression |
|---|---|
risk_score | max(35) |
target_user_agent | array_distinct($login.network.http.user_agent) |
principal_ip | array_distinct($login.principal.ip) |
principal_ip_country | array_distinct($login.principal.ip_geo_artifact.location.country_or_region) |
principal_ip_state | array_distinct($login.principal.ip_geo_artifact.location.state) |
principal_ip_city | array_distinct($login.principal.location.city) |
principal_user_email_addresses | array_distinct ($login.principal.user.email_addresses) |
security_result_summary | array_distinct($login.security_result.summary) |
security_result_category_details | array_distinct($login.security_result.category_details) |
sap change documents sensitive profile assignment
#Detects the assignment of highly privileged SAP profiles via Change Documents.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Privilege Escalation |
Rule Body
// Copyright 2026 Google LLC. Licensed under Apache-2.0.
rule sap_change_documents_sensitive_profile_assignment {
meta:
author = "Google Cloud Security"
description = "Detects the assignment of highly privileged SAP profiles via Change Documents."
severity = "Critical"
tactic = "TA0004"
technique = "T1098"
events:
$e.metadata.log_type = "SAP_CHANGE_DOCUMENT"
$e.target.resource.attribute.labels["TABKEY"] = /^SAP_ALL$|^SAP_NEW$/
$e.target.resource.name = "IDENTITY"
$principal_user = $e.principal.user.userid
match:
$principal_user over 30m
outcome:
$target_user = array_distinct($e.target.resource.product_object_id)
$tcode = array_distinct($e.target.application)
$tabname = array_distinct($e.target.resource.attribute.labels["TABNAME"])
$sensitive_profile_assigned = array_distinct($e.target.resource.attribute.labels["TABKEY"])
condition:
$e
}
YARA-L Rule Structure
Condition
Fires when at least one $e event in the 30m window.
Events
$e
metadata.log_type = "SAP_CHANGE_DOCUMENT"target.resource.attribute.labels["TABKEY"] matches "^SAP_ALL$|^SAP_NEW$"target.resource.name = "IDENTITY"
Match and Correlation
Outcome
Outcome variables add context to a detection. When the rule generates an alert, $risk_score is displayed with it.
| Field | Expression |
|---|---|
target_user | array_distinct($e.target.resource.product_object_id) |
tcode | array_distinct($e.target.application) |
tabname | array_distinct($e.target.resource.attribute.labels["TABNAME"]) |
sensitive_profile_assigned | array_distinct($e.target.resource.attribute.labels["TABKEY"]) |