Detection rules › Elastic
Elastic rules: 0a
AWS IAM Permissions Boundary Modified or Removed
#Identifies the modification or removal of an IAM permissions boundary on an IAM user or role. A permissions boundary caps the maximum permissions an identity can have, regardless of its attached identity policies. An adversary who can delete a boundary ("DeleteUserPermissionsBoundary", "DeleteRolePermissionsBoundary") or replace it with a more permissive one ("PutUserPermissionsBoundary", "PutRolePermissionsBoundary") can lift that cap and unlock permissions the identity's policies already grant, enabling privilege escalation. Boundary changes are infrequent and usually performed by a small set of administrators or infrastructure-as-code pipelines, so changes by unexpected principals warrant review.
Known False Positives
- Permissions boundaries are managed by identity/platform teams and infrastructure-as-code pipelines as part of normal governance. Verify the principal in `aws.cloudtrail.user_identity.arn`, the targeted user or role, and the boundary policy against approved change records. Known administration roles and deployment automation can be excluded after validation.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Privilege Escalation |
Telemetry Coverage
Rule Body
[metadata]
creation_date = "2026/06/18"
integration = ["aws"]
maturity = "production"
updated_date = "2026/06/18"
[rule]
author = ["Elastic"]
description = """
Identifies the modification or removal of an IAM permissions boundary on an IAM user or role. A permissions boundary
caps the maximum permissions an identity can have, regardless of its attached identity policies. An adversary who can
delete a boundary ("DeleteUserPermissionsBoundary", "DeleteRolePermissionsBoundary") or replace it with a more
permissive one ("PutUserPermissionsBoundary", "PutRolePermissionsBoundary") can lift that cap and unlock permissions the
identity's policies already grant, enabling privilege escalation. Boundary changes are infrequent and usually performed
by a small set of administrators or infrastructure-as-code pipelines, so changes by unexpected principals warrant
review.
"""
false_positives = [
"""
Permissions boundaries are managed by identity/platform teams and infrastructure-as-code pipelines as part of normal
governance. Verify the principal in `aws.cloudtrail.user_identity.arn`, the targeted user or role, and the boundary
policy against approved change records. Known administration roles and deployment automation can be excluded after
validation.
""",
]
from = "now-6m"
index = ["logs-aws.cloudtrail-*"]
language = "kuery"
license = "Elastic License v2"
name = "AWS IAM Permissions Boundary Modified or Removed"
note = """## Triage and analysis
### Investigating AWS IAM Permissions Boundary Modified or Removed
An IAM permissions boundary is the maximum set of permissions an identity can ever have — even if its identity policies grant more, the effective permissions are the intersection of the two. Removing a boundary (`DeleteUserPermissionsBoundary` / `DeleteRolePermissionsBoundary`) or replacing it with a broader one (`PutUserPermissionsBoundary` / `PutRolePermissionsBoundary`) lifts that cap, so any permissions already present in the identity's attached policies immediately take effect. This is a recognized privilege-escalation path: an adversary who can edit a boundary can unlock latent permissions without attaching any new policy.
#### Possible investigation steps
- Identify the actor in `aws.cloudtrail.user_identity.arn`, `aws.cloudtrail.user_identity.type`, and `aws.cloudtrail.user_identity.session_context.session_issuer.arn`, and review `source.ip` / `user_agent.original` to determine how the change was made (console, CLI, SDK, automation).
- Inspect `aws.cloudtrail.request_parameters` for the targeted `userName`/`roleName` and, for `Put*` operations, the `permissionsBoundary` policy ARN that was applied.
- Determine the identity's attached identity policies to assess what permissions are now unlocked by the boundary change (the effective blast radius).
- Confirm whether the change aligns with an approved governance change, onboarding, or deployment.
- Correlate with recent activity by the same principal, such as policy attachment, access key creation, or role assumption that may indicate an escalation chain.
### False positive analysis
- Identity/platform teams and infrastructure-as-code routinely set and update boundaries. Confirm the change is approved and exclude known administration roles or automation on `aws.cloudtrail.user_identity.arn` after validation.
### Response and remediation
- If the change is unauthorized, restore the intended permissions boundary on the affected identity and review what the identity could access while the boundary was relaxed or absent.
- Rotate or restrict credentials for the principal that made the change if compromise is suspected, and constrain `iam:PutUserPermissionsBoundary`, `iam:PutRolePermissionsBoundary`, `iam:DeleteUserPermissionsBoundary`, and `iam:DeleteRolePermissionsBoundary` to a small set of trusted administrators.
"""
references = [
"https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_boundaries.html",
"https://hackingthe.cloud/aws/exploitation/iam_privilege_escalation/",
]
risk_score = 47
rule_id = "0f5d410c-a594-4cdb-8b48-f36a61838d67"
severity = "medium"
tags = [
"Domain: Cloud",
"Domain: Identity",
"Data Source: AWS",
"Data Source: Amazon Web Services",
"Data Source: AWS IAM",
"Use Case: Threat Detection",
"Tactic: Privilege Escalation",
"Resources: Investigation Guide",
]
timestamp_override = "event.ingested"
type = "query"
query = '''
data_stream.dataset: "aws.cloudtrail"
and event.provider: "iam.amazonaws.com"
and event.action: (
"PutUserPermissionsBoundary" or
"PutRolePermissionsBoundary" or
"DeleteUserPermissionsBoundary" or
"DeleteRolePermissionsBoundary"
)
and event.outcome: "success"
and not aws.cloudtrail.user_identity.type: "AWSService"
and not user_agent.original: (*terraform* or *pulumi* or *ansible*)
and not aws.cloudtrail.user_identity.arn: (*terraform* or *pulumi* or *ansible*)
and not source.as.organization.name: (Amazon* or AMAZON* or Google*)
and not source.address: ("cloudformation.amazonaws.com" or "servicecatalog.amazonaws.com")
'''
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1098"
name = "Account Manipulation"
reference = "https://attack.mitre.org/techniques/T1098/"
[rule.threat.tactic]
id = "TA0004"
name = "Privilege Escalation"
reference = "https://attack.mitre.org/tactics/TA0004/"
[rule.investigation_fields]
field_names = [
"@timestamp",
"user.name",
"user_agent.original",
"source.ip",
"aws.cloudtrail.user_identity.arn",
"aws.cloudtrail.user_identity.type",
"aws.cloudtrail.user_identity.access_key_id",
"aws.cloudtrail.user_identity.session_context.session_issuer.arn",
"aws.cloudtrail.request_parameters",
"aws.cloudtrail.response_elements",
"event.action",
"event.outcome",
"cloud.account.id",
"cloud.region",
]
Stages and Predicates
Stage 1: query
data_stream.dataset: "aws.cloudtrail"
and event.provider: "iam.amazonaws.com"
and event.action: (
"PutUserPermissionsBoundary" or
"PutRolePermissionsBoundary" or
"DeleteUserPermissionsBoundary" or
"DeleteRolePermissionsBoundary"
)
and event.outcome: "success"
and not aws.cloudtrail.user_identity.type: "AWSService"
and not user_agent.original: (*terraform* or *pulumi* or *ansible*)
and not aws.cloudtrail.user_identity.arn: (*terraform* or *pulumi* or *ansible*)
and not source.as.organization.name: (Amazon* or AMAZON* or Google*)
and not source.address: ("cloudformation.amazonaws.com" or "servicecatalog.amazonaws.com")
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
data_stream.dataset | eq |
| field:"data_stream.dataset" kind:eq value:"aws.cloudtrail" |
event.action | in |
| field:"EventType" kind:in |
event.outcome | eq |
| field:"event.outcome" kind:eq value:"success" |
event.provider | eq |
| field:"Provider_Name" kind:eq value:"iam.amazonaws.com" |
Exclusions
The rule actively suppresses these predicates.
Azure AKS Suspicious Self-Subject Review by Service Account or Node Identity
#Detects AKS (Azure Kubernetes Service) service account or node identities invoking self-subject access or rules review APIs. Non-human identities rarely enumerate their own permissions outside known controllers; this can indicate stolen tokens probing effective RBAC before privilege escalation.
Known False Positives
- SelfSubjectAccessReview ("can I do X") is routinely issued by controllers checking their own permissions, so busy clusters generate benign volume from platform and add-on service accounts (for example kube-system managed add-ons such as azure-policy, Microsoft Defender, metrics-server, and konnectivity, plus operators like cert-manager, ingress controllers, and Argo/Flux). The rule ships with only the Azure Arc agent accounts (system:serviceaccount:azure-arc:*) excluded; that namespace exists only on Arc-enabled clusters and is one example, not a complete list. Treat the exclusion set as a per-environment denylist: baseline the calling service accounts and add validated platform/observability controllers after review. SelfSubjectRulesReview ("list everything I can do") is far rarer from non-human identities and higher signal. Admin impersonation workflows can also trigger this via an impersonated service account; validate the impersonating user.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Discovery |
Telemetry Coverage
Rules Detecting the Same Action
These rules filter on the same operation.
Rule Body
[metadata]
creation_date = "2026/07/09"
integration = ["azure"]
maturity = "production"
updated_date = "2026/07/09"
[rule]
author = ["Elastic"]
description = """
Detects AKS (Azure Kubernetes Service) service account or node identities invoking self-subject access or rules review
APIs. Non-human identities rarely enumerate their own permissions outside known controllers; this can indicate stolen
tokens probing effective RBAC before privilege escalation.
"""
false_positives = [
"""
SelfSubjectAccessReview ("can I do X") is routinely issued by controllers checking their own permissions, so busy
clusters generate benign volume from platform and add-on service accounts (for example kube-system managed add-ons
such as azure-policy, Microsoft Defender, metrics-server, and konnectivity, plus operators like cert-manager,
ingress controllers, and Argo/Flux). The rule ships with only the Azure Arc agent accounts
(system:serviceaccount:azure-arc:*) excluded; that namespace exists only on Arc-enabled clusters and is one example,
not a complete list. Treat the exclusion set as a per-environment denylist: baseline the calling service accounts and
add validated platform/observability controllers after review. SelfSubjectRulesReview ("list everything I can do")
is far rarer from non-human identities and higher signal. Admin impersonation workflows can also trigger this via an
impersonated service account; validate the impersonating user.
""",
]
from = "now-9m"
index = ["logs-azure.platformlogs-*"]
language = "kuery"
license = "Elastic License v2"
name = "Azure AKS Suspicious Self-Subject Review by Service Account or Node Identity"
note = """## Triage and analysis
### Investigating Azure AKS Suspicious Self-Subject Review by Service Account or Node Identity
AKS kube-audit events are carried under the flattened `azure.platformlogs.properties.log.*` subtree and share the ARM
operation `event.action: Microsoft.ContainerService/managedClusters/diagnosticLogs/Read`. A `selfsubjectaccessreviews`
or `selfsubjectrulesreviews` create lets the caller enumerate its own effective permissions. Service account and node
identities issuing these reviews outside of known controllers can indicate a stolen token mapping out what it can reach.
### Possible investigation steps
- Confirm the acting identity in `azure.platformlogs.properties.log.user.username` and its groups in
`azure.platformlogs.properties.log.user.groups`, and whether that service account or node routinely performs
self-subject reviews. Check `azure.platformlogs.properties.log.impersonatedUser.username`: when populated, the review
was issued via impersonation (e.g. `kubectl auth can-i --as=<service account>`) and the real actor is the
impersonating user, not the service account in `user.username`.
- Review `azure.platformlogs.properties.log.objectRef.resource` (selfsubjectaccessreviews or selfsubjectrulesreviews)
and the `azure.platformlogs.properties.log.requestObject` to see what access was checked, plus the API path in
`azure.platformlogs.properties.log.requestURI`. Inspect `azure.platformlogs.properties.log.userAgent` to distinguish
interactive tooling (`kubectl`) from custom recon tooling or in-cluster SDKs.
- Evaluate the source in `azure.platformlogs.properties.log.sourceIPs`. Control-plane and in-cluster agents use loopback
(`127.0.0.1`/`::1`) or pod-network addresses (e.g. `10.244.0.0/16`); an external caller wielding a service account
token is more suspicious. Pivot on the source for related API activity, denied requests, exec sessions, or RBAC
changes from the same identity.
### False positive analysis
- Known observability or workflow controllers may issue self-subject reviews; extend exclusions for validated
identities. Azure Arc's agent service accounts (`system:serviceaccount:azure-arc:*`) legitimately submit these reviews
and are already excluded; add other validated platform controllers as they are baselined.
- Admin impersonation workflows can trigger this via an impersonated service account; validate the impersonating user in
`azure.platformlogs.properties.log.impersonatedUser.username`.
### Response and remediation
- If unauthorized, revoke the service account token and review the RBAC bindings granted to it.
- Correlate with any successful privileged actions the identity performed after the review.
- Collect kube-audit and identity artifacts per incident response procedures.
"""
references = [
"https://kubernetes.io/docs/reference/access-authn-authz/authorization/#checking-api-access",
"https://microsoft.github.io/Threat-Matrix-for-Kubernetes/",
"https://github.com/inguardians/peirates",
]
risk_score = 21
rule_id = "11afa743-5264-460b-9d0a-b687efd38a71"
setup = """
The Azure Fleet integration collecting AKS diagnostic logs forwarded through Event Hub into the `azure.platformlogs`
data stream is required for this rule. Enable either the `kube-audit` or the `kube-audit-admin` log category (Microsoft
recommends `kube-audit-admin` alone to reduce volume, as it only drops read-only get/list events). Self-subject review
creates are recorded in both categories with the same `auditID`, so clusters that enable both categories may generate
two alerts per review.
"""
severity = "low"
tags = [
"Domain: Cloud",
"Domain: Kubernetes",
"Data Source: Azure",
"Data Source: Azure Platform Logs",
"Data Source: Kubernetes",
"Use Case: Threat Detection",
"Tactic: Discovery",
"Resources: Investigation Guide",
]
timestamp_override = "event.ingested"
type = "query"
query = '''
data_stream.dataset:azure.platformlogs and
event.action:Microsoft.ContainerService/managedClusters/diagnosticLogs/Read and
azure.platformlogs.category:(kube-audit or kube-audit-admin) and
azure.platformlogs.properties.log.stage:ResponseComplete and
azure.platformlogs.properties.log.verb:create and
azure.platformlogs.properties.log.objectRef.resource:(selfsubjectaccessreviews or selfsubjectrulesreviews) and
azure.platformlogs.properties.log.user.username:((system\:node\:* or system\:serviceaccount\:*) and
not system\:serviceaccount\:azure-arc\:*)
'''
[rule.investigation_fields]
field_names = [
"@timestamp",
"event.action",
"azure.platformlogs.category",
"azure.platformlogs.properties.log.verb",
"azure.platformlogs.properties.log.user.username",
"azure.platformlogs.properties.log.user.groups",
"azure.platformlogs.properties.log.impersonatedUser.username",
"azure.platformlogs.properties.log.userAgent",
"azure.platformlogs.properties.log.sourceIPs",
"azure.platformlogs.properties.log.objectRef.resource",
"azure.platformlogs.properties.log.objectRef.namespace",
"azure.platformlogs.properties.log.requestURI",
"azure.platformlogs.properties.log.responseStatus.code",
]
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1069"
name = "Permission Groups Discovery"
reference = "https://attack.mitre.org/techniques/T1069/"
[[rule.threat.technique.subtechnique]]
id = "T1069.003"
name = "Cloud Groups"
reference = "https://attack.mitre.org/techniques/T1069/003/"
[[rule.threat.technique]]
id = "T1613"
name = "Container and Resource Discovery"
reference = "https://attack.mitre.org/techniques/T1613/"
[rule.threat.tactic]
id = "TA0007"
name = "Discovery"
reference = "https://attack.mitre.org/tactics/TA0007/"
Stages and Predicates
Stage 1: query
data_stream.dataset:azure.platformlogs and
event.action:Microsoft.ContainerService/managedClusters/diagnosticLogs/Read and
azure.platformlogs.category:(kube-audit or kube-audit-admin) and
azure.platformlogs.properties.log.stage:ResponseComplete and
azure.platformlogs.properties.log.verb:create and
azure.platformlogs.properties.log.objectRef.resource:(selfsubjectaccessreviews or selfsubjectrulesreviews) and
azure.platformlogs.properties.log.user.username:((system\:node\:* or system\:serviceaccount\:*) and
not system\:serviceaccount\:azure-arc\:*)
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
azure.platformlogs.category | in |
| field:"azure.platformlogs.category" kind:in |
azure.platformlogs.properties.log.objectRef.resource | in |
| field:"azure.platformlogs.properties.log.objectRef.resource" kind:in |
azure.platformlogs.properties.log.stage | eq |
| field:"azure.platformlogs.properties.log.stage" kind:eq value:"ResponseComplete" |
azure.platformlogs.properties.log.user.username | wildcard |
| field:"azure.platformlogs.properties.log.user.username" kind:wildcard |
azure.platformlogs.properties.log.verb | eq |
| field:"azure.platformlogs.properties.log.verb" kind:eq value:"create" |
data_stream.dataset | eq |
| field:"data_stream.dataset" kind:eq value:"azure.platformlogs" |
event.action | eq |
| field:"EventType" kind:eq value:"Microsoft.ContainerService/managedClusters/diagnosticLogs/Read" |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
azure.platformlogs.properties.log.user.username | starts_with | system:serviceaccount:azure-arc: | excludes:azure.platformlogs.properties.log.user.username field:"azure.platformlogs.properties.log.user.username" value:"system:serviceaccount:azure-arc:" |
Azure Automation Runbook Deleted
#Identifies when an Azure Automation runbook is deleted. An adversary may delete an Azure Automation runbook in order to disrupt their target's automated business operations or to remove a malicious runbook for defense evasion.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Impact |
Telemetry Coverage
Rule Body
[metadata]
creation_date = "2020/09/01"
integration = ["azure"]
maturity = "production"
updated_date = "2026/04/10"
[rule]
author = ["Elastic"]
description = """
Identifies when an Azure Automation runbook is deleted. An adversary may delete an Azure Automation runbook in order to
disrupt their target's automated business operations or to remove a malicious runbook for defense evasion.
"""
from = "now-9m"
index = ["logs-azure.activitylogs-*", "filebeat-*"]
language = "kuery"
license = "Elastic License v2"
name = "Azure Automation Runbook Deleted"
note = """## Triage and analysis
> **Disclaimer**:
> This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs.
### Investigating Azure Automation Runbook Deleted
Azure Automation Runbooks automate repetitive tasks in cloud environments, enhancing operational efficiency. Adversaries may exploit this by deleting runbooks to disrupt operations or conceal malicious activities. The detection rule monitors Azure activity logs for successful runbook deletions, signaling potential defense evasion tactics, and alerts analysts to investigate further.
### Possible investigation steps
- Review the Azure activity logs to confirm the deletion event by checking the operation name "MICROSOFT.AUTOMATION/AUTOMATIONACCOUNTS/RUNBOOKS/DELETE" and ensure the event outcome is marked as Success.
- Identify the user or service principal responsible for the deletion by examining the associated user identity information in the activity logs.
- Investigate the timeline of events leading up to and following the runbook deletion to identify any suspicious activities or patterns, such as unauthorized access attempts or changes to other resources.
- Check for any recent modifications or unusual activities in the affected Azure Automation account to determine if there are other signs of compromise or tampering.
- Assess the impact of the deleted runbook on business operations and determine if any critical automation processes were disrupted.
- If applicable, review any available backup or version history of the deleted runbook to restore it and mitigate operational disruptions.
### False positive analysis
- Routine maintenance activities by IT staff may lead to legitimate runbook deletions. To manage this, create exceptions for known maintenance periods or specific user accounts responsible for these tasks.
- Automated scripts or third-party tools that manage runbooks might trigger deletions as part of their normal operation. Identify these tools and exclude their activity from alerts by filtering based on their service accounts or IP addresses.
- Organizational policy changes or cloud environment restructuring can result in planned runbook deletions. Document these changes and adjust the detection rule to exclude these events by correlating with change management records.
- Test environments often involve frequent creation and deletion of runbooks. Exclude these environments from alerts by using tags or specific resource group identifiers associated with non-production environments.
### Response and remediation
- Immediately isolate the affected Azure Automation account to prevent further unauthorized deletions or modifications of runbooks.
- Review the Azure activity logs to identify the user or service principal responsible for the deletion and revoke their access if unauthorized.
- Restore the deleted runbook from backups or version control if available, ensuring that the restored version is free from any malicious modifications.
- Conduct a security review of all remaining runbooks to ensure they have not been tampered with or contain malicious code.
- Implement stricter access controls and auditing for Azure Automation accounts, ensuring that only authorized personnel have the ability to delete runbooks.
- Escalate the incident to the security operations team for further investigation and to determine if additional malicious activities have occurred.
- Enhance monitoring and alerting for similar activities by integrating additional context or indicators from the MITRE ATT&CK framework related to defense evasion tactics.
## Setup
The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule."""
references = [
"https://powerzure.readthedocs.io/en/latest/Functions/operational.html#create-backdoor",
"https://github.com/hausec/PowerZure",
"https://posts.specterops.io/attacking-azure-azure-ad-and-introducing-powerzure-ca70b330511a",
"https://azure.microsoft.com/en-in/blog/azure-automation-runbook-management/",
]
risk_score = 21
rule_id = "8ddab73b-3d15-4e5d-9413-47f05553c1d7"
severity = "low"
tags = ["Domain: Cloud", "Data Source: Azure", "Use Case: Configuration Audit", "Tactic: Defense Evasion", "Resources: Investigation Guide"]
timestamp_override = "event.ingested"
type = "query"
query = '''
data_stream.dataset:azure.activitylogs and
azure.activitylogs.operation_name:"MICROSOFT.AUTOMATION/AUTOMATIONACCOUNTS/RUNBOOKS/DELETE" and
event.outcome:(Success or success)
'''
[[rule.threat]]
framework = "MITRE ATT&CK"
[rule.threat.tactic]
id = "TA0005"
name = "Defense Evasion"
reference = "https://attack.mitre.org/tactics/TA0005/"
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1485"
name = "Data Destruction"
reference = "https://attack.mitre.org/techniques/T1485/"
[rule.threat.tactic]
id = "TA0040"
name = "Impact"
reference = "https://attack.mitre.org/tactics/TA0040/"
Stages and Predicates
Stage 1: query
data_stream.dataset:azure.activitylogs and
azure.activitylogs.operation_name:"MICROSOFT.AUTOMATION/AUTOMATIONACCOUNTS/RUNBOOKS/DELETE" and
event.outcome:(Success or success)
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
azure.activitylogs.operation_name | eq |
| field:"azure.activitylogs.operation_name" kind:eq value:"MICROSOFT.AUTOMATION/AUTOMATIONACCOUNTS/RUNBOOKS/DELETE" |
data_stream.dataset | eq |
| field:"data_stream.dataset" kind:eq value:"azure.activitylogs" |
event.outcome | in |
| field:"event.outcome" kind:in |
File made Immutable by Chattr
#Detects a file being made immutable using the chattr binary. Making a file immutable means it cannot be deleted or renamed, no link can be created to this file, most of the file's metadata can not be modified, and the file can not be opened in write mode. Threat actors will commonly utilize this to prevent tampering or modification of their malicious files or any system files they have modified for purposes of persistence (e.g .ssh, /etc/passwd, etc.).
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Defense Impairment |
Rule Body
[metadata]
creation_date = "2022/07/22"
integration = ["endpoint", "sentinel_one_cloud_funnel", "auditd_manager", "crowdstrike"]
maturity = "production"
updated_date = "2025/12/17"
[rule]
author = ["Elastic"]
description = """
Detects a file being made immutable using the chattr binary. Making a file immutable means it cannot be deleted or
renamed, no link can be created to this file, most of the file's metadata can not be modified, and the file can not be
opened in write mode. Threat actors will commonly utilize this to prevent tampering or modification of their malicious
files or any system files they have modified for purposes of persistence (e.g .ssh, /etc/passwd, etc.).
"""
from = "now-9m"
index = [
"auditbeat-*",
"endgame-*",
"logs-auditd_manager.auditd-*",
"logs-crowdstrike.fdr*",
"logs-endpoint.events.process*",
"logs-sentinel_one_cloud_funnel.*",
]
language = "eql"
license = "Elastic License v2"
max_signals = 33
name = "File made Immutable by Chattr"
note = """## Triage and analysis
> **Disclaimer**:
> This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs.
### Investigating File made Immutable by Chattr
The `chattr` command in Linux is used to change file attributes, including making files immutable, which prevents modifications or deletions. Adversaries exploit this to secure malicious files or altered system files against tampering, aiding persistence. The detection rule identifies suspicious use of `chattr` by monitoring process executions, filtering out benign parent processes, and focusing on those altering immutability attributes, thus highlighting potential misuse.
### Possible investigation steps
- Review the process execution details to confirm the use of the chattr command with arguments altering immutability, specifically looking for "+i" or "-i" in process.args.
- Identify the file(s) targeted by the chattr command to determine if they are critical system files or files commonly targeted by threat actors, such as .ssh or /etc/passwd.
- Investigate the parent process of the chattr execution by examining process.parent.executable and process.parent.name to determine if it is a known benign process or potentially malicious.
- Check the user context under which the chattr command was executed to assess if it aligns with expected administrative activity or if it indicates unauthorized access.
- Correlate the event with other security alerts or logs to identify any related suspicious activities, such as unauthorized access attempts or changes to other system files.
- Evaluate the risk and impact of the immutable file(s) on system operations and security posture, considering the potential for persistence or defense evasion by threat actors.
### False positive analysis
- System processes like systemd and cf-agent may invoke chattr for legitimate reasons, such as system maintenance or configuration management. To handle these, exclude these processes by adding them to the exception list in the detection rule.
- Scheduled tasks or scripts that use chattr to manage file attributes for security or operational purposes can trigger false positives. Identify these tasks and exclude their parent processes from the rule.
- Administrative actions performed by authorized users, such as securing configuration files, might be flagged. Regularly review and update the list of known benign parent processes to prevent unnecessary alerts.
- Security tools or agents that modify file attributes as part of their protection mechanisms can cause false positives. Ensure these tools are recognized and excluded by their executable paths or parent process names.
### Response and remediation
- Isolate the affected system from the network to prevent further spread or communication with potential command and control servers.
- Identify and terminate any malicious processes associated with the `chattr` command to stop further unauthorized file modifications.
- Restore the affected files from a known good backup, ensuring that any immutable attributes set by the attacker are removed.
- Conduct a thorough review of user accounts and permissions on the affected system to ensure no unauthorized access or privilege escalation has occurred.
- Implement file integrity monitoring to detect unauthorized changes to critical system files, enhancing detection capabilities for similar threats.
- Escalate the incident to the security operations team for further investigation and to determine if additional systems are compromised.
- Review and update security policies and configurations to prevent unauthorized use of the `chattr` command, such as restricting its execution to trusted administrators only."""
risk_score = 47
rule_id = "968ccab9-da51-4a87-9ce2-d3c9782fd759"
setup = """## Setup
This rule requires data coming in from one of the following integrations:
- Elastic Defend
- Auditbeat
### Elastic Defend Integration Setup
Elastic Defend is integrated into the Elastic Agent using Fleet. Upon configuration, the integration allows the Elastic Agent to monitor events on your host and send data to the Elastic Security app.
#### Prerequisite Requirements:
- Fleet is required for Elastic Defend.
- To configure Fleet Server refer to the [documentation](https://www.elastic.co/guide/en/fleet/current/fleet-server.html).
#### The following steps should be executed in order to add the Elastic Defend integration on a Linux System:
- Go to the Kibana home page and click "Add integrations".
- In the query bar, search for "Elastic Defend" and select the integration to see more details about it.
- Click "Add Elastic Defend".
- Configure the integration name and optionally add a description.
- Select the type of environment you want to protect, either "Traditional Endpoints" or "Cloud Workloads".
- Select a configuration preset. Each preset comes with different default settings for Elastic Agent, you can further customize these later by configuring the Elastic Defend integration policy. [Helper guide](https://www.elastic.co/guide/en/security/current/configure-endpoint-integration-policy.html).
- We suggest selecting "Complete EDR (Endpoint Detection and Response)" as a configuration setting, that provides "All events; all preventions"
- Enter a name for the agent policy in "New agent policy name". If other agent policies already exist, you can click the "Existing hosts" tab and select an existing policy instead.
For more details on Elastic Agent configuration settings, refer to the [helper guide](https://www.elastic.co/guide/en/fleet/8.10/agent-policy.html).
- Click "Save and Continue".
- To complete the integration, select "Add Elastic Agent to your hosts" and continue to the next section to install the Elastic Agent on your hosts.
For more details on Elastic Defend refer to the [helper guide](https://www.elastic.co/guide/en/security/current/install-endpoint.html).
### Auditbeat Setup
Auditbeat is a lightweight shipper that you can install on your servers to audit the activities of users and processes on your systems. For example, you can use Auditbeat to collect and centralize audit events from the Linux Audit Framework. You can also use Auditbeat to detect changes to critical files, like binaries and configuration files, and identify potential security policy violations.
#### The following steps should be executed in order to add the Auditbeat on a Linux System:
- Elastic provides repositories available for APT and YUM-based distributions. Note that we provide binary packages, but no source packages.
- To install the APT and YUM repositories follow the setup instructions in this [helper guide](https://www.elastic.co/guide/en/beats/auditbeat/current/setup-repositories.html).
- To run Auditbeat on Docker follow the setup instructions in the [helper guide](https://www.elastic.co/guide/en/beats/auditbeat/current/running-on-docker.html).
- To run Auditbeat on Kubernetes follow the setup instructions in the [helper guide](https://www.elastic.co/guide/en/beats/auditbeat/current/running-on-kubernetes.html).
- For complete “Setup and Run Auditbeat” information refer to the [helper guide](https://www.elastic.co/guide/en/beats/auditbeat/current/setting-up-and-running.html).
#### Custom Ingest Pipeline
For versions <8.2, you need to add a custom ingest pipeline to populate `event.ingested` with @timestamp for non-elastic-agent indexes, like auditbeats/filebeat/winlogbeat etc. For more details to add a custom ingest pipeline refer to the [guide](https://www.elastic.co/guide/en/fleet/current/data-streams-pipeline-tutorial.html).
"""
severity = "medium"
tags = [
"Domain: Endpoint",
"OS: Linux",
"Use Case: Threat Detection",
"Tactic: Defense Evasion",
"Data Source: Elastic Endgame",
"Data Source: Elastic Defend",
"Data Source: SentinelOne",
"Data Source: Auditd Manager",
"Data Source: Crowdstrike",
"Resources: Investigation Guide",
]
timestamp_override = "event.ingested"
type = "eql"
query = '''
process where host.os.type == "linux" and event.type == "start" and
event.action in ("exec", "exec_event", "start", "ProcessRollup2", "executed", "process_started") and
?process.parent.executable != null and
process.name == "chattr" and process.args : ("-*i*", "+*i*") and
not (
?process.parent.executable: (
"/lib/systemd/systemd", "/usr/local/uems_agent/bin/*", "/usr/lib/systemd/systemd", "/usr/local/emps/sbin/php-fpm",
"/usr/local/emps/bin/php"
) or
?process.parent.name in (
"systemd", "cf-agent", "ntpdate", "xargs", "px", "preinst", "auth", "cf-agent", "dcservice", "dcagentupgrader",
"sudo", "ephemeral-disk-warning"
) or
process.args like "/opt/ai-bolit/*"
)
'''
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1222"
name = "File and Directory Permissions Modification"
reference = "https://attack.mitre.org/techniques/T1222/"
[[rule.threat.technique.subtechnique]]
id = "T1222.002"
name = "Linux and Mac File and Directory Permissions Modification"
reference = "https://attack.mitre.org/techniques/T1222/002/"
[rule.threat.tactic]
id = "TA0005"
name = "Defense Evasion"
reference = "https://attack.mitre.org/tactics/TA0005/"
Stages and Predicates
Stage 1: process
process where host.os.type == "linux" and event.type == "start" and
event.action in ("exec", "exec_event", "start", "ProcessRollup2", "executed", "process_started") and
?process.parent.executable != null and
process.name == "chattr" and process.args : ("-*i*", "+*i*") and
not (
?process.parent.executable: (
"/lib/systemd/systemd", "/usr/local/uems_agent/bin/*", "/usr/lib/systemd/systemd", "/usr/local/emps/sbin/php-fpm",
"/usr/local/emps/bin/php"
) or
?process.parent.name in (
"systemd", "cf-agent", "ntpdate", "xargs", "px", "preinst", "auth", "cf-agent", "dcservice", "dcagentupgrader",
"sudo", "ephemeral-disk-warning"
) or
process.args like "/opt/ai-bolit/*"
)
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
event.action | in |
| field:"EventType" kind:in |
event.type | eq |
| field:"event.type" kind:eq value:"start" |
process.args | wildcard |
| field:"process.args" kind:wildcard |
process.name | eq |
| field:"process_basename" kind:eq value:"chattr" |
process.parent.executable | is_not_null | field:"ParentImage" kind:is_not_null |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
process.args | starts_with | /opt/ai-bolit/ | excludes:process.args field:"process.args" value:"/opt/ai-bolit/" |
process.parent.executable | wildcard | /lib/systemd/systemd, /usr/local/uems_agent/bin/*, /usr/lib/systemd/systemd, /usr/local/emps/sbin/php-fpm, /usr/local/emps/bin/php | excludes:process.parent.executable |
process.parent.name | in | auth, cf-agent, dcagentupgrader, dcservice, ephemeral-disk-warning, ntpdate, preinst, px, sudo, systemd, xargs | excludes:process.parent.name |
FortiGate Administrator Login from Multiple IP Addresses
#This rule detects successful logins to the FortiGate management interface using the same Administrator account from multiple distinct source IP addresses within an 24-hour period. Administrator logins from multiple locations in a short time window may indicate credential sharing, compromised credentials, or unauthorized access and should be investigated.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access |
Rule Body
[metadata]
creation_date = "2026/01/28"
integration = ["fortinet_fortigate"]
maturity = "production"
updated_date = "2026/04/10"
[rule]
author = ["Elastic"]
description = """
This rule detects successful logins to the FortiGate management interface using the same Administrator account from
multiple distinct source IP addresses within an 24-hour period. Administrator logins from multiple locations in a short
time window may indicate credential sharing, compromised credentials, or unauthorized access and should be investigated.
"""
from = "now-24h"
interval = "5m"
language = "esql"
license = "Elastic License v2"
name = "FortiGate Administrator Login from Multiple IP Addresses"
note = """## ## Triage and Analysis
### Investigating FortiGate Administrator Login from Multiple IP Addresses
This alert indicates that the same **Administrator** account successfully logged in to the FortiGate management interface from **multiple distinct source IP addresses** within an 24-hour period.
Because FortiGate administrator credentials grant full control over network security infrastructure, this behavior may indicate credential compromise, account sharing, or misuse of administrative access.
### Investigation Steps
- **Review the affected account**
- Identify the administrator account in `source.user.name`.
- Confirm whether the account is shared, personal, or service-related.
- Validate whether concurrent or near-concurrent access is expected.
- **Analyze source IP addresses**
- Review the list of `source.ip` values associated with the logins.
- Determine whether the IPs belong to trusted management networks, VPN pools, or jump hosts.
- Investigate geolocation differences using `source.geo.country_name`.
- **Assess timing and session behavior**
- Check whether logins occurred close together in time or overlapped.
- Identify whether access patterns suggest session hopping or credential reuse.
- **Review post-authentication activity**
- Examine FortiGate logs for configuration changes, policy updates, or administrative actions following the logins.
- Look for additional authentication attempts (successful or failed) from the same IPs or user.
- **Correlate with environment context**
- Verify maintenance windows, incident response activity, or operational tasks that could explain the behavior.
- Confirm whether administrators commonly access FortiGate via multiple networks or devices.
### False Positive Considerations
- Administrators connecting through VPNs with dynamic or rotating IP addresses.
- Access via bastion hosts, load-balanced management interfaces, or cloud-based management tools.
- Automation or orchestration systems using shared administrator credentials.
- Incident response or troubleshooting activity involving multiple access points.
### Response and Remediation
- **If the activity is expected**
- Document the behavior and consider tuning the rule or adding exceptions for known IP ranges or accounts.
- Encourage use of named accounts and centralized access paths.
- **If the activity is suspicious**
- Reset or rotate credentials for the affected administrator account.
- Review FortiGate configuration changes made during the session(s).
- Restrict administrative access to trusted IP ranges.
- Enforce MFA for administrative logins if not already enabled.
- Monitor for additional signs of lateral movement or persistence."""
references = [
"https://www.elastic.co/docs/reference/integrations/fortinet_fortigate",
"https://www.cisa.gov/news-events/alerts/2026/01/28/fortinet-releases-guidance-address-ongoing-exploitation-authentication-bypass-vulnerability-cve-2026",
]
risk_score = 73
rule_id = "8a556117-3f05-430e-b2eb-7df0100b4e3b"
severity = "high"
tags = [
"Use Case: Threat Detection",
"Tactic: Initial Access",
"Resources: Investigation Guide",
"Domain: Network",
"Domain: Identity",
"Data Source: Fortinet",
"Data Source: Fortinet FortiGate",
]
timestamp_override = "event.ingested"
type = "esql"
query = '''
FROM logs-fortinet_fortigate.*, filebeat-* metadata _id
| WHERE data_stream.dataset == "fortinet_fortigate.log" and
event.category == "authentication" and event.action == "login" and
event.outcome == "success" and source.user.roles == "Administrator" and
source.user.name is not null and source.ip is not null
| stats Esql.logon_count = count(*),
Esql.source_ip_count_distinct = COUNT_DISTINCT(source.ip),
Esql.max_timestamp = MAX(@timestamp),
Esql.source_ip_values = VALUES(source.ip),
Esql.message_values = VALUES(message),
Esql.source_geo_country_name_values = VALUES(source.geo.country_name) by source.user.name
// last logon event timestamp is within 6m of the rule execution time to avoid duplicates
| eval Esql.recent = DATE_DIFF("minute", Esql.max_timestamp, now())
| where Esql.recent <= 6 and Esql.logon_count >= 2 and Esql.source_ip_count_distinct >= 2
// move dynamic fields to ECS equivalent for rule exceptions
| eval source.ip = MV_FIRST(Esql.source_ip_values)
| keep source.ip, source.user.name, Esql.*
'''
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1078"
name = "Valid Accounts"
reference = "https://attack.mitre.org/techniques/T1078/"
[rule.threat.tactic]
id = "TA0001"
name = "Initial Access"
reference = "https://attack.mitre.org/tactics/TA0001/"
Stages and Predicates
Stage 1: from
FROM logs-fortinet_fortigate.*, filebeat-* metadata _id
Stage 2: where
| WHERE data_stream.dataset == "fortinet_fortigate.log" and
event.category == "authentication" and event.action == "login" and
event.outcome == "success" and source.user.roles == "Administrator" and
source.user.name is not null and source.ip is not null
Stage 3: stats
| stats Esql.logon_count = count(*),
Esql.source_ip_count_distinct = COUNT_DISTINCT(source.ip),
Esql.max_timestamp = MAX(@timestamp),
Esql.source_ip_values = VALUES(source.ip),
Esql.message_values = VALUES(message),
Esql.source_geo_country_name_values = VALUES(source.geo.country_name) by source.user.name
Stage 4: eval
| eval Esql.recent = DATE_DIFF("minute", Esql.max_timestamp, now())
Stage 5: where
| where Esql.recent <= 6 and Esql.logon_count >= 2 and Esql.source_ip_count_distinct >= 2
Stage 6: eval
| eval source.ip = MV_FIRST(Esql.source_ip_values)
Stage 7: keep
| keep source.ip, source.user.name, Esql.*
Indicators
These rows show field, operator, and value matches.
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
source.ip | KEEP source.ip |
source.user.name | KEEP source.user.name |
Esql.* | KEEP Esql.* |
GitHub Actions Runner with Disabled Telemetry
#This rule detects commands spawned by the GitHub Actions Runner.Worker process on self-hosted runner machines and where RUNNER_TRACKING_ID environment variable is set to an invalid value. RUNNER_TRACKING_ID is an internal environment variable used by GitHub's self-hosted runner to decide whether to generate telemetry. This may indicate an attempt to execute malicious commands without leaving any GitHub-side forensic trace.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access | |
| Execution | |
| Defense Impairment |
Telemetry Coverage
Rule Body
[rule]
description = """
This rule detects commands spawned by the GitHub Actions Runner.Worker process on self-hosted runner machines and where
RUNNER_TRACKING_ID environment variable is set to an invalid value. RUNNER_TRACKING_ID is an internal environment
variable used by GitHub's self-hosted runner to decide whether to generate telemetry. This may indicate an attempt to
execute malicious commands without leaving any GitHub-side forensic trace.
"""
id = "167ae29d-ac26-4cf0-8cfb-596a63a95e4e"
license = "Elastic License v2"
name = "GitHub Actions Runner with Disabled Telemetry"
os_list = ["linux", "macos"]
reference = [
"https://www.elastic.co/blog/shai-hulud-worm-npm-supply-chain-compromise",
"https://socket.dev/blog/shai-hulud-strikes-again-v2",
"https://www.wiz.io/blog/shai-hulud-2-0-ongoing-supply-chain-attack",
]
version = "1.0.1"
query = '''
process where event.action == "exec" and
(
process.parent.name in ("Runner.Worker", "Runner.Listener") or
descendant of [process where event.action == "start" and process.parent.name in ("Runner.Worker", "Runner.Listener")]
) and
process.env_vars : "RUNNER_TRACKING_ID*" and not process.env_vars like~ "RUNNER_TRACKING_ID=github_*"
'''
min_endpoint_version = "8.11.0"
optional_actions = []
[[actions]]
action = "kill_process"
field = "process.entity_id"
state = 0
[[actions]]
action = "kill_process"
field = "process.parent.entity_id"
state = 0
[[threat]]
framework = "MITRE ATT&CK"
[[threat.technique]]
id = "T1195"
name = "Supply Chain Compromise"
reference = "https://attack.mitre.org/techniques/T1195/"
[[threat.technique.subtechnique]]
id = "T1195.001"
name = "Compromise Software Dependencies and Development Tools"
reference = "https://attack.mitre.org/techniques/T1195/001/"
[threat.tactic]
id = "TA0001"
name = "Initial Access"
reference = "https://attack.mitre.org/tactics/TA0001/"
[[threat]]
framework = "MITRE ATT&CK"
[[threat.technique]]
id = "T1059"
name = "Command and Scripting Interpreter"
reference = "https://attack.mitre.org/techniques/T1059/"
[threat.tactic]
id = "TA0002"
name = "Execution"
reference = "https://attack.mitre.org/tactics/TA0002/"
[[threat]]
framework = "MITRE ATT&CK"
[[threat.technique]]
id = "T1562"
name = "Impair Defenses"
reference = "https://attack.mitre.org/techniques/T1562/"
[[threat.technique.subtechnique]]
id = "T1562.001"
name = "Disable or Modify Tools"
reference = "https://attack.mitre.org/techniques/T1562/001/"
[threat.tactic]
id = "TA0005"
name = "Defense Evasion"
reference = "https://attack.mitre.org/tactics/TA0005/"
[internal]
min_endpoint_version = "8.11.0"
Stages and Predicates
Stage 1: process
process where event.action == "exec" and
(
process.parent.name in ("Runner.Worker", "Runner.Listener") or
descendant of [process where event.action == "start" and process.parent.name in ("Runner.Worker", "Runner.Listener")]
) and
process.env_vars : "RUNNER_TRACKING_ID*" and not process.env_vars like~ "RUNNER_TRACKING_ID=github_*"
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
event.action | eq |
| field:"EventType" kind:eq value:"exec" |
process.env_vars | wildcard |
| field:"process.env_vars" kind:wildcard value:"RUNNER_TRACKING_ID*" |
process.parent.name | in |
| field:"parent_process_basename" kind:in |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
process.env_vars | starts_with | RUNNER_TRACKING_ID=github_ | excludes:process.env_vars field:"process.env_vars" value:"RUNNER_TRACKING_ID=github_" |
High Number of Closed Pull Requests by User
#Detects a high number of closed pull requests by a single user within a short time frame. Adversaries may close multiple pull requests to disrupt development workflows or hide malicious changes.
MITRE ATT&CK Coverage
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| GitHub | Audit log action pull_request.close: Pull request closed without merging |
Rule Body
[metadata]
creation_date = "2025/12/16"
integration = ["github"]
maturity = "production"
updated_date = "2026/04/10"
[rule]
author = ["Elastic"]
description = """
Detects a high number of closed pull requests by a single user within a short time frame. Adversaries may
close multiple pull requests to disrupt development workflows or hide malicious changes.
"""
from = "now-9m"
interval = "8m"
language = "esql"
license = "Elastic License v2"
name = "High Number of Closed Pull Requests by User"
note = """ ## Triage and analysis
> **Disclaimer**:
> This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs.
### Investigating High Number of Closed Pull Requests by User
This rule flags a single user rapidly closing many pull requests in a short window, a disruptive pattern that suppresses review history, delays releases, and masks unauthorized changes. An attacker with stolen maintainer access mass-closes pull requests across multiple repositories, then force-pushes branches and opens new pull requests that sidestep earlier review threads, making malicious edits appear routine amid churn.
### Possible investigation steps
- Determine if the actor is a bot or sanctioned maintenance by confirming account type, scheduled workflows, and change advisories from repo/org owners.
- Open a sample of the closed PRs to review comments, labels, linked issues, and whether closure coincided with branch deletions, force-pushes, or unusual commit history in the target branches.
- Correlate the closure burst with audit events for permission changes, role assignments, repository settings edits, or protection rule modifications to detect potential sabotage.
- Validate the actor’s IPs, geolocation, and user agents against baselines and check for recent PAT creations, OAuth app grants, or SSO anomalies indicating credential theft.
- Identify whether closed PRs were immediately replaced by new PRs carrying similar diffs that bypass prior review threads and required checks, and verify branch protection remained enforced.
### False positive analysis
- A maintainer or org-owned bot performs scheduled backlog hygiene, closing stale, duplicate, or superseded PRs across multiple repositories after a default branch rename or policy update, resulting in a high closure count from one account.
- During a planned migration or archival, a release manager closes PRs tied to deprecated branches and consolidates work into new targets, legitimately generating a burst of closures attributed to a single user.
### Response and remediation
- Immediately contain by removing the user from teams with Triage/Write permissions on affected repositories, revoking their personal access tokens from Tokens & keys, and tightening branch protection by disallowing force-pushes and restricting who can push to main and release branches.
- Trigger escalation to Security Incident Response if closed pull requests span more than five repositories within one hour, coincide with branch deletions or forced pushes, or originate from a new user agent/IP, and disable the account at the identity provider while contacting GitHub Support.
- Eradicate impact by reopening legitimate PRs via each closed PR URL, using Restore branch or recreating the head branch from the last known commit SHA, and reapplying required labels and reviewers.
- Recover repository state by comparing diffs of closed PRs to any newly opened PRs by the same user, reverting unauthorized commits in target branches with git revert, and re-running required status checks before merging.
- Harden controls by enforcing branch protection rules (require two approvals, restrict who can dismiss reviews, require signed commits), enabling CODEOWNERS for critical paths, and turning off Allow deletions on default and release branches.
- Prevent recurrence by disabling classic PATs and requiring short-lived fine-grained PATs, revoking unusual OAuth app grants, mandating SSO with hardware-backed MFA, and installing a GitHub App/Action that notifies on PR closures with PR URLs, repos, and branches and requires a reason-coded label per policy.
"""
references = [
"https://www.wiz.io/blog/shai-hulud-2-0-ongoing-supply-chain-attack",
"https://trigger.dev/blog/shai-hulud-postmortem",
"https://posthog.com/blog/nov-24-shai-hulud-attack-post-mortem",
]
risk_score = 47
rule_id = "098bd5cc-fd55-438f-b354-7d6cd9856a08"
severity = "medium"
tags = [
"Domain: Cloud",
"Use Case: Threat Detection",
"Tactic: Impact",
"Tactic: Exfiltration",
"Data Source: Github",
"Resources: Investigation Guide",
]
timestamp_override = "event.ingested"
type = "esql"
query = '''
from logs-github.audit-* metadata _id, _index, _version
| where
data_stream.dataset == "github.audit" and
github.category == "pull_request" and
event.type == "change" and
event.action == "pull_request.close"
| stats
Esql.document_count = COUNT(*),
Esql.github_org_values = values(github.org),
Esql.github_repo_values = values(github.repo),
Esql.github_user_agent_values = values(github.user_agent),
Esql.github_pull_request_url_values = values(github.pull_request_url),
Esql.user_name_values = values(user.name),
Esql.agent_id_values = values(agent.id),
Esql.data_stream_dataset_values = values(data_stream.dataset),
Esql.data_stream_namespace_values = values(data_stream.namespace)
by user.name
| keep Esql.*
| where
Esql.document_count >= 10
'''
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1485"
name = "Data Destruction"
reference = "https://attack.mitre.org/techniques/T1485/"
[[rule.threat.technique]]
id = "T1565"
name = "Data Manipulation"
reference = "https://attack.mitre.org/techniques/T1565/"
[[rule.threat.technique.subtechnique]]
id = "T1565.001"
name = "Stored Data Manipulation"
reference = "https://attack.mitre.org/techniques/T1565/001/"
[rule.threat.tactic]
id = "TA0040"
name = "Impact"
reference = "https://attack.mitre.org/tactics/TA0040/"
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1020"
name = "Automated Exfiltration"
reference = "https://attack.mitre.org/techniques/T1020/"
[[rule.threat.technique]]
id = "T1567"
name = "Exfiltration Over Web Service"
reference = "https://attack.mitre.org/techniques/T1567/"
[[rule.threat.technique.subtechnique]]
id = "T1567.001"
name = "Exfiltration to Code Repository"
reference = "https://attack.mitre.org/techniques/T1567/001/"
[rule.threat.tactic]
id = "TA0010"
name = "Exfiltration"
reference = "https://attack.mitre.org/tactics/TA0010/"
Stages and Predicates
Stage 1: from
from logs-github.audit-* metadata _id, _index, _version
Stage 2: where
| where
data_stream.dataset == "github.audit" and
github.category == "pull_request" and
event.type == "change" and
event.action == "pull_request.close"
Stage 3: stats
| stats
Esql.document_count = COUNT(*),
Esql.github_org_values = values(github.org),
Esql.github_repo_values = values(github.repo),
Esql.github_user_agent_values = values(github.user_agent),
Esql.github_pull_request_url_values = values(github.pull_request_url),
Esql.user_name_values = values(user.name),
Esql.agent_id_values = values(agent.id),
Esql.data_stream_dataset_values = values(data_stream.dataset),
Esql.data_stream_namespace_values = values(data_stream.namespace)
by user.name
Stage 4: keep
| keep Esql.*
Stage 5: where
| where
Esql.document_count >= 10
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Esql.document_count | ge |
| field:"Esql.document_count" kind:ge value:"10" |
data_stream.dataset | eq |
| field:"data_stream.dataset" kind:eq value:"github.audit" |
event.action | eq |
| field:"EventType" kind:eq value:"pull_request.close" |
event.type | eq |
| field:"event.type" kind:eq value:"change" |
github.category | eq |
| field:"github.category" kind:eq value:"pull_request" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Esql.* | KEEP Esql.* |
Inhibit System Recovery via Signed Binary Proxy
#Identifies the execution of Windows utilities to tamper with system recovery settings. Adversaries may delete or remove built-in operating system data and turn off services designed to aid in the recovery of a corrupted system and prevent recovery.
MITRE ATT&CK Coverage
Rule Body
[rule]
description = """
Identifies the execution of Windows utilities to tamper with system recovery settings. Adversaries may delete or remove
built-in operating system data and turn off services designed to aid in the recovery of a corrupted system and prevent
recovery.
"""
id = "740ad26d-3e67-47e1-aff1-adb47a697375"
license = "Elastic License v2"
name = "Inhibit System Recovery via Signed Binary Proxy"
os_list = ["windows"]
version = "1.0.32"
query = '''
process where event.action == "start" and
descendant of [process where event.action == "start" and
process.name:
(
"rundll32.exe",
"cscript.exe",
"wscript.exe",
"regsvr32.exe",
"regasm.exe",
"regsvcs.exe",
"installutil.exe",
"mshta.exe",
"cmstp.exe",
"msxsl.exe",
"Microsoft.Workflow.Compiler.exe",
"ieexec.exe",
"iexpress.exe"
)]
and
(
(process.pe.original_file_name : "wmic.exe" and process.command_line : "*shadowcopy*" and
process.command_line : "*delete*") or
(process.pe.original_file_name : "vssadmin.exe" and process.command_line : "*shadows*" and
process.command_line : ("*delete*", "*resize*401*")) or
(process.pe.original_file_name : "bcdedit.exe" and process.command_line : ("*bootstatuspolicy*", "*recoveryenabled*")) or
(process.pe.original_file_name : "wbadmin.exe" and process.command_line : ("*catalog*", "*systemstatebackup*") and process.command_line : "*delete*")
) and
not (process.name : "vssadmin.exe" and process.args : "Resize" and process.parent.executable : "?:\\Program Files\\Geni\\Insights\\GsAgent.exe")
'''
min_endpoint_version = "7.15.0"
[[actions]]
action = "kill_process"
field = "process.entity_id"
state = 0
[[optional_actions]]
action = "rollback"
field = "process.entity_id"
state = 0
[[threat]]
framework = "MITRE ATT&CK"
[[threat.technique]]
id = "T1059"
name = "Command and Scripting Interpreter"
reference = "https://attack.mitre.org/techniques/T1059/"
[[threat.technique.subtechnique]]
id = "T1059.005"
name = "Visual Basic"
reference = "https://attack.mitre.org/techniques/T1059/005/"
[threat.tactic]
id = "TA0002"
name = "Execution"
reference = "https://attack.mitre.org/tactics/TA0002/"
[[threat]]
framework = "MITRE ATT&CK"
[[threat.technique]]
id = "T1216"
name = "System Script Proxy Execution"
reference = "https://attack.mitre.org/techniques/T1216/"
[[threat.technique]]
id = "T1218"
name = "System Binary Proxy Execution"
reference = "https://attack.mitre.org/techniques/T1218/"
[[threat.technique.subtechnique]]
id = "T1218.003"
name = "CMSTP"
reference = "https://attack.mitre.org/techniques/T1218/003/"
[[threat.technique.subtechnique]]
id = "T1218.004"
name = "InstallUtil"
reference = "https://attack.mitre.org/techniques/T1218/004/"
[[threat.technique.subtechnique]]
id = "T1218.005"
name = "Mshta"
reference = "https://attack.mitre.org/techniques/T1218/005/"
[[threat.technique.subtechnique]]
id = "T1218.009"
name = "Regsvcs/Regasm"
reference = "https://attack.mitre.org/techniques/T1218/009/"
[[threat.technique.subtechnique]]
id = "T1218.010"
name = "Regsvr32"
reference = "https://attack.mitre.org/techniques/T1218/010/"
[[threat.technique.subtechnique]]
id = "T1218.011"
name = "Rundll32"
reference = "https://attack.mitre.org/techniques/T1218/011/"
[[threat.technique]]
id = "T1220"
name = "XSL Script Processing"
reference = "https://attack.mitre.org/techniques/T1220/"
[threat.tactic]
id = "TA0005"
name = "Defense Evasion"
reference = "https://attack.mitre.org/tactics/TA0005/"
[[threat]]
framework = "MITRE ATT&CK"
[[threat.technique]]
id = "T1490"
name = "Inhibit System Recovery"
reference = "https://attack.mitre.org/techniques/T1490/"
[threat.tactic]
id = "TA0040"
name = "Impact"
reference = "https://attack.mitre.org/tactics/TA0040/"
[internal]
min_endpoint_version = "7.15.0"
Stages and Predicates
Stage 1: process
process where event.action == "start" and
descendant of [process where event.action == "start" and
process.name:
(
"rundll32.exe",
"cscript.exe",
"wscript.exe",
"regsvr32.exe",
"regasm.exe",
"regsvcs.exe",
"installutil.exe",
"mshta.exe",
"cmstp.exe",
"msxsl.exe",
"Microsoft.Workflow.Compiler.exe",
"ieexec.exe",
"iexpress.exe"
)]
and
(
(process.pe.original_file_name : "wmic.exe" and process.command_line : "*shadowcopy*" and
process.command_line : "*delete*") or
(process.pe.original_file_name : "vssadmin.exe" and process.command_line : "*shadows*" and
process.command_line : ("*delete*", "*resize*401*")) or
(process.pe.original_file_name : "bcdedit.exe" and process.command_line : ("*bootstatuspolicy*", "*recoveryenabled*")) or
(process.pe.original_file_name : "wbadmin.exe" and process.command_line : ("*catalog*", "*systemstatebackup*") and process.command_line : "*delete*")
) and
not (process.name : "vssadmin.exe" and process.args : "Resize" and process.parent.executable : "?:\\Program Files\\Geni\\Insights\\GsAgent.exe")
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
event.action | eq |
| field:"EventType" kind:eq value:"start" |
process.command_line | wildcard |
| field:"CommandLine" kind:wildcard |
process.pe.original_file_name | wildcard |
| field:"OriginalFileName" kind:wildcard |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
process.args | eq | Resize | excludes:process.args field:"process.args" value:"Resize" |
process.name | eq | vssadmin.exe | excludes:process.name field:"process.name" value:"vssadmin.exe" |
process.parent.executable | eq | ?:\Program Files\Geni\Insights\GsAgent.exe | excludes:process.parent.executable field:"process.parent.executable" value:"?:\Program Files\Geni\Insights\GsAgent.exe" |
Potential Credentials Phishing via Osascript
#Identifies the use of osascript to execute scripts via standard input that may prompt a user with a rogue dialog for credentials.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Credential Access |
Telemetry Coverage
Rule Body
[rule]
description = """
Identifies the use of osascript to execute scripts via standard input that may prompt a user with a rogue dialog for
credentials.
"""
id = "318d3d9d-ba60-40e3-bc8c-3d3304209a3c"
license = "Elastic License v2"
name = "Potential Credentials Phishing via Osascript"
os_list = ["macos"]
reference = [
"https://github.com/EmpireProject/EmPyre/blob/master/lib/modules/collection/osx/prompt.py",
"https://ss64.com/osx/osascript.html",
"https://www.elastic.co/security-labs/beyond-the-wail",
]
version = "1.0.37"
query = '''
process where event.action == "exec" and
process.name == "osascript" and process.args == "-e" and process.command_line like~ ("*osascript*display*dialog*password*",
"*osascript*display*dialog*passphrase*",
"*osascript*display*dialog*authenticate*",
"*pass*display*dialog*") and
not (process.parent.executable == "/usr/bin/sudo" and process.command_line like~ "*Encryption Key Escrow*") and
not (process.command_line like~ "*-e with timeout of 3600 seconds*" and user.id == 0 and process.parent.executable == "/bin/bash") and
not process.parent.command_line like "sudo*" and
not process.Ext.effective_parent.executable like~
("/usr/local/jamf/*",
"/Library/Intune/Microsoft Intune Agent.app/Contents/MacOS/IntuneMdmDaemon",
"/Library/Application Support/Mosyle/MosyleMDM.app/Contents/MacOS/MosyleMDM",
"/Applications/NinjaRMMAgent/programfiles/ninjarmm-macagent",
"/Applications/Karabiner-Elements.app/Contents/MacOS/Karabiner-Elements",
"/Library/Application Support/JAMF/Jamf.app/Contents/MacOS/JamfDaemon.app/Contents/MacOS/JamfDaemon",
"/Library/Application Support/JAMF/Jamf.app/Contents/MacOS/JamfManagementService.app/Contents/MacOS/JamfManagementService")
'''
min_endpoint_version = "8.8.0"
optional_actions = []
[[actions]]
action = "kill_process"
field = "process.entity_id"
state = 0
[[actions]]
action = "kill_process"
field = "process.parent.entity_id"
state = 0
[[threat]]
framework = "MITRE ATT&CK"
[[threat.technique]]
id = "T1056"
name = "Input Capture"
reference = "https://attack.mitre.org/techniques/T1056/"
[[threat.technique.subtechnique]]
id = "T1056.002"
name = "GUI Input Capture"
reference = "https://attack.mitre.org/techniques/T1056/002/"
[threat.tactic]
id = "TA0006"
name = "Credential Access"
reference = "https://attack.mitre.org/tactics/TA0006/"
[internal]
min_endpoint_version = "8.8.0"
Stages and Predicates
Stage 1: process
process where event.action == "exec" and
process.name == "osascript" and process.args == "-e" and process.command_line like~ ("*osascript*display*dialog*password*",
"*osascript*display*dialog*passphrase*",
"*osascript*display*dialog*authenticate*",
"*pass*display*dialog*") and
not (process.parent.executable == "/usr/bin/sudo" and process.command_line like~ "*Encryption Key Escrow*") and
not (process.command_line like~ "*-e with timeout of 3600 seconds*" and user.id == 0 and process.parent.executable == "/bin/bash") and
not process.parent.command_line like "sudo*" and
not process.Ext.effective_parent.executable like~
("/usr/local/jamf/*",
"/Library/Intune/Microsoft Intune Agent.app/Contents/MacOS/IntuneMdmDaemon",
"/Library/Application Support/Mosyle/MosyleMDM.app/Contents/MacOS/MosyleMDM",
"/Applications/NinjaRMMAgent/programfiles/ninjarmm-macagent",
"/Applications/Karabiner-Elements.app/Contents/MacOS/Karabiner-Elements",
"/Library/Application Support/JAMF/Jamf.app/Contents/MacOS/JamfDaemon.app/Contents/MacOS/JamfDaemon",
"/Library/Application Support/JAMF/Jamf.app/Contents/MacOS/JamfManagementService.app/Contents/MacOS/JamfManagementService")
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
event.action | eq |
| field:"EventType" kind:eq value:"exec" |
process.args | eq |
| field:"process.args" kind:eq value:"-e" |
process.command_line | wildcard |
| field:"CommandLine" kind:wildcard |
process.name | eq |
| field:"process_basename" kind:eq value:"osascript" |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
process.command_line | match | -e with timeout of 3600 seconds | excludes:process.command_line field:"process.command_line" value:"-e with timeout of 3600 seconds" |
process.parent.executable | eq | /bin/bash | excludes:process.parent.executable field:"process.parent.executable" value:"/bin/bash" |
user.id | eq | 0 | excludes:user.id field:"user.id" value:"0" |
process.command_line | match | Encryption Key Escrow | excludes:process.command_line field:"process.command_line" value:"Encryption Key Escrow" |
process.parent.executable | eq | /usr/bin/sudo | excludes:process.parent.executable field:"process.parent.executable" value:"/usr/bin/sudo" |
process.Ext.effective_parent.executable | wildcard | /usr/local/jamf/*, /Library/Intune/Microsoft Intune Agent.app/Contents/MacOS/IntuneMdmDaemon, /Library/Application Support/Mosyle/MosyleMDM.app/Contents/MacOS/MosyleMDM, /Applications/NinjaRMMAgent/programfiles/ninjarmm-macagent, /Applications/Karabiner-Elements.app/Contents/MacOS/Karabiner-Elements, /Library/Application Support/JAMF/Jamf.app/Contents/MacOS/JamfDaemon.app/Contents/MacOS/JamfDaemon, /Library/Application Support/JAMF/Jamf.app/Contents/MacOS/JamfManagementService.app/Contents/MacOS/JamfManagementService | excludes:process.Ext.effective_parent.executable |
process.parent.command_line | starts_with | sudo | excludes:process.parent.command_line field:"process.parent.command_line" value:"sudo" |
Potential Execution via VS Code Tasks
#Identifies creation or modification of a .vscode/tasks.json file followed by opening the current project in a short time. Threat actors distribute malicious repositories that embed autorun task configurations to phish for credentials or execute payloads when a developer opens the project in Visual Studio Code.
MITRE ATT&CK Coverage
Telemetry Coverage
Rule Body
[rule]
description = """
Identifies creation or modification of a .vscode/tasks.json file followed by opening the current project in a short
time. Threat actors distribute malicious repositories that embed autorun task configurations to phish for credentials or
execute payloads when a developer opens the project in Visual Studio Code.
"""
id = "ad058e28-8504-4bfe-9b91-22d24d903ede"
license = "Elastic License v2"
name = "Potential Execution via VS Code Tasks"
os_list = ["macos"]
reference = [
"https://www.jamf.com/blog/threat-actors-expand-abuse-of-visual-studio-code/",
"https://about.gitlab.com/blog/how-to-detect-and-prevent-contagious-interview-ide-attacks/",
"https://kl4r10n.tech/blog/dprk-new-malware",
]
version = "1.0.2"
query = '''
sequence with maxspan=30s
[file where event.action in ("creation", "modification") and file.name == "tasks.json" and
process.name in (
// Windows browsers
"chrome.exe", "msedge.exe", "firefox.exe", "brave.exe", "opera.exe", "vivaldi.exe",
// macOS browsers (bundle exec names)
"Google Chrome", "Google Chrome Helper", "Chromium", "Chromium Helper",
"firefox", "Firefox", "Safari", "SafariTP",
"Brave Browser", "Opera", "Vivaldi", "Arc",
// Linux browsers
"google-chrome", "google-chrome-stable", "chromium", "chromium-browser",
"firefox", "firefox-esr", "brave-browser", "opera", "vivaldi-bin",
// Windows archivers
"7z.exe", "7zFM.exe", "7zG.exe", "winrar.exe", "tar", "unzip.exe", "winscp.exe",
// macOS/Linux archivers and fetch tools
"unzip", "tar", "bsdtar", "curl", "wget",
// Version control / package managers
"git", "git.exe", "gh", "gh.exe", "npm", "npm.exe", "node", "node.exe",
"pip", "pip3", "python", "python3", "python.exe",
// Shells / script runners
"powershell.exe", "pwsh.exe", "cmd.exe", "wscript.exe", "cscript.exe",
"bash", "zsh", "sh", "fish", "dash"
) and
file.path : ("?:\\*\\.vscode\\tasks.json", "/*/.vscode/tasks.json")]
[process where event.type == "start" and event.action in ("start", "exec") and
process.name in ("code", "cursor", "Code.exe", "Cursor.exe", "codium", "VSCodium.exe", "windsurf", "Windsurf.exe") and
process.args == "."]
'''
min_endpoint_version = "8.16.0"
optional_actions = []
[[actions]]
action = "kill_process"
field = "process.entity_id"
state = 0
[[actions]]
action = "kill_process"
field = "process.entity_id"
state = 1
[[actions]]
action = "kill_process"
field = "process.parent.entity_id"
state = 0
[[actions]]
action = "kill_process"
field = "process.parent.entity_id"
state = 1
[[threat]]
framework = "MITRE ATT&CK"
[[threat.technique]]
id = "T1195"
name = "Supply Chain Compromise"
reference = "https://attack.mitre.org/techniques/T1195/"
[[threat.technique.subtechnique]]
id = "T1195.001"
name = "Compromise Software Dependencies and Development Tools"
reference = "https://attack.mitre.org/techniques/T1195/001/"
[[threat.technique]]
id = "T1566"
name = "Phishing"
reference = "https://attack.mitre.org/techniques/T1566/"
[[threat.technique.subtechnique]]
id = "T1566.002"
name = "Spearphishing Link"
reference = "https://attack.mitre.org/techniques/T1566/002/"
[threat.tactic]
id = "TA0001"
name = "Initial Access"
reference = "https://attack.mitre.org/tactics/TA0001/"
[internal]
min_endpoint_version = "8.16.0"
Stages and Predicates
Stage 1: file
[file where event.action in ("creation", "modification") and file.name == "tasks.json" and
process.name in (
"chrome.exe", "msedge.exe", "firefox.exe", "brave.exe", "opera.exe", "vivaldi.exe",
"Google Chrome", "Google Chrome Helper", "Chromium", "Chromium Helper",
"firefox", "Firefox", "Safari", "SafariTP",
"Brave Browser", "Opera", "Vivaldi", "Arc",
"google-chrome", "google-chrome-stable", "chromium", "chromium-browser",
"firefox", "firefox-esr", "brave-browser", "opera", "vivaldi-bin",
"7z.exe", "7zFM.exe", "7zG.exe", "winrar.exe", "tar", "unzip.exe", "winscp.exe",
"unzip", "tar", "bsdtar", "curl", "wget",
"git", "git.exe", "gh", "gh.exe", "npm", "npm.exe", "node", "node.exe",
"pip", "pip3", "python", "python3", "python.exe",
"powershell.exe", "pwsh.exe", "cmd.exe", "wscript.exe", "cscript.exe",
"bash", "zsh", "sh", "fish", "dash"
) and
file.path : ("?:\\*\\.vscode\\tasks.json", "/*/.vscode/tasks.json")]
Stage 2: process
[process where event.type == "start" and event.action in ("start", "exec") and
process.name in ("code", "cursor", "Code.exe", "Cursor.exe", "codium", "VSCodium.exe", "windsurf", "Windsurf.exe") and
process.args == "."]
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
event.action | in |
| field:"EventType" kind:in |
event.type | eq |
| field:"event.type" kind:eq value:"start" |
file.name | eq |
| field:"file.name" kind:eq value:"tasks.json" |
file.path | wildcard |
| field:"TargetFilename" kind:wildcard |
process.args | eq |
| field:"process.args" kind:eq value:"." |
process.name | in |
| field:"process_basename" kind:in |
Potential File Transfer via Certreq
#Identifies Certreq making an HTTP Post request. Adversaries could abuse Certreq to download files or upload data to a remote URL.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Stealth | |
| Command & Control | |
| Exfiltration |
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
[metadata]
creation_date = "2023/01/13"
integration = ["endpoint", "windows", "system", "m365_defender", "sentinel_one_cloud_funnel", "crowdstrike"]
maturity = "production"
updated_date = "2026/05/04"
[transform]
[[transform.osquery]]
label = "Osquery - Retrieve DNS Cache"
query = "SELECT * FROM dns_cache"
[[transform.osquery]]
label = "Osquery - Retrieve All Services"
query = "SELECT description, display_name, name, path, pid, service_type, start_type, status, user_account FROM services"
[[transform.osquery]]
label = "Osquery - Retrieve Services Running on User Accounts"
query = """
SELECT description, display_name, name, path, pid, service_type, start_type, status, user_account FROM services WHERE
NOT (user_account LIKE '%LocalSystem' OR user_account LIKE '%LocalService' OR user_account LIKE '%NetworkService' OR
user_account == null)
"""
[[transform.osquery]]
label = "Osquery - Retrieve Service Unsigned Executables with Virustotal Link"
query = """
SELECT concat('https://www.virustotal.com/gui/file/', sha1) AS VtLink, name, description, start_type, status, pid,
services.path FROM services JOIN authenticode ON services.path = authenticode.path OR services.module_path =
authenticode.path JOIN hash ON services.path = hash.path WHERE authenticode.result != 'trusted'
"""
[rule]
author = ["Elastic"]
description = """
Identifies Certreq making an HTTP Post request. Adversaries could abuse Certreq to download files or upload data to a
remote URL.
"""
from = "now-9m"
index = [
"endgame-*",
"logs-crowdstrike.fdr*",
"logs-endpoint.events.process-*",
"logs-m365_defender.event-*",
"logs-sentinel_one_cloud_funnel.*",
"logs-system.security*",
"logs-windows.forwarded*",
"logs-windows.sysmon_operational-*",
"winlogbeat-*",
]
language = "eql"
license = "Elastic License v2"
name = "Potential File Transfer via Certreq"
note = """## Triage and analysis
### Investigating Potential File Transfer via Certreq
Certreq is a command-line utility in Windows operating systems that allows users to request and manage certificates from certificate authorities. It is primarily used for generating certificate signing requests (CSRs) and installing certificates. However, adversaries may abuse Certreq's functionality to download files or upload data to a remote URL by making an HTTP POST request.
This rule identifies the potential abuse of Certreq to download files or upload data to a remote URL.
> **Note**:
> This investigation guide uses the [Osquery Markdown Plugin](https://www.elastic.co/guide/en/security/current/invest-guide-run-osquery.html) introduced in Elastic Stack version 8.5.0. Older Elastic Stack versions will display unrendered Markdown in this guide.
#### Possible investigation steps
- Investigate the process execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures.
- Identify the user account that performed the action and whether it should perform this kind of action.
- Contact the account owner and confirm whether they are aware of this activity.
- Investigate other alerts associated with the user/host during the past 48 hours.
- Assess whether this behavior is prevalent in the environment by looking for similar occurrences across hosts.
- Examine the details of the dropped file, and whether it was executed.
- Check the reputation of the domain or IP address used to host the downloaded file or if the user downloaded the file from an internal system.
- Examine the host for derived artifacts that indicate suspicious activities:
- Analyze the file using a private sandboxed analysis system.
- Observe and collect information about the following activities in both the sandbox and the alert subject host:
- Attempts to contact external domains and addresses.
- Use the Elastic Defend network events to determine domains and addresses contacted by the subject process by filtering by the process's `process.entity_id`.
- Examine the DNS cache for suspicious or anomalous entries.
- $osquery_0
- Use the Elastic Defend registry events to examine registry keys accessed, modified, or created by the related processes in the process tree.
- Examine the host services for suspicious or anomalous entries.
- $osquery_1
- $osquery_2
- $osquery_3
- Retrieve the files' SHA-256 hash values using the PowerShell `Get-FileHash` cmdlet and search for the existence and reputation of the hashes in resources like VirusTotal, Hybrid-Analysis, CISCO Talos, Any.run, etc.
### False positive analysis
- This activity is unusual but can be done by administrators. Benign true positives (B-TPs) can be added as exceptions if necessary.
### Response and remediation
- Initiate the incident response process based on the outcome of the triage.
- Isolate the involved host to prevent further post-compromise behavior.
- If the triage identified malware, search the environment for additional compromised hosts.
- Implement temporary network rules, procedures, and segmentation to contain the malware.
- Stop suspicious processes.
- Immediately block the identified indicators of compromise (IoCs).
- Inspect the affected systems for additional malware backdoors like reverse shells, reverse proxies, or droppers that attackers could use to reinfect the system.
- Remove and block malicious artifacts identified during triage.
- Investigate credential exposure on systems compromised or used by the attacker to ensure all compromised accounts are identified. Reset passwords for these accounts and other potentially compromised credentials, such as email, business systems, and web services.
- Run a full antimalware scan. This may reveal additional artifacts left in the system, persistence mechanisms, and malware components.
- Determine the initial vector abused by the attacker and take action to prevent reinfection through the same vector.
- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).
"""
setup = """## Setup
This rule is designed for data generated by [Elastic Defend](https://www.elastic.co/security/endpoint-security), which provides native endpoint detection and response, along with event enrichments designed to work with our detection rules.
Setup instructions: https://ela.st/install-elastic-defend
### Additional data sources
This rule also supports the following third-party data sources. For setup instructions, refer to the links below:
- [CrowdStrike](https://ela.st/crowdstrike-integration)
- [Microsoft Defender XDR](https://ela.st/m365-defender)
- [SentinelOne Cloud Funnel](https://ela.st/sentinel-one-cloud-funnel)
- [Sysmon Event ID 1 - Process Creation](https://ela.st/sysmon-event-1-setup)
- [Windows Process Creation Logs](https://ela.st/audit-process-creation)
"""
references = ["https://lolbas-project.github.io/lolbas/Binaries/Certreq/"]
risk_score = 47
rule_id = "79f0a1f7-ed6b-471c-8eb1-23abd6470b1c"
severity = "medium"
tags = [
"Domain: Endpoint",
"OS: Windows",
"Use Case: Threat Detection",
"Tactic: Defense Evasion",
"Tactic: Command and Control",
"Tactic: Exfiltration",
"Data Source: Elastic Endgame",
"Data Source: Elastic Defend",
"Data Source: Windows Security Event Logs",
"Data Source: Microsoft Defender XDR",
"Data Source: Sysmon",
"Data Source: SentinelOne",
"Data Source: Crowdstrike",
"Resources: Investigation Guide",
]
timestamp_override = "event.ingested"
type = "eql"
query = '''
process where host.os.type == "windows" and event.type == "start" and
(process.name : "CertReq.exe" or ?process.pe.original_file_name == "CertReq.exe") and process.args : "-Post"
'''
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1071"
name = "Application Layer Protocol"
reference = "https://attack.mitre.org/techniques/T1071/"
[[rule.threat.technique.subtechnique]]
id = "T1071.001"
name = "Web Protocols"
reference = "https://attack.mitre.org/techniques/T1071/001/"
[[rule.threat.technique]]
id = "T1105"
name = "Ingress Tool Transfer"
reference = "https://attack.mitre.org/techniques/T1105/"
[rule.threat.tactic]
id = "TA0011"
name = "Command and Control"
reference = "https://attack.mitre.org/tactics/TA0011/"
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1218"
name = "System Binary Proxy Execution"
reference = "https://attack.mitre.org/techniques/T1218/"
[rule.threat.tactic]
id = "TA0005"
name = "Defense Evasion"
reference = "https://attack.mitre.org/tactics/TA0005/"
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1567"
name = "Exfiltration Over Web Service"
reference = "https://attack.mitre.org/techniques/T1567/"
[rule.threat.tactic]
id = "TA0010"
name = "Exfiltration"
reference = "https://attack.mitre.org/tactics/TA0010/"
Stages and Predicates
Stage 1: process
process where host.os.type == "windows" and event.type == "start" and
(process.name : "CertReq.exe" or ?process.pe.original_file_name == "CertReq.exe") and process.args : "-Post"
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
event.type | eq |
| field:"event.type" kind:eq value:"start" |
process.args | wildcard |
| field:"process.args" kind:wildcard value:"-Post" |
process.name | wildcard |
| field:"process_basename" kind:wildcard value:"CertReq.exe" |
process.pe.original_file_name | eq |
| field:"OriginalFileName" kind:eq value:"CertReq.exe" |
Potential Remote Code Execution via Database Server
#This rule detects potential remote code execution attempts via commonly used database server applications, by monitoring for unusual child processes and command line arguments.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access | |
| Execution | |
| Persistence | |
| Lateral Movement | |
| Command & Control |
Rule Body
[rule]
description = """
This rule detects potential remote code execution attempts via commonly used database server applications, by monitoring
for unusual child processes and command line arguments.
"""
id = "057bd963-2dce-4951-87ce-5923803158ff"
license = "Elastic License v2"
name = "Potential Remote Code Execution via Database Server"
os_list = ["linux"]
version = "1.0.11"
query = '''
process where event.type == "start" and event.action == "exec" and process.parent.interactive == false and (
process.parent.name in (
"redis-server", "mongod", "mysqld", "oracle", "tnslsnr", "postgres", "mariadbd", "sqlservr",
"beam.smp", "db2sysc", "clickhouse-server"
) or
(process.parent.name == "redis-check-rdb" and process.parent.command_line like "*redis-server*")
) and
not (
(process.parent.name == "oracle" and process.args like "/bin/grep -q kubepods /proc/self/cgroup*") or
(process.parent.name == "beam.smp" and process.name == "erl_child_setup") or
(process.parent.name == "erl_child_setup" and process.command_line like ("*rabbitmq-env.conf*echo*VARS*set", "inet_gethost 4")) or
(process.name == "epmd" and process.command_line == "epmd -daemon")
) and
(
process.name in (
"scp", "gzip", "bzip2", "xz", "tar", "getcap", "capsh", "nohup", "setsid", "timeout", "disown",
"mkfifo", "printenv", "env", "chpasswd"
) or
process.name like ".*" or
(
process.name in ("whoami", "id", "hostname", "uname", "ps", "netstat", "ss", "ip", "ifconfig") and
process.interactive == true and process.parent.interactive == false
) or
process.executable like ("/dev/shm/*", "/tmp/*", "/var/tmp/*", "/root/*", "./*") or
(
process.executable like ("/bin/python*", "/usr/bin/python*", "/usr/local/bin/python*") and (
process.args == "-c" or
(
process.args_count <= 2 and
process.args like ("/tmp/*", "/var/tmp/*", "/dev/shm/*", "/var/www/*", "/root/*", "/home/*/*", "./*.py") and
process.args like "*.py*"
)
) and
not process.args in ("--version", "app.py")
) or
(
process.executable like (
"/bin/perl*", "/usr/bin/perl*", "/usr/local/bin/perl*",
"/bin/ruby*", "/usr/bin/ruby*", "/usr/local/bin/ruby*",
"/bin/lua*", "/usr/bin/lua*", "/usr/local/bin/lua*",
"/bin/node", "/usr/bin/node", "/usr/local/bin/node"
) and
(process.args like "-e*" or process.args_count <= 2)
) or
(
process.executable like ("/bin/php*", "/usr/bin/php*", "/usr/local/bin/php*") and
(process.args like "-r*" or process.args_count <= 2) and
not (
process.args like "var_export*" or
process.command_line in ("php -r echo get_current_user().PHP_EOL;", "php -r echo date('T');")
)
) or
(
process.name in ("nc", "ncat", "netcat", "netcat.openbsd", "netcat.traditional", "nc.openbsd", "nc.traditional") and (
process.command_line regex ".*[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}.*" or
process.command_line like "*http*"
) and
not process.args in ("localhost", "127.0.0.1", "-z", "-zv")
) or
(
process.name == "socat" and
process.command_line like~ ("*exec*", "*tty*", "*fork*", "*file*", "*open*") and
process.command_line like~ ("*tcp*", "*udp*", "*openssl*")
) or
(
process.name == "openssl" and (
process.command_line like ("*s_server*", "*s_client*") or
(process.args == "enc" and process.args in ("-d", "-base64", "-a", "-A"))
)
) or
(
process.name in ("curl", "wget") and process.args like~ ("-o", "--output*", "-o-") and (
process.command_line regex ".*[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}.*" or
process.command_line like "*http*"
) and
process.command_line like ("* /tmp/*", "* /var/tmp/*", "* /dev/shm/*", "* /var/www/*", "* ~/*", "* /home/*", "* /run/*", "* /var/run/*")
) or
(
process.name in ("base64", "basez", "base64plain", "base64url", "base64mime", "base64pem", "basenc", "base32", "base16") and
process.args like~ "-*d*"
) or
(
process.name == "xxd" and process.args like~ ("-*r*", "-*p*")
) or
(process.name == "sudo" and process.args == "-l") or
(
process.executable like ("/bin/chmod", "/usr/bin/chmod", "/usr/local/bin/chmod") and
process.args like ("+x", "a+x", "0777", "755", "777", "+s", "u+s", "g+s")
) or
(
process.executable like ("/bin/cat", "/usr/bin/cat", "/usr/local/bin/cat") and
process.args like (
"/etc/passwd", "/etc/shadow", "/etc/hostname", "/etc/hosts", "*ssh*", "/proc/self/environ",
"*.env*", "*../../../*", "*/secrets/kubernetes.io/serviceaccount/*", "*/.docker/config.json*",
"*/.npmrc*", "*.aws/credentials*", "*/.aws/config*"
)
) or
(
process.name in ("bash", "dash", "sh", "tcsh", "csh", "zsh", "ksh", "fish", "busybox") and
process.args in ("-c", "-cl", "-lc") and (
process.command_line like (
/* Suspicious Paths */
"* /tmp/* ", "* /var/tmp/* ", "* /dev/shm/*", "* /var/www/*", "* /run/*", "* /var/run/*",
/* Interpreter Execution */
"*python* -c*", "*php* -r*", "*perl* -e*", "*ruby* -e*", "*lua* -e*", "*node * -e *",
/* Encoding, Decoding & Piping */
"*|sh", "*| sh *", "*| sh ", "*|bash*", "*| bash*", "*|zsh*", "*| zsh*", "*|dash*", "*| dash*",
"*|python*", "*| python*", "*|php*", "*| php*", "*|perl*", "*| perl*", "*|ruby*", "*| ruby*",
"*|node*", "*| node*", "*|lua*", "*| lua*", "*|busybox*", "*| busybox*", "*|*base64 -d*", "*|*base64 --decode*",
"*|*base64 --decode*", "*|*openssl base64 -d*", "*xxd *", "*| openssl*enc * -d *", "*b64decode -r*",
/* Reverse Shells */
"*netcat *", "* nc *", "*ncat *", "*/dev/tcp*", "*/dev/udp/*", "*socat *", "*openssl*s_client *", "*stty*raw*-echo*",
/* File Access */
"*>*/etc/cron*", "*/etc/ssh*", "*/home/*/.ssh/*", "*/root/.ssh*", "*~/.ssh/*", "*/etc/shadow*", "*/etc/passwd*", "*chpasswd*",
/* Helpers */
"*nohup*", "*setsid *", "*timeout *sh -c *", "*disown*", "*env *sh *-c*",
/* Miscellaneous */
"*chattr *", "*busybox *", "*#!*", "*chmod +x *",
/* Decompression */
"*gzip -*d *", "*bzip2 -*d *", "*xz -*d *", "*tar -*x*",
/* Path Traversal */
"*../../../*etc/*", "*/.../*", "*../../../*home/*/*", "*../../../*root/*"
) or
(
process.command_line like ("*wget *", "*curl *") and
(
process.command_line regex ".*[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}(:[0-9]{1,5})?/.*" or
process.command_line like ("*http*", "*ftp*")
) and
(
(
process.command_line regex~ """.*curl.* \-[a-zA-Z]*[oO]( .+|\-.*)?""" or
process.command_line like~ ("*curl* --output*", "*curl* --remote-name*")
) or
(
(
process.command_line regex~ """.*wget.* \-[a-zA-Z]*O.*""" or
process.command_line like~ "*wget* --output-document*"
) and
not process.command_line like """*--output-document "-"*"""
) or
process.command_line like ("*|*sh*", "*|*python*", "*|*php*", "*|*perl*", "*|*ruby*", "*|*node*", "*|*lua*", "*|*busybox*") or
(
process.command_line like ("*curl *>> /*", "*curl *>>/*", "*curl *> /*", "*curl *>/*", "*wget *>> /*", "*wget *>>/*", "*wget *> /*", "*wget *>/*") and
not process.command_line like ("*> /dev/null*", "*>/dev/null*", "*curl*/etc/cobra/*/uploads/whatsapp/*")
)
) and
not process.command_line like ("*-O /dev/null*", "*-o /dev/null*")
)
)
)
) and
not (
process.executable like ("/tmp/newroot/*", "./runc") or
process.command_line == "sh -c locale -a" or
process.args == "/usr/bin/env" and process.args in ("check_postgres.pl", "/usr/lib/pscheduler/commands/validate-configurables") or
(
process.parent.executable == "/etc/init.d/redis-server" and
process.command_line in ("chmod 755 /var/run/redis", "touch /var/run/redis/redis-server.pid")
) or
(
process.parent.name == "postgres" and
process.command_line in (
"ps -p 1", "python2 -c pass", "timeout 5 cat /proc/net/tcp /proc/net/tcp6", "runc init", "env hostname -s",
"find . -maxdepth 1 -mindepth 1 -type d", "netstat -an"
)
) or
(
process.parent.name in ("postgres", "oracle", "tnslsnr") and
process.command_line like (
"echo nagios", "gzip -c", "/usr/bin/python3 /root/bin/yaml2json.py", "sh -c /*/scripts/check/libexec/check_df*",
"timeout --signal=3 3 telnet*", "sh -c scp*pg_wal/RECOVERYHISTORY*", "sh -c scp*pg_wal/RECOVERYXLOG*",
"env LC_ALL=C /bin/bash -c [ -f /sbin/ifconfig ] && echo 1 || echo 0"
)
) or
(
process.parent.name == "tnslsnr" and (
process.command_line like (
"/usr/bin/python3 /root/bin/yaml2json.py", "/bin/echo Filesystem 1024-blocks*", "timeout 60 ls", "timeout 10 lsblk -lbSo SIZE,TYPE"
) or
process.name in ("printenv", "env", "find", "gzip")
)
) or
(
process.parent.name == "postgres" and (
process.args like "scp*pgsql*" or
(process.name == "scp" and process.command_line like "*pgsql*") or
process.name == "uname"
)
) or
(
process.parent.name == "mysqld" and
process.command_line in ("touch /var/log/mysqld.log", "touch /var/lock/subsys/mysql")
)
)
'''
min_endpoint_version = "8.3.0"
optional_actions = []
[[actions]]
action = "kill_process"
field = "process.entity_id"
state = 0
[[threat]]
framework = "MITRE ATT&CK"
[[threat.technique]]
id = "T1190"
name = "Exploit Public-Facing Application"
reference = "https://attack.mitre.org/techniques/T1190/"
[threat.tactic]
id = "TA0001"
name = "Initial Access"
reference = "https://attack.mitre.org/tactics/TA0001/"
[[threat]]
framework = "MITRE ATT&CK"
[[threat.technique]]
id = "T1059"
name = "Command and Scripting Interpreter"
reference = "https://attack.mitre.org/techniques/T1059/"
[[threat.technique.subtechnique]]
id = "T1059.004"
name = "Unix Shell"
reference = "https://attack.mitre.org/techniques/T1059/004/"
[threat.tactic]
id = "TA0002"
name = "Execution"
reference = "https://attack.mitre.org/tactics/TA0002/"
[[threat]]
framework = "MITRE ATT&CK"
[[threat.technique]]
id = "T1505"
name = "Server Software Component"
reference = "https://attack.mitre.org/techniques/T1505/"
[[threat.technique.subtechnique]]
id = "T1505.001"
name = "SQL Stored Procedures"
reference = "https://attack.mitre.org/techniques/T1505/001/"
[[threat.technique]]
id = "T1554"
name = "Compromise Host Software Binary"
reference = "https://attack.mitre.org/techniques/T1554/"
[threat.tactic]
id = "TA0003"
name = "Persistence"
reference = "https://attack.mitre.org/tactics/TA0003/"
[[threat]]
framework = "MITRE ATT&CK"
[[threat.technique]]
id = "T1210"
name = "Exploitation of Remote Services"
reference = "https://attack.mitre.org/techniques/T1210/"
[threat.tactic]
id = "TA0008"
name = "Lateral Movement"
reference = "https://attack.mitre.org/tactics/TA0008/"
[[threat]]
framework = "MITRE ATT&CK"
[[threat.technique]]
id = "T1071"
name = "Application Layer Protocol"
reference = "https://attack.mitre.org/techniques/T1071/"
[threat.tactic]
id = "TA0011"
name = "Command and Control"
reference = "https://attack.mitre.org/tactics/TA0011/"
[internal]
min_endpoint_version = "8.3.0"
Stages and Predicates
Stage 1: process
process where event.type == "start" and event.action == "exec" and process.parent.interactive == false and (
process.parent.name in (
"redis-server", "mongod", "mysqld", "oracle", "tnslsnr", "postgres", "mariadbd", "sqlservr",
"beam.smp", "db2sysc", "clickhouse-server"
) or
(process.parent.name == "redis-check-rdb" and process.parent.command_line like "*redis-server*")
) and
not (
(process.parent.name == "oracle" and process.args like "/bin/grep -q kubepods /proc/self/cgroup*") or
(process.parent.name == "beam.smp" and process.name == "erl_child_setup") or
(process.parent.name == "erl_child_setup" and process.command_line like ("*rabbitmq-env.conf*echo*VARS*set", "inet_gethost 4")) or
(process.name == "epmd" and process.command_line == "epmd -daemon")
) and
(
process.name in (
"scp", "gzip", "bzip2", "xz", "tar", "getcap", "capsh", "nohup", "setsid", "timeout", "disown",
"mkfifo", "printenv", "env", "chpasswd"
) or
process.name like ".*" or
(
process.name in ("whoami", "id", "hostname", "uname", "ps", "netstat", "ss", "ip", "ifconfig") and
process.interactive == true and process.parent.interactive == false
) or
process.executable like ("/dev/shm/*", "/tmp/*", "/var/tmp/*", "/root/*", "./*") or
(
process.executable like ("/bin/python*", "/usr/bin/python*", "/usr/local/bin/python*") and (
process.args == "-c" or
(
process.args_count <= 2 and
process.args like ("/tmp/*", "/var/tmp/*", "/dev/shm/*", "/var/www/*", "/root/*", "/home/*/*", "./*.py") and
process.args like "*.py*"
)
) and
not process.args in ("--version", "app.py")
) or
(
process.executable like (
"/bin/perl*", "/usr/bin/perl*", "/usr/local/bin/perl*",
"/bin/ruby*", "/usr/bin/ruby*", "/usr/local/bin/ruby*",
"/bin/lua*", "/usr/bin/lua*", "/usr/local/bin/lua*",
"/bin/node", "/usr/bin/node", "/usr/local/bin/node"
) and
(process.args like "-e*" or process.args_count <= 2)
) or
(
process.executable like ("/bin/php*", "/usr/bin/php*", "/usr/local/bin/php*") and
(process.args like "-r*" or process.args_count <= 2) and
not (
process.args like "var_export*" or
process.command_line in ("php -r echo get_current_user().PHP_EOL;", "php -r echo date('T');")
)
) or
(
process.name in ("nc", "ncat", "netcat", "netcat.openbsd", "netcat.traditional", "nc.openbsd", "nc.traditional") and (
process.command_line regex ".*[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}.*" or
process.command_line like "*http*"
) and
not process.args in ("localhost", "127.0.0.1", "-z", "-zv")
) or
(
process.name == "socat" and
process.command_line like~ ("*exec*", "*tty*", "*fork*", "*file*", "*open*") and
process.command_line like~ ("*tcp*", "*udp*", "*openssl*")
) or
(
process.name == "openssl" and (
process.command_line like ("*s_server*", "*s_client*") or
(process.args == "enc" and process.args in ("-d", "-base64", "-a", "-A"))
)
) or
(
process.name in ("curl", "wget") and process.args like~ ("-o", "--output*", "-o-") and (
process.command_line regex ".*[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}.*" or
process.command_line like "*http*"
) and
process.command_line like ("* /tmp/*", "* /var/tmp/*", "* /dev/shm/*", "* /var/www/*", "* ~/*", "* /home/*", "* /run/*", "* /var/run/*")
) or
(
process.name in ("base64", "basez", "base64plain", "base64url", "base64mime", "base64pem", "basenc", "base32", "base16") and
process.args like~ "-*d*"
) or
(
process.name == "xxd" and process.args like~ ("-*r*", "-*p*")
) or
(process.name == "sudo" and process.args == "-l") or
(
process.executable like ("/bin/chmod", "/usr/bin/chmod", "/usr/local/bin/chmod") and
process.args like ("+x", "a+x", "0777", "755", "777", "+s", "u+s", "g+s")
) or
(
process.executable like ("/bin/cat", "/usr/bin/cat", "/usr/local/bin/cat") and
process.args like (
"/etc/passwd", "/etc/shadow", "/etc/hostname", "/etc/hosts", "*ssh*", "/proc/self/environ",
"*.env*", "*../../../*", "*/secrets/kubernetes.io/serviceaccount/*", "*/.docker/config.json*",
"*/.npmrc*", "*.aws/credentials*", "*/.aws/config*"
)
) or
(
process.name in ("bash", "dash", "sh", "tcsh", "csh", "zsh", "ksh", "fish", "busybox") and
process.args in ("-c", "-cl", "-lc") and (
process.command_line like (
"* /tmp/* ", "* /var/tmp/* ", "* /dev/shm/*", "* /var/www/*", "* /run/*", "* /var/run/*",
"*python* -c*", "*php* -r*", "*perl* -e*", "*ruby* -e*", "*lua* -e*", "*node * -e *",
"*|sh", "*| sh *", "*| sh ", "*|bash*", "*| bash*", "*|zsh*", "*| zsh*", "*|dash*", "*| dash*",
"*|python*", "*| python*", "*|php*", "*| php*", "*|perl*", "*| perl*", "*|ruby*", "*| ruby*",
"*|node*", "*| node*", "*|lua*", "*| lua*", "*|busybox*", "*| busybox*", "*|*base64 -d*", "*|*base64 --decode*",
"*|*base64 --decode*", "*|*openssl base64 -d*", "*xxd *", "*| openssl*enc * -d *", "*b64decode -r*",
"*netcat *", "* nc *", "*ncat *", "*/dev/tcp*", "*/dev/udp/*", "*socat *", "*openssl*s_client *", "*stty*raw*-echo*",
"*>*/etc/cron*", "*/etc/ssh*", "*/home/*/.ssh/*", "*/root/.ssh*", "*~/.ssh/*", "*/etc/shadow*", "*/etc/passwd*", "*chpasswd*",
"*nohup*", "*setsid *", "*timeout *sh -c *", "*disown*", "*env *sh *-c*",
"*chattr *", "*busybox *", "*#!*", "*chmod +x *",
"*gzip -*d *", "*bzip2 -*d *", "*xz -*d *", "*tar -*x*",
"*../../../*etc/*", "*/.../*", "*../../../*home/*/*", "*../../../*root/*"
) or
(
process.command_line like ("*wget *", "*curl *") and
(
process.command_line regex ".*[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}(:[0-9]{1,5})?/.*" or
process.command_line like ("*http*", "*ftp*")
) and
(
(
process.command_line regex~ """.*curl.* \-[a-zA-Z]*[oO]( .+|\-.*)?""" or
process.command_line like~ ("*curl* --output*", "*curl* --remote-name*")
) or
(
(
process.command_line regex~ """.*wget.* \-[a-zA-Z]*O.*""" or
process.command_line like~ "*wget* --output-document*"
) and
not process.command_line like """*--output-document "-"*"""
) or
process.command_line like ("*|*sh*", "*|*python*", "*|*php*", "*|*perl*", "*|*ruby*", "*|*node*", "*|*lua*", "*|*busybox*") or
(
process.command_line like ("*curl *>> /*", "*curl *>>/*", "*curl *> /*", "*curl *>/*", "*wget *>> /*", "*wget *>>/*", "*wget *> /*", "*wget *>/*") and
not process.command_line like ("*> /dev/null*", "*>/dev/null*", "*curl*/etc/cobra/*/uploads/whatsapp/*")
)
) and
not process.command_line like ("*-O /dev/null*", "*-o /dev/null*")
)
)
)
) and
not (
process.executable like ("/tmp/newroot/*", "./runc") or
process.command_line == "sh -c locale -a" or
process.args == "/usr/bin/env" and process.args in ("check_postgres.pl", "/usr/lib/pscheduler/commands/validate-configurables") or
(
process.parent.executable == "/etc/init.d/redis-server" and
process.command_line in ("chmod 755 /var/run/redis", "touch /var/run/redis/redis-server.pid")
) or
(
process.parent.name == "postgres" and
process.command_line in (
"ps -p 1", "python2 -c pass", "timeout 5 cat /proc/net/tcp /proc/net/tcp6", "runc init", "env hostname -s",
"find . -maxdepth 1 -mindepth 1 -type d", "netstat -an"
)
) or
(
process.parent.name in ("postgres", "oracle", "tnslsnr") and
process.command_line like (
"echo nagios", "gzip -c", "/usr/bin/python3 /root/bin/yaml2json.py", "sh -c /*/scripts/check/libexec/check_df*",
"timeout --signal=3 3 telnet*", "sh -c scp*pg_wal/RECOVERYHISTORY*", "sh -c scp*pg_wal/RECOVERYXLOG*",
"env LC_ALL=C /bin/bash -c [ -f /sbin/ifconfig ] && echo 1 || echo 0"
)
) or
(
process.parent.name == "tnslsnr" and (
process.command_line like (
"/usr/bin/python3 /root/bin/yaml2json.py", "/bin/echo Filesystem 1024-blocks*", "timeout 60 ls", "timeout 10 lsblk -lbSo SIZE,TYPE"
) or
process.name in ("printenv", "env", "find", "gzip")
)
) or
(
process.parent.name == "postgres" and (
process.args like "scp*pgsql*" or
(process.name == "scp" and process.command_line like "*pgsql*") or
process.name == "uname"
)
) or
(
process.parent.name == "mysqld" and
process.command_line in ("touch /var/log/mysqld.log", "touch /var/lock/subsys/mysql")
)
)
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
event.action | eq |
| field:"EventType" kind:eq value:"exec" |
event.type | eq |
| field:"event.type" kind:eq value:"start" |
process.args | eq |
| field:"process.args" kind:eq |
process.args | in |
| field:"process.args" kind:in |
process.args | wildcard |
| field:"process.args" kind:wildcard |
process.args_count | le |
| field:"process.args_count" kind:le value:"2" |
process.command_line | regex_match |
| field:"CommandLine" kind:regex_match |
process.command_line | wildcard |
| field:"CommandLine" kind:wildcard |
process.executable | wildcard |
| field:"Image" kind:wildcard |
process.interactive | eq |
| field:"process.interactive" kind:eq value:"true" |
process.name | eq |
| field:"process_basename" kind:eq |
process.name | in |
| field:"process_basename" kind:in |
process.name | wildcard |
| field:"process_basename" kind:wildcard value:".*" |
process.parent.command_line | wildcard |
| field:"ParentCommandLine" kind:wildcard value:"*redis-server*" |
process.parent.interactive | eq |
| field:"process.parent.interactive" kind:eq value:"false" |
process.parent.name | eq |
| field:"parent_process_basename" kind:eq value:"redis-check-rdb" |
process.parent.name | in |
| field:"parent_process_basename" kind:in |
Exclusions
The rule actively suppresses these predicates.
Potential Reverse Shell via Background Process
#Monitors for the execution of background processes with process arguments capable of opening a socket in the /dev/tcp channel. This may indicate the creation of a backdoor reverse connection, and should be investigated further.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Execution | |
| Command & Control |
Rule Body
[metadata]
creation_date = "2023/09/20"
integration = ["endpoint", "crowdstrike", "sentinel_one_cloud_funnel"]
maturity = "production"
updated_date = "2026/03/24"
[rule]
author = ["Elastic"]
description = """
Monitors for the execution of background processes with process arguments capable of opening a socket in the /dev/tcp
channel. This may indicate the creation of a backdoor reverse connection, and should be investigated further.
"""
from = "now-9m"
index = [
"endgame-*",
"logs-crowdstrike.fdr*",
"logs-endpoint.events.process*",
"logs-sentinel_one_cloud_funnel.*",
]
language = "eql"
license = "Elastic License v2"
name = "Potential Reverse Shell via Background Process"
note = """## Triage and analysis
> **Disclaimer**:
> This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs.
### Investigating Potential Reverse Shell via Background Process
In Linux environments, background processes can be manipulated to establish reverse shells, allowing adversaries to gain remote access. By exploiting shell commands to open network sockets, attackers can create backdoor connections. The detection rule identifies suspicious executions of background processes, like 'setsid' or 'nohup', with arguments indicating socket activity in '/dev/tcp', often initiated by common shell interpreters. This helps in flagging potential reverse shell activities for further investigation.
### Possible investigation steps
- Review the process details to confirm the presence of suspicious arguments, specifically looking for '/dev/tcp' in the process.args field, which indicates an attempt to open a network socket.
- Identify the parent process by examining the process.parent.name field to determine if it is one of the common shell interpreters like 'bash', 'dash', 'sh', etc., which could suggest a script-based execution.
- Check the user context under which the process was executed to assess if it aligns with expected user behavior or if it indicates potential compromise of a user account.
- Investigate the network activity associated with the host to identify any unusual outbound connections that could correlate with the reverse shell attempt.
- Correlate the event with other security alerts or logs from the same host to identify any preceding or subsequent suspicious activities that might indicate a broader attack pattern.
- Review historical data for similar process executions on the host to determine if this is an isolated incident or part of a recurring pattern.
### False positive analysis
- Legitimate administrative scripts may use background processes with network socket activity for maintenance tasks. Review the script's purpose and source to determine if it is authorized.
- Automated monitoring tools might execute commands that match the rule's criteria. Identify these tools and consider excluding their specific process names or paths from the rule.
- Development environments often run test scripts that open network connections. Verify the development context and exclude known development-related processes to reduce noise.
- Backup or synchronization software may use similar techniques to transfer data. Confirm the software's legitimacy and add exceptions for its processes if necessary.
- System updates or package management tools might trigger alerts when installing or updating software. Monitor these activities and whitelist trusted update processes.
### Response and remediation
- Immediately isolate the affected host from the network to prevent further unauthorized access or data exfiltration.
- Terminate any suspicious background processes identified by the alert, specifically those involving 'setsid' or 'nohup' with '/dev/tcp' in their arguments.
- Conduct a thorough review of the affected system's process and network activity logs to identify any additional indicators of compromise or lateral movement.
- Reset credentials for any accounts that were active on the affected system to prevent unauthorized access using potentially compromised credentials.
- Apply security patches and updates to the affected system to address any vulnerabilities that may have been exploited.
- Implement network segmentation to limit the ability of compromised systems to communicate with critical infrastructure or sensitive data repositories.
- Escalate the incident to the security operations center (SOC) or incident response team for further analysis and to determine if additional systems are affected."""
risk_score = 73
rule_id = "259be2d8-3b1a-4c2c-a0eb-0c8e77f35e39"
setup = """## Setup
This rule requires data coming in from Elastic Defend.
### Elastic Defend Integration Setup
Elastic Defend is integrated into the Elastic Agent using Fleet. Upon configuration, the integration allows the Elastic Agent to monitor events on your host and send data to the Elastic Security app.
#### Prerequisite Requirements:
- Fleet is required for Elastic Defend.
- To configure Fleet Server refer to the [documentation](https://www.elastic.co/guide/en/fleet/current/fleet-server.html).
#### The following steps should be executed in order to add the Elastic Defend integration on a Linux System:
- Go to the Kibana home page and click "Add integrations".
- In the query bar, search for "Elastic Defend" and select the integration to see more details about it.
- Click "Add Elastic Defend".
- Configure the integration name and optionally add a description.
- Select the type of environment you want to protect, either "Traditional Endpoints" or "Cloud Workloads".
- Select a configuration preset. Each preset comes with different default settings for Elastic Agent, you can further customize these later by configuring the Elastic Defend integration policy. [Helper guide](https://www.elastic.co/guide/en/security/current/configure-endpoint-integration-policy.html).
- We suggest selecting "Complete EDR (Endpoint Detection and Response)" as a configuration setting, that provides "All events; all preventions"
- Enter a name for the agent policy in "New agent policy name". If other agent policies already exist, you can click the "Existing hosts" tab and select an existing policy instead.
For more details on Elastic Agent configuration settings, refer to the [helper guide](https://www.elastic.co/guide/en/fleet/8.10/agent-policy.html).
- Click "Save and Continue".
- To complete the integration, select "Add Elastic Agent to your hosts" and continue to the next section to install the Elastic Agent on your hosts.
For more details on Elastic Defend refer to the [helper guide](https://www.elastic.co/guide/en/security/current/install-endpoint.html).
"""
severity = "high"
tags = [
"Domain: Endpoint",
"OS: Linux",
"Use Case: Threat Detection",
"Tactic: Execution",
"Data Source: Elastic Defend",
"Data Source: Elastic Endgame",
"Data Source: Crowdstrike",
"Data Source: SentinelOne",
"Resources: Investigation Guide",
]
timestamp_override = "event.ingested"
type = "eql"
query = '''
process where host.os.type == "linux" and event.type == "start" and
event.action in ("exec", "exec_event", "start", "ProcessRollup2") and
process.name in ("setsid", "nohup") and process.args : "*/dev/tcp/*0>&1*" and
process.parent.name in ("bash", "dash", "sh", "tcsh", "csh", "zsh", "ksh", "fish")
'''
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1059"
name = "Command and Scripting Interpreter"
reference = "https://attack.mitre.org/techniques/T1059/"
[[rule.threat.technique.subtechnique]]
id = "T1059.004"
name = "Unix Shell"
reference = "https://attack.mitre.org/techniques/T1059/004/"
[rule.threat.tactic]
id = "TA0002"
name = "Execution"
reference = "https://attack.mitre.org/tactics/TA0002/"
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1071"
name = "Application Layer Protocol"
reference = "https://attack.mitre.org/techniques/T1071/"
[[rule.threat.technique]]
id = "T1095"
name = "Non-Application Layer Protocol"
reference = "https://attack.mitre.org/techniques/T1095/"
[rule.threat.tactic]
id = "TA0011"
name = "Command and Control"
reference = "https://attack.mitre.org/tactics/TA0011/"
Stages and Predicates
Stage 1: process
process where host.os.type == "linux" and event.type == "start" and
event.action in ("exec", "exec_event", "start", "ProcessRollup2") and
process.name in ("setsid", "nohup") and process.args : "*/dev/tcp/*0>&1*" and
process.parent.name in ("bash", "dash", "sh", "tcsh", "csh", "zsh", "ksh", "fish")
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
event.action | in |
| field:"EventType" kind:in |
event.type | eq |
| field:"event.type" kind:eq value:"start" |
process.args | wildcard |
| field:"process.args" kind:wildcard value:"*/dev/tcp/*0>&1*" |
process.name | in |
| field:"process_basename" kind:in |
process.parent.name | in |
| field:"parent_process_basename" kind:in |
Process Creation with Unusual Mitigation
#Identifies attempts to create a process with Microsoft mitigation policy set prevent loading non Microsoft signed DLLs. Adversaries may abuse this feature to prevent loading Endpoint security DLLs that lacks this code signing requirement.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Defense Impairment |
Rule Body
[rule]
description = """
Identifies attempts to create a process with Microsoft mitigation policy set prevent loading non Microsoft signed DLLs.
Adversaries may abuse this feature to prevent loading Endpoint security DLLs that lacks this code signing requirement.
"""
id = "d09ce1d0-f961-4eae-906c-22e551a1c3b6"
license = "Elastic License v2"
name = "Process Creation with Unusual Mitigation"
os_list = ["windows"]
reference = [
"https://blog.xpnsec.com/protecting-your-malware/",
"https://www.elastic.co/security-labs/pikabot-i-choose-you",
]
version = "1.0.22"
query = '''
process where event.type == "start" and process.executable != null and
process.parent.executable != null and process.Ext.token.integrity_level_name != "low" and
process.Ext.mitigation_policies : "Microsoft only" and
(
(process.parent.thread.Ext.call_stack_contains_unbacked == true and
process.parent.thread.Ext.call_stack_summary :
("ntdll.dll|Unbacked",
"ntdll.dll|kernelbase.dll|Unbacked",
"ntdll.dll|kernelbase.dll|kernel32.dll|Unbacked",
"ntdll.dll|wow64.dll|wow64cpu.dll|wow64.dll|ntdll.dll|kernelbase.dll|Unbacked",
"ntdll.dll|wow64.dll|wow64cpu.dll|wow64.dll|ntdll.dll|kernelbase.dll|kernel32.dll|Unbacked",
"ntdll.dll|wow64.dll|wow64cpu.dll|wow64.dll|ntdll.dll|kernelbase.dll|Unbacked|kernel32.dll|ntdll.dll")) or
process.parent.Ext.real.pid > 0 or
(process.parent.thread.Ext.call_stack_summary : "ntdll.dll|*" and
not process.parent.thread.Ext.call_stack_summary : ("*kernelbase.dll*", "*rpcrt4.dll*", "ntdll.dll|tmmon64.dll"))
) and
not (process.Ext.token.integrity_level_name : "system" and
process.executable :
("?:\\ProgramData\\Microsoft\\Windows Defender Advanced Threat Protection\\DataCollection\\*.exe",
"\\Device\\HarddiskVolume*\\ProgramData\\Microsoft\\Windows Defender Advanced Threat Protection\\DataCollection\\*.exe")) and
not (process.code_signature.subject_name : ("Microsoft Windows Defender Advanced Threat Protection", "Wavesor Software (Eightpoint Technologies Ltd. SEZC)") and
process.code_signature.status : "trusted" and process.Ext.token.integrity_level_name : "system") and
not (process.parent.executable : "?:\\Windows\\System32\\hv*.exe" and process.executable : "?:\\Windows\\System32\\hv*.exe") and
not (process.executable : "?:\\Program Files\\Microsoft Office\\root\\vfs\\*\\AI\\ai.exe" and process.parent.executable : "?:\\Program Files\\Microsoft Office\\*.EXE") and
not (process.executable : "?:\\Program Files (x86)\\Microsoft Office\\*\\AI\\ai.exe" and process.parent.executable : "?:\\Program Files (x86)\\Microsoft Office\\*.EXE") and
not (process.parent.executable : "?:\\Windows\\System32\\browser_broker.exe" and process.executable : "?:\\Windows\\System32\\browser_broker.exe") and
not (process.executable : "?:\\Windows\\System32\\vmwp.exe" and process.parent.executable : "?:\\Windows\\System32\\vmcompute.exe") and
not (process.parent.executable : "?:\\Windows\\System32\\lsass.exe" and process.executable : "?:\\Windows\\system32\\lsass.exe" and
user.id == "S-1-5-18") and
not (process.executable : "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe" and
process.parent.executable : "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe") and
not (process.executable : "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe" and
process.parent.executable : "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe") and
not (process.executable : "C:\\Users\\*\\AppData\\Local\\Yandex\\YandexBrowser\\Application\\browser.exe" and
process.parent.executable : "C:\\Users\\*\\AppData\\Local\\Yandex\\YandexBrowser\\Application\\browser.exe" and
process.code_signature.subject_name == "YANDEX LLC" and process.code_signature.trusted == true) and
not (process.executable : "C:\\Windows\\System32\\Dism.exe" and process.args : "/Online" and
(process.parent.executable : ("C:\\Program Files\\*.exe", "C:\\Program Files (x86)\\*") or user.id == "S-1-5-18")) and
not (process.executable : "?:\\Windows\\system32\\DllHost.exe" and
process.parent.executable : "?:\\Windows\\System32\\dllhost.exe" and
process.args : "/Processid:{3EB3C877-1F16-487C-9050-104DBCD66683}" and
process.parent.thread.Ext.call_stack_summary : "ntdll.dll|kernel32.dll|ntdll.dll") and
not (process.parent.thread.Ext.call_stack_summary : "ntdll.dll|atcuf*.dll|Unbacked" and
_arraysearch(process.parent.thread.Ext.call_stack, $entry,
$entry.symbol_info : "?:\\Program Files*\\N-able Technologies\\AVDefender\\*.dll!*")) and
not (process.executable : "?:\\Windows\\System32\\CastSrv.exe" and process.parent.args : "CCastServerControlInteractiveUser" and
process.parent.executable : "?:\\Windows\\System32\\CastSrv.exe") and
not (process.name : "powershell.exe" and user.id in ("S-1-5-19", "S-1-5-20") and process.parent.name : "powershell.exe" and
process.parent.args :
("& {$OutputEncoding = [Console]::OutputEncoding =[System.Text.Encoding]::UTF8;$scriptFileStream = [System.IO.File]::Open('C:\\ProgramData\\Microsoft\\Windows Defender Advanced Threat Protection\\Downloads\\PSScript*",
"& {if ($ExecutionContext.SessionState.LanguageMode -eq 'FullLanguage') {$OutputEncoding = [Console]::OutputEncoding =[System.Text.Encoding]::UTF8}else {chcp 65001};Start-Transcript -Path 'C:\\ProgramData\\Microsoft\\Windows Defender Advanced Threat Protection\\Temp\\PSScriptOutputs\\PSScript_Transcript_*")) and
not _arraysearch(process.parent.thread.Ext.call_stack, $entry, $entry.callsite_trailing_bytes : "8945ac65488b042530000000448ba05012000065488b042530000000448b6868eb0a448b642460448b6c24644d85ff7409498b0748894598eb0448897598448b") and
not (process.executable : "?:\\Program Files\\Microsoft Office\\root\\vfs\\ProgramFilesCommonX64\\Microsoft Shared\\Office??\\AI\\aimgr.exe" and
process.parent.executable : "?:\\Program Files\\Microsoft Office\\root\\Office??\\*.EXE")
'''
min_endpoint_version = "8.8.0"
optional_actions = []
[[actions]]
action = "kill_process"
field = "process.entity_id"
state = 0
[[threat]]
framework = "MITRE ATT&CK"
[[threat.technique]]
id = "T1562"
name = "Impair Defenses"
reference = "https://attack.mitre.org/techniques/T1562/"
[[threat.technique.subtechnique]]
id = "T1562.001"
name = "Disable or Modify Tools"
reference = "https://attack.mitre.org/techniques/T1562/001/"
[threat.tactic]
id = "TA0005"
name = "Defense Evasion"
reference = "https://attack.mitre.org/tactics/TA0005/"
[internal]
min_endpoint_version = "8.8.0"
Stages and Predicates
Stage 1: process
process where event.type == "start" and process.executable != null and
process.parent.executable != null and process.Ext.token.integrity_level_name != "low" and
process.Ext.mitigation_policies : "Microsoft only" and
(
(process.parent.thread.Ext.call_stack_contains_unbacked == true and
process.parent.thread.Ext.call_stack_summary :
("ntdll.dll|Unbacked",
"ntdll.dll|kernelbase.dll|Unbacked",
"ntdll.dll|kernelbase.dll|kernel32.dll|Unbacked",
"ntdll.dll|wow64.dll|wow64cpu.dll|wow64.dll|ntdll.dll|kernelbase.dll|Unbacked",
"ntdll.dll|wow64.dll|wow64cpu.dll|wow64.dll|ntdll.dll|kernelbase.dll|kernel32.dll|Unbacked",
"ntdll.dll|wow64.dll|wow64cpu.dll|wow64.dll|ntdll.dll|kernelbase.dll|Unbacked|kernel32.dll|ntdll.dll")) or
process.parent.Ext.real.pid > 0 or
(process.parent.thread.Ext.call_stack_summary : "ntdll.dll|*" and
not process.parent.thread.Ext.call_stack_summary : ("*kernelbase.dll*", "*rpcrt4.dll*", "ntdll.dll|tmmon64.dll"))
) and
not (process.Ext.token.integrity_level_name : "system" and
process.executable :
("?:\\ProgramData\\Microsoft\\Windows Defender Advanced Threat Protection\\DataCollection\\*.exe",
"\\Device\\HarddiskVolume*\\ProgramData\\Microsoft\\Windows Defender Advanced Threat Protection\\DataCollection\\*.exe")) and
not (process.code_signature.subject_name : ("Microsoft Windows Defender Advanced Threat Protection", "Wavesor Software (Eightpoint Technologies Ltd. SEZC)") and
process.code_signature.status : "trusted" and process.Ext.token.integrity_level_name : "system") and
not (process.parent.executable : "?:\\Windows\\System32\\hv*.exe" and process.executable : "?:\\Windows\\System32\\hv*.exe") and
not (process.executable : "?:\\Program Files\\Microsoft Office\\root\\vfs\\*\\AI\\ai.exe" and process.parent.executable : "?:\\Program Files\\Microsoft Office\\*.EXE") and
not (process.executable : "?:\\Program Files (x86)\\Microsoft Office\\*\\AI\\ai.exe" and process.parent.executable : "?:\\Program Files (x86)\\Microsoft Office\\*.EXE") and
not (process.parent.executable : "?:\\Windows\\System32\\browser_broker.exe" and process.executable : "?:\\Windows\\System32\\browser_broker.exe") and
not (process.executable : "?:\\Windows\\System32\\vmwp.exe" and process.parent.executable : "?:\\Windows\\System32\\vmcompute.exe") and
not (process.parent.executable : "?:\\Windows\\System32\\lsass.exe" and process.executable : "?:\\Windows\\system32\\lsass.exe" and
user.id == "S-1-5-18") and
not (process.executable : "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe" and
process.parent.executable : "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe") and
not (process.executable : "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe" and
process.parent.executable : "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe") and
not (process.executable : "C:\\Users\\*\\AppData\\Local\\Yandex\\YandexBrowser\\Application\\browser.exe" and
process.parent.executable : "C:\\Users\\*\\AppData\\Local\\Yandex\\YandexBrowser\\Application\\browser.exe" and
process.code_signature.subject_name == "YANDEX LLC" and process.code_signature.trusted == true) and
not (process.executable : "C:\\Windows\\System32\\Dism.exe" and process.args : "/Online" and
(process.parent.executable : ("C:\\Program Files\\*.exe", "C:\\Program Files (x86)\\*") or user.id == "S-1-5-18")) and
not (process.executable : "?:\\Windows\\system32\\DllHost.exe" and
process.parent.executable : "?:\\Windows\\System32\\dllhost.exe" and
process.args : "/Processid:{3EB3C877-1F16-487C-9050-104DBCD66683}" and
process.parent.thread.Ext.call_stack_summary : "ntdll.dll|kernel32.dll|ntdll.dll") and
not (process.parent.thread.Ext.call_stack_summary : "ntdll.dll|atcuf*.dll|Unbacked" and
_arraysearch(process.parent.thread.Ext.call_stack, $entry,
$entry.symbol_info : "?:\\Program Files*\\N-able Technologies\\AVDefender\\*.dll!*")) and
not (process.executable : "?:\\Windows\\System32\\CastSrv.exe" and process.parent.args : "CCastServerControlInteractiveUser" and
process.parent.executable : "?:\\Windows\\System32\\CastSrv.exe") and
not (process.name : "powershell.exe" and user.id in ("S-1-5-19", "S-1-5-20") and process.parent.name : "powershell.exe" and
process.parent.args :
("& {$OutputEncoding = [Console]::OutputEncoding =[System.Text.Encoding]::UTF8;$scriptFileStream = [System.IO.File]::Open('C:\\ProgramData\\Microsoft\\Windows Defender Advanced Threat Protection\\Downloads\\PSScript*",
"& {if ($ExecutionContext.SessionState.LanguageMode -eq 'FullLanguage') {$OutputEncoding = [Console]::OutputEncoding =[System.Text.Encoding]::UTF8}else {chcp 65001};Start-Transcript -Path 'C:\\ProgramData\\Microsoft\\Windows Defender Advanced Threat Protection\\Temp\\PSScriptOutputs\\PSScript_Transcript_*")) and
not _arraysearch(process.parent.thread.Ext.call_stack, $entry, $entry.callsite_trailing_bytes : "8945ac65488b042530000000448ba05012000065488b042530000000448b6868eb0a448b642460448b6c24644d85ff7409498b0748894598eb0448897598448b") and
not (process.executable : "?:\\Program Files\\Microsoft Office\\root\\vfs\\ProgramFilesCommonX64\\Microsoft Shared\\Office??\\AI\\aimgr.exe" and
process.parent.executable : "?:\\Program Files\\Microsoft Office\\root\\Office??\\*.EXE")
Indicators
These rows show field, operator, and value matches.
Exclusions
The rule actively suppresses these predicates.
Script File Written to Startup Folder
#Identifies suspicious Windows script file extensions written to the startup folder. Adversaries may use this technique to maintain persistence.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Persistence |
Rule Body
[rule]
description = """
Identifies suspicious Windows script file extensions written to the startup folder. Adversaries may use this technique
to maintain persistence.
"""
id = "dec8781c-ef73-4037-9684-ef28c0322fa4"
license = "Elastic License v2"
name = "Script File Written to Startup Folder"
os_list = ["windows"]
reference = ["https://www.elastic.co/security-labs/doing-time-with-the-yipphb-dropper"]
version = "1.0.37"
query = '''
file where event.action != "deletion" and process.name != null and
file.extension : ("js", "vbs", "jar") and file.name != null and user.id : ("S-1-5-21*", "S-1-12-*") and
file.path : ("?:\\Users\\*\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\*",
"?:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\StartUp\\*") and
not process.code_signature.trusted == true and
not process.executable : ("?:\\Program Files\\*.exe", "?:\\Program Files (x86)\\*.exe")
'''
min_endpoint_version = "8.0.0"
optional_actions = []
[[actions]]
action = "kill_process"
field = "process.entity_id"
state = 0
[[threat]]
framework = "MITRE ATT&CK"
[[threat.technique]]
id = "T1547"
name = "Boot or Logon Autostart Execution"
reference = "https://attack.mitre.org/techniques/T1547/"
[[threat.technique.subtechnique]]
id = "T1547.001"
name = "Registry Run Keys / Startup Folder"
reference = "https://attack.mitre.org/techniques/T1547/001/"
[threat.tactic]
id = "TA0003"
name = "Persistence"
reference = "https://attack.mitre.org/tactics/TA0003/"
[internal]
min_endpoint_version = "8.0.0"
Stages and Predicates
Stage 1: file
file where event.action != "deletion" and process.name != null and
file.extension : ("js", "vbs", "jar") and file.name != null and user.id : ("S-1-5-21*", "S-1-12-*") and
file.path : ("?:\\Users\\*\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\*",
"?:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\StartUp\\*") and
not process.code_signature.trusted == true and
not process.executable : ("?:\\Program Files\\*.exe", "?:\\Program Files (x86)\\*.exe")
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
event.action | ne |
| field:"EventType" kind:ne value:"deletion" |
file.extension | wildcard |
| field:"file.extension" kind:wildcard |
file.name | is_not_null | field:"file.name" kind:is_not_null | |
file.path | wildcard |
| field:"TargetFilename" kind:wildcard |
process.name | is_not_null | field:"process_basename" kind:is_not_null | |
user.id | wildcard |
| field:"user.id" kind:wildcard |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
process.code_signature.trusted | eq | true | excludes:process.code_signature.trusted field:"process.code_signature.trusted" value:"true" |
process.executable | wildcard | ?:\Program Files\*.exe, ?:\Program Files (x86)\*.exe | excludes:process.executable field:"process.executable" value:"?:\Program Files\*.exe" field:"process.executable" value:"?:\Program Files (x86)\*.exe" |
Splunk External Alerts
#This is a third-party alert feed, not a detection over modeled telemetry. Another security product raised the finding; this rule forwards or reshapes it into the SIEM. It is searchable for reference but is excluded from the detection-rule browse and the ATT&CK coverage matrix.
Generates a detection alert for each Splunk alert written to the configured indices. Enabling this rule allows you to immediately begin investigating Splunk alerts in the app.
Rule Body
[metadata]
creation_date = "2025/07/31"
integration = ["splunk"]
maturity = "production"
promotion = true
updated_date = "2025/10/17"
[rule]
author = ["Elastic"]
description = """
Generates a detection alert for each Splunk alert written to the configured indices. Enabling this rule allows you to
immediately begin investigating Splunk alerts in the app.
"""
from = "now-2m"
index = ["logs-splunk.alert-*"]
interval = "1m"
language = "kuery"
license = "Elastic License v2"
max_signals = 1000
name = "Splunk External Alerts"
note = """## Triage and analysis
### Investigating Splunk External Alerts
Splunk monitors and analyzes data, often used in security environments to track and respond to potential threats. The rule identifies such manipulations by flagging alerts enabling timely investigation and response.
### Possible investigation steps
- Examine the specific indices where the alert was written to identify any unusual or unauthorized activity.
- Cross-reference the alert with recent changes or activities in the Splunk environment to determine if the alert could be a result of legitimate administrative actions.
- Investigate the source and context of the alert to identify any patterns or anomalies that could indicate manipulation or false positives.
- Check for any related alerts or logs that might provide additional context or evidence of adversarial behavior.
- Consult the Splunk investigation guide and resources tagged in the alert for specific guidance on handling similar threats.
### False positive analysis
- Alerts triggered by routine Splunk maintenance activities can be false positives. To manage these, identify and document regular maintenance schedules and create exceptions for alerts generated during these times.
- Frequent alerts from specific indices that are known to contain non-threatening data can be excluded by adjusting the rule to ignore these indices, ensuring only relevant alerts are investigated.
- Alerts generated by automated scripts or tools that interact with Splunk for legitimate purposes can be false positives. Review and whitelist these scripts or tools to prevent unnecessary alerts.
- If certain user actions consistently trigger alerts but are verified as non-malicious, consider creating user-specific exceptions to reduce noise and focus on genuine threats.
- Regularly review and update the list of exceptions to ensure they remain relevant and do not inadvertently exclude new or evolving threats.
### Response and remediation
- Immediately isolate affected systems to prevent further manipulation of Splunk alerts and potential spread of malicious activity.
- Review and validate the integrity of the Splunk alert indices to ensure no unauthorized changes have been made.
- Restore any compromised Splunk alert configurations from a known good backup to ensure accurate monitoring and alerting.
- Conduct a thorough audit of user access and permissions within Splunk to identify and revoke any unauthorized access.
- Escalate the incident to the security operations center (SOC) for further analysis and to determine if additional systems or data have been affected.
- Implement enhanced monitoring on Splunk indices to detect any future unauthorized changes or suspicious activities.
- Document the incident details and response actions taken for future reference and to improve incident response procedures.
"""
references = ["https://docs.elastic.co/en/integrations/splunk"]
risk_score = 47
rule_id = "d3b6222f-537e-4b84-956a-3ebae2dcf811"
rule_name_override = "splunk.alert.source"
setup = """## Setup
### Splunk Alert Integration
This rule is designed to capture alert events generated by the Splunk integration and promote them as Elastic detection alerts.
To capture Splunk alerts, install and configure the Splunk integration to ingest alert events into the `logs-splunk.alert-*` index pattern.
If this rule is enabled alongside the External Alerts promotion rule (UUID: eb079c62-4481-4d6e-9643-3ca499df7aaa), you may receive duplicate alerts for the same Splunk events. Consider adding a rule exception for the External Alert rule to exclude data_stream.dataset:splunk.alert to avoid receiving duplicate alerts.
### Additional notes
For information on troubleshooting the maximum alerts warning please refer to this [guide](https://www.elastic.co/guide/en/security/current/alerts-ui-monitor.html#troubleshoot-max-alerts).
"""
severity = "medium"
tags = [
"Data Source: Splunk",
"Use Case: Threat Detection",
"Resources: Investigation Guide",
"Promotion: External Alerts",
]
timestamp_override = "event.ingested"
type = "query"
query = '''
event.kind: alert and data_stream.dataset: splunk.alert
'''
[[rule.risk_score_mapping]]
field = "event.risk_score"
operator = "equals"
value = ""
[[rule.severity_mapping]]
field = "event.severity"
operator = "equals"
severity = "low"
value = "21"
[[rule.severity_mapping]]
field = "event.severity"
operator = "equals"
severity = "medium"
value = "47"
[[rule.severity_mapping]]
field = "event.severity"
operator = "equals"
severity = "high"
value = "73"
[[rule.severity_mapping]]
field = "event.severity"
operator = "equals"
severity = "critical"
value = "99"
Stages and Predicates
Stage 1: query
event.kind: alert and data_stream.dataset: splunk.alert
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
data_stream.dataset | eq |
| field:"data_stream.dataset" kind:eq value:"splunk.alert" |
event.kind | eq |
| field:"event.kind" kind:eq value:"alert" |
Suspicious Curl to OAST Domain
#Detects when curl is used to make an outbound network connection to a .oast domain. Threat actors have been recently seen using .oast domains in order to exfiltrate sensitive data from infected systems.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Command & Control |
Telemetry Coverage
Rule Body
[rule]
description = """
Detects when curl is used to make an outbound network connection to a .oast domain. Threat actors have been recently
seen using .oast domains in order to exfiltrate sensitive data from infected systems.
"""
id = "f0d4b092-8bc7-4625-9290-5f4a530a167f"
license = "Elastic License v2"
name = "Suspicious Curl to OAST Domain"
os_list = ["macos"]
reference = ["https://socket.dev/blog/weaponizing-oast-how-malicious-packages-exploit-npm-pypi-and-rubygems"]
version = "1.0.4"
query = '''
process where event.type == "start" and event.action == "exec" and process.name in ("curl", "nscurl") and
process.command_line like~ "*.oast*"
'''
min_endpoint_version = "8.16.0"
optional_actions = []
[[actions]]
action = "kill_process"
field = "process.entity_id"
state = 0
[[actions]]
action = "kill_process"
field = "process.parent.entity_id"
state = 0
[[threat]]
framework = "MITRE ATT&CK"
[[threat.technique]]
id = "T1105"
name = "Ingress Tool Transfer"
reference = "https://attack.mitre.org/techniques/T1105/"
[threat.tactic]
id = "TA0011"
name = "Command and Control"
reference = "https://attack.mitre.org/tactics/TA0011/"
[internal]
min_endpoint_version = "8.16.0"
Stages and Predicates
Stage 1: process
process where event.type == "start" and event.action == "exec" and process.name in ("curl", "nscurl") and
process.command_line like~ "*.oast*"
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
event.action | eq |
| field:"EventType" kind:eq value:"exec" |
event.type | eq |
| field:"event.type" kind:eq value:"start" |
process.command_line | wildcard |
| field:"CommandLine" kind:wildcard value:"*.oast*" |
process.name | in |
| field:"process_basename" kind:in |
Suspicious SUID/SGID Utility Execution
#This rule looks for likely exploitation behavior by detecting common SUID helpers such as su, sudo, pkexec, and passwd being launched with minimal arguments from interpreters, temporary paths, home directories, or shell one-liners.
MITRE ATT&CK Coverage
Rule Body
[rule]
description = """
This rule looks for likely exploitation behavior by detecting common SUID helpers such as su, sudo, pkexec, and passwd
being launched with minimal arguments from interpreters, temporary paths, home directories, or shell one-liners.
"""
id = "83b0e48b-f42e-4323-b8cd-386619a96d35"
license = "Elastic License v2"
name = "Suspicious SUID/SGID Utility Execution"
os_list = ["linux"]
reference = ["https://xint.io/blog/copy-fail-linux-distributions", "https://github.com/badsectorlabs/copyfail-go"]
version = "1.0.3"
query = '''
process where event.type == "start" and event.action == "exec" and (
(process.user.id == 0 and process.real_user.id != 0) or
(process.group.id == 0 and process.real_group.id != 0)
) and (
(process.name == "su" and process.args_count <= 2) or
(process.name == "sudo" and process.args_count == 1) or
(process.name == "pkexec" and process.args_count == 1) or
(process.name == "passwd" and process.args_count <= 2)
) and
(
process.parent.name like (".*", "python*", "perl*", "ruby*", "lua*", "php*", "node", "deno", "bun", "java") or
process.parent.executable like ("./*", "/tmp/*", "/var/tmp/*", "/dev/shm/*", "/run/user/*", "/var/run/user/*", "/home/*/*") or
(
process.parent.name in ("bash", "dash", "sh", "tcsh", "csh", "zsh", "ksh", "fish", "mksh") and
process.parent.args in ("-c", "-cl", "-lc", "--command", "-ic", "-ci") and
process.parent.args_count <= 4
)
) and
not (
(process.name == "passwd" and process.parent.command_line like "*Bastion*") or
(process.executable == "/usr/bin/sudo" and process.parent.command_line like "*clean_pat_system_pip.py*")
)
'''
min_endpoint_version = "8.2.0"
optional_actions = []
[[actions]]
action = "kill_process"
field = "process.entity_id"
state = 0
[[actions]]
action = "kill_process"
field = "process.parent.entity_id"
state = 0
[[threat]]
framework = "MITRE ATT&CK"
[[threat.technique]]
id = "T1068"
name = "Exploitation for Privilege Escalation"
reference = "https://attack.mitre.org/techniques/T1068/"
[[threat.technique]]
id = "T1548"
name = "Abuse Elevation Control Mechanism"
reference = "https://attack.mitre.org/techniques/T1548/"
[[threat.technique.subtechnique]]
id = "T1548.001"
name = "Setuid and Setgid"
reference = "https://attack.mitre.org/techniques/T1548/001/"
[[threat.technique.subtechnique]]
id = "T1548.003"
name = "Sudo and Sudo Caching"
reference = "https://attack.mitre.org/techniques/T1548/003/"
[threat.tactic]
id = "TA0004"
name = "Privilege Escalation"
reference = "https://attack.mitre.org/tactics/TA0004/"
[internal]
min_endpoint_version = "8.2.0"
Stages and Predicates
Stage 1: process
process where event.type == "start" and event.action == "exec" and (
(process.user.id == 0 and process.real_user.id != 0) or
(process.group.id == 0 and process.real_group.id != 0)
) and (
(process.name == "su" and process.args_count <= 2) or
(process.name == "sudo" and process.args_count == 1) or
(process.name == "pkexec" and process.args_count == 1) or
(process.name == "passwd" and process.args_count <= 2)
) and
(
process.parent.name like (".*", "python*", "perl*", "ruby*", "lua*", "php*", "node", "deno", "bun", "java") or
process.parent.executable like ("./*", "/tmp/*", "/var/tmp/*", "/dev/shm/*", "/run/user/*", "/var/run/user/*", "/home/*/*") or
(
process.parent.name in ("bash", "dash", "sh", "tcsh", "csh", "zsh", "ksh", "fish", "mksh") and
process.parent.args in ("-c", "-cl", "-lc", "--command", "-ic", "-ci") and
process.parent.args_count <= 4
)
) and
not (
(process.name == "passwd" and process.parent.command_line like "*Bastion*") or
(process.executable == "/usr/bin/sudo" and process.parent.command_line like "*clean_pat_system_pip.py*")
)
Indicators
These rows show field, operator, and value matches.
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
process.executable | eq | /usr/bin/sudo | excludes:process.executable field:"process.executable" value:"/usr/bin/sudo" |
process.parent.command_line | match | clean_pat_system_pip.py | excludes:process.parent.command_line field:"process.parent.command_line" value:"clean_pat_system_pip.py" |
process.name | eq | passwd | excludes:process.name field:"process.name" value:"passwd" |
process.parent.command_line | match | Bastion | excludes:process.parent.command_line field:"process.parent.command_line" value:"Bastion" |
System and Network Configuration Check
#Detects when the SystemConfiguration preferences plist file is accessed by an unusual or suspicious process. This may indicate an attempt to gain situational awareness on a target system by reading network configuration details.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Discovery |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| macOS | ESF event open (NOTIFY): Fires after the kernel grants a process access to open a file. |
Rule Body
[metadata]
creation_date = "2026/01/30"
integration = ["endpoint"]
maturity = "production"
updated_date = "2026/03/24"
[rule]
author = ["Elastic"]
description = """
Detects when the SystemConfiguration preferences plist file is accessed by an unusual or suspicious
process. This may indicate an attempt to gain situational awareness on a target system by reading
network configuration details.
"""
from = "now-9m"
index = ["logs-endpoint.events.file-*"]
language = "eql"
license = "Elastic License v2"
name = "System and Network Configuration Check"
note = """ ## Triage and analysis
> **Disclaimer**:
> This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs.
### Investigating System and Network Configuration Check
This rule flags suspicious processes reading macOS SystemConfiguration preferences, which can reveal network interfaces, DNS settings, and other environment details used to plan lateral movement or data exfiltration. Attackers commonly run scripting runtimes (e.g., Python, AppleScript, Node) or binaries staged in temporary/shared directories to open the preferences plist during early discovery. Catching this access helps identify stealthy reconnaissance before overt network activity begins.
### Possible investigation steps
- Identify the parent process and full execution chain for the accessing process, including any script path/arguments, to determine whether it was launched by an interactive user, management tooling, or a suspicious launcher.
- Review the accessing binary’s provenance by checking code signature/notarization status, file hash reputation, and whether it was recently created or executed from temporary/shared directories indicating staging.
- Correlate nearby discovery activity on the host (e.g., reads of other system/network plists, execution of `scutil`, `ifconfig`, `networksetup`, or `defaults read`) to assess whether this is part of a broader reconnaissance sequence.
- Examine concurrent network activity from the same process (outbound connections, DNS lookups, proxy changes) to identify follow-on behavior consistent with environment mapping or command-and-control.
- Validate the behavior against legitimate software on the host (IT management, VPN/endpoint tools, developer workflows) by matching timestamps to user logins, scheduled jobs, and recent installs/updates.
### False positive analysis
- A legitimate IT/admin or troubleshooting script run interactively (e.g., a Python/AppleScript wrapper) may read `/Library/Preferences/SystemConfiguration/preferences.plist` to collect network settings during support, onboarding, or diagnostics.
- A developer or automation workflow may execute a temporary or shared-directory runtime (e.g., `node`/`python` unpacked to `/tmp` or `/Users/Shared`) that reads the plist to detect interfaces, DNS, or proxy configuration for environment-aware builds or tests.
### Response and remediation
- Isolate the affected Mac from the network and terminate the offending process tree, then quarantine the on-disk script/binary (especially if staged in /tmp, /private/tmp, /var/tmp, or /Users/Shared) to stop further discovery or follow-on execution.
- Collect and preserve artifacts before cleanup, including the suspicious executable/script, its launch mechanism (LaunchAgents/LaunchDaemons, cron, login items), recent shell history, and a copy of /Library/Preferences/SystemConfiguration/preferences.plist metadata for later scoping and forensics.
- Eradicate persistence by removing unauthorized launch entries and deleting the staged payloads, then re-scan the host with EDR/AV and verify no additional suspicious interpreters or unsigned tools remain in temporary/shared directories.
- Recover by rotating credentials used on the host, reviewing and resetting network settings (DNS, proxy, VPN) if changed, and returning the system to service only after repeated checks show no re-creation of the removed artifacts across a full reboot cycle.
- Escalate to incident response immediately if the same process also makes outbound connections, modifies SystemConfiguration plists, or appears on multiple hosts, and initiate enterprise-wide hunting for the file hash and the associated launcher.
- Harden by restricting execution from temporary/shared directories, enforcing signed/notarized code where possible, auditing who can read sensitive configuration files, and adding allowlists for known management tools that legitimately access the preferences plist.
"""
risk_score = 47
rule_id = "6e5189c4-d3a5-4114-8cb3-bd3a65713f19"
severity = "medium"
tags = [
"Domain: Endpoint",
"OS: macOS",
"Use Case: Threat Detection",
"Tactic: Discovery",
"Data Source: Elastic Defend",
"Resources: Investigation Guide",
]
timestamp_override = "event.ingested"
type = "eql"
query = '''
file where host.os.type == "macos" and event.action == "open" and
file.path like "/Library/Preferences/SystemConfiguration/preferences.plist" and
(process.name like~ ("python*", "osascript", "perl", "ruby", "node") or
process.executable like ("/Users/Shared/*", "/tmp/*", "/private/tmp/*", "/var/tmp/*", "/private/var/tmp/*")) and
not Effective_process.executable like "/Applications/Docker.app/Contents/MacOS/Docker"
'''
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1016"
name = "System Network Configuration Discovery"
reference = "https://attack.mitre.org/techniques/T1016/"
[[rule.threat.technique]]
id = "T1082"
name = "System Information Discovery"
reference = "https://attack.mitre.org/techniques/T1082/"
[rule.threat.tactic]
id = "TA0007"
name = "Discovery"
reference = "https://attack.mitre.org/tactics/TA0007/"
Stages and Predicates
Stage 1: file
file where host.os.type == "macos" and event.action == "open" and
file.path like "/Library/Preferences/SystemConfiguration/preferences.plist" and
(process.name like~ ("python*", "osascript", "perl", "ruby", "node") or
process.executable like ("/Users/Shared/*", "/tmp/*", "/private/tmp/*", "/var/tmp/*", "/private/var/tmp/*")) and
not Effective_process.executable like "/Applications/Docker.app/Contents/MacOS/Docker"
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
event.action | eq |
| field:"EventType" kind:eq value:"open" |
file.path | wildcard |
| field:"TargetFilename" kind:wildcard value:"/Library/Preferences/SystemConfiguration/preferences.plist" |
process.executable | wildcard |
| field:"Image" kind:wildcard |
process.name | wildcard |
| field:"process_basename" kind:wildcard |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
Effective_process.executable | eq | /Applications/Docker.app/Contents/MacOS/Docker | excludes:Effective_process.executable field:"Effective_process.executable" value:"/Applications/Docker.app/Contents/MacOS/Docker" |
UAC Bypass via DiskCleanup Scheduled Task Hijack
#Identifies User Account Control (UAC) bypass via hijacking DiskCleanup Scheduled Task. Attackers bypass UAC to stealthily execute code with elevated permissions.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Execution | |
| Privilege Escalation |
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
[metadata]
creation_date = "2020/08/18"
integration = ["endpoint", "windows", "system", "m365_defender", "sentinel_one_cloud_funnel", "crowdstrike"]
maturity = "production"
updated_date = "2026/05/04"
[rule]
author = ["Elastic"]
description = """
Identifies User Account Control (UAC) bypass via hijacking DiskCleanup Scheduled Task. Attackers bypass UAC to
stealthily execute code with elevated permissions.
"""
from = "now-9m"
index = [
"endgame-*",
"logs-crowdstrike.fdr*",
"logs-endpoint.events.process-*",
"logs-m365_defender.event-*",
"logs-sentinel_one_cloud_funnel.*",
"logs-system.security*",
"logs-windows.forwarded*",
"logs-windows.sysmon_operational-*",
"winlogbeat-*",
]
language = "eql"
license = "Elastic License v2"
name = "UAC Bypass via DiskCleanup Scheduled Task Hijack"
note = """## Triage and analysis
> **Disclaimer**:
> This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs.
### Investigating UAC Bypass via DiskCleanup Scheduled Task Hijack
User Account Control (UAC) is a security feature in Windows that helps prevent unauthorized changes. Adversaries may exploit the DiskCleanup Scheduled Task to bypass UAC, executing code with elevated privileges. The detection rule identifies suspicious processes using specific arguments and executables not matching known safe paths, flagging potential UAC bypass attempts for further investigation.
### Possible investigation steps
- Review the process details to confirm the presence of suspicious arguments "/autoclean" and "/d" in the process execution.
- Verify the executable path of the process to ensure it does not match known safe paths such as "C:\\Windows\\System32\\cleanmgr.exe" or "C:\\Windows\\SysWOW64\\cleanmgr.exe".
- Investigate the parent process to determine how the suspicious process was initiated and assess if it was triggered by a legitimate application or script.
- Check the user account under which the process was executed to identify if it aligns with expected user behavior or if it indicates potential compromise.
- Analyze recent system changes or scheduled tasks to identify any unauthorized modifications that could facilitate UAC bypass.
- Correlate the event with other security alerts or logs from data sources like Microsoft Defender XDR or Sysmon to gather additional context on the activity.
- Assess the risk and impact of the event by considering the severity and risk score, and determine if further containment or remediation actions are necessary.
### False positive analysis
- Legitimate system maintenance tools or scripts may trigger the rule if they use similar arguments and executables not listed in the safe paths. Review the process origin and context to determine if it is part of routine maintenance.
- Custom administrative scripts that automate disk cleanup tasks might be flagged. Verify the script's source and purpose, and consider adding it to an exception list if it is deemed safe.
- Software updates or installations that temporarily use disk cleanup functionalities could be misidentified. Monitor the timing and context of these events, and exclude known update processes from the rule.
- Third-party disk management tools that mimic or extend Windows disk cleanup features may cause alerts. Validate the tool's legitimacy and add it to the exclusion list if it is a trusted application.
- Scheduled tasks created by IT departments for system optimization might match the rule's criteria. Confirm the task's legitimacy and adjust the rule to exclude these specific tasks if they are verified as non-threatening.
### Response and remediation
- Immediately isolate the affected system from the network to prevent further unauthorized access or lateral movement by the adversary.
- Terminate any suspicious processes identified by the detection rule that are not using the legitimate DiskCleanup executables.
- Conduct a thorough review of scheduled tasks on the affected system to identify and remove any unauthorized or malicious tasks that may have been created or modified.
- Restore any altered system files or configurations to their original state using known good backups or system restore points.
- Update and patch the affected system to the latest security updates to mitigate any known vulnerabilities that could be exploited for UAC bypass.
- Monitor the affected system and network for any signs of recurring unauthorized activity or similar UAC bypass attempts.
- Escalate the incident to the security operations center (SOC) or incident response team for further analysis and to determine if additional systems are affected."""
risk_score = 47
rule_id = "1dcc51f6-ba26-49e7-9ef4-2655abb2361e"
severity = "medium"
tags = [
"Domain: Endpoint",
"OS: Windows",
"Use Case: Threat Detection",
"Tactic: Privilege Escalation",
"Tactic: Defense Evasion",
"Tactic: Execution",
"Data Source: Elastic Endgame",
"Data Source: Elastic Defend",
"Data Source: Windows Security Event Logs",
"Data Source: Microsoft Defender XDR",
"Data Source: Sysmon",
"Data Source: SentinelOne",
"Data Source: Crowdstrike",
"Resources: Investigation Guide",
]
timestamp_override = "event.ingested"
type = "eql"
query = '''
process where host.os.type == "windows" and event.type == "start" and
process.args : "/autoclean" and process.args : "/d" and process.executable != null and
not process.executable : (
"C:\\Windows\\System32\\cleanmgr.exe",
"C:\\Windows\\SysWOW64\\cleanmgr.exe",
"C:\\Windows\\System32\\taskhostw.exe",
/* Crowdstrike specific exclusion as it uses NT Object paths */
"\\Device\\HarddiskVolume*\\Windows\\System32\\cleanmgr.exe",
"\\Device\\HarddiskVolume*\\Windows\\SysWOW64\\cleanmgr.exe",
"\\Device\\HarddiskVolume*\\Windows\\System32\\taskhostw.exe"
)
'''
setup = """## Setup
This rule is designed for data generated by [Elastic Defend](https://www.elastic.co/security/endpoint-security), which provides native endpoint detection and response, along with event enrichments designed to work with our detection rules.
Setup instructions: https://ela.st/install-elastic-defend
### Additional data sources
This rule also supports the following third-party data sources. For setup instructions, refer to the links below:
- [CrowdStrike](https://ela.st/crowdstrike-integration)
- [Microsoft Defender XDR](https://ela.st/m365-defender)
- [SentinelOne Cloud Funnel](https://ela.st/sentinel-one-cloud-funnel)
- [Sysmon Event ID 1 - Process Creation](https://ela.st/sysmon-event-1-setup)
- [Windows Process Creation Logs](https://ela.st/audit-process-creation)
"""
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1548"
name = "Abuse Elevation Control Mechanism"
reference = "https://attack.mitre.org/techniques/T1548/"
[[rule.threat.technique.subtechnique]]
id = "T1548.002"
name = "Bypass User Account Control"
reference = "https://attack.mitre.org/techniques/T1548/002/"
[rule.threat.tactic]
id = "TA0004"
name = "Privilege Escalation"
reference = "https://attack.mitre.org/tactics/TA0004/"
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1548"
name = "Abuse Elevation Control Mechanism"
reference = "https://attack.mitre.org/techniques/T1548/"
[[rule.threat.technique.subtechnique]]
id = "T1548.002"
name = "Bypass User Account Control"
reference = "https://attack.mitre.org/techniques/T1548/002/"
[rule.threat.tactic]
id = "TA0005"
name = "Defense Evasion"
reference = "https://attack.mitre.org/tactics/TA0005/"
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1053"
name = "Scheduled Task/Job"
reference = "https://attack.mitre.org/techniques/T1053/"
[[rule.threat.technique.subtechnique]]
id = "T1053.005"
name = "Scheduled Task"
reference = "https://attack.mitre.org/techniques/T1053/005/"
[rule.threat.tactic]
id = "TA0002"
name = "Execution"
reference = "https://attack.mitre.org/tactics/TA0002/"
Stages and Predicates
Stage 1: process
process where host.os.type == "windows" and event.type == "start" and
process.args : "/autoclean" and process.args : "/d" and process.executable != null and
not process.executable : (
"C:\\Windows\\System32\\cleanmgr.exe",
"C:\\Windows\\SysWOW64\\cleanmgr.exe",
"C:\\Windows\\System32\\taskhostw.exe",
"\\Device\\HarddiskVolume*\\Windows\\System32\\cleanmgr.exe",
"\\Device\\HarddiskVolume*\\Windows\\SysWOW64\\cleanmgr.exe",
"\\Device\\HarddiskVolume*\\Windows\\System32\\taskhostw.exe"
)
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
event.type | eq |
| field:"event.type" kind:eq value:"start" |
process.args | wildcard |
| field:"process.args" kind:wildcard |
process.executable | is_not_null | field:"Image" kind:is_not_null |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
process.executable | wildcard | C:\Windows\System32\cleanmgr.exe, C:\Windows\SysWOW64\cleanmgr.exe, C:\Windows\System32\taskhostw.exe, \Device\HarddiskVolume*\Windows\System32\cleanmgr.exe, \Device\HarddiskVolume*\Windows\SysWOW64\cleanmgr.exe, \Device\HarddiskVolume*\Windows\System32\taskhostw.exe | excludes:process.executable |
VirtualProtect via Vectored Exception Handling
#Identifies suspicious memory intrusion events originating from an exception handler. This may be the result of an evasion attempt to evade memory scanners while performing malicious code injection.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Stealth |
Rule Body
[rule]
description = """
Identifies suspicious memory intrusion events originating from an exception handler. This may be the result of an
evasion attempt to evade memory scanners while performing malicious code injection.
"""
id = "20b374bd-2288-48f1-ad70-fa498e69e164"
license = "Elastic License v2"
name = "VirtualProtect via Vectored Exception Handling"
os_list = ["windows"]
reference = ["https://github.com/lem0nSec/ShellGhost"]
version = "1.0.5"
query = '''
api where process.Ext.api.behaviors : ("execute_fluctuation", "hollow_unbacked") and
process.Ext.api.name == "VirtualProtect" and
/* an exception call stack pattern to match before the full arraysearch */
process.thread.Ext.call_stack_summary: "ntdll.dll|*|ntdll.dll|*" and
/* provenance metadata exists */
process.thread.Ext.call_stack_final_user_module.code_signature != null and
/* abusing exception handlers for proxying memory manip */
_arraysearch(process.thread.Ext.call_stack, $entry, $entry.symbol_info: "*ntdll.dll!KiUserExceptionDispatcher*") and
/* final user module is unsigned or signed with an untrusted code signature */
_arraysearch(process.thread.Ext.call_stack_final_user_module.code_signature, $entry, $entry.trusted == false or $entry.exists == false) and
not process.thread.Ext.call_stack_final_user_module.hash.sha256 :
("fdb0c7af2ab2e821787222517531068ad01e333fe91e54d59bb80a8f49eb0bec",
"e4a0aa2bb7e9003d1f436e1fcc783c4949f38e24d0d9b960ae9411609fe9c0a6",
"03a8cfcb10a61492b540734147888867f43e501322e17202bca8bfb4065197a7",
"db1bb8b11da98f97a9dcd58d4c204d82c0c059a45e54c13f59ef8a6cc84549fc",
"417f8e95cffbb97dba4ebc9f0c8dd226bc915314738431caeec0dc879a704794",
"ff9fbf4db360272b8350b5f1e3a827c7fbd12ce07b1728ad9407a61440f15d96",
"d55b376190b15b61f4c74a3cad999b1e8f083201306d0258053a00c30d29990c",
"6bb9e06812826df9539a9300e96c8b2c0281c7c3d566f5ce332d2dcfa6f1808f")
'''
min_endpoint_version = "8.10.0"
[[actions]]
action = "kill_process"
field = "process.entity_id"
state = 0
[[optional_actions]]
action = "rollback"
field = "process.entity_id"
state = 0
[[threat]]
framework = "MITRE ATT&CK"
[[threat.technique]]
id = "T1055"
name = "Process Injection"
reference = "https://attack.mitre.org/techniques/T1055/"
[threat.tactic]
id = "TA0005"
name = "Defense Evasion"
reference = "https://attack.mitre.org/tactics/TA0005/"
[internal]
min_endpoint_version = "8.10.0"
Stages and Predicates
Stage 1: api
api where process.Ext.api.behaviors : ("execute_fluctuation", "hollow_unbacked") and
process.Ext.api.name == "VirtualProtect" and
process.thread.Ext.call_stack_summary: "ntdll.dll|*|ntdll.dll|*" and
process.thread.Ext.call_stack_final_user_module.code_signature != null and
_arraysearch(process.thread.Ext.call_stack, $entry, $entry.symbol_info: "*ntdll.dll!KiUserExceptionDispatcher*") and
_arraysearch(process.thread.Ext.call_stack_final_user_module.code_signature, $entry, $entry.trusted == false or $entry.exists == false) and
not process.thread.Ext.call_stack_final_user_module.hash.sha256 :
("fdb0c7af2ab2e821787222517531068ad01e333fe91e54d59bb80a8f49eb0bec",
"e4a0aa2bb7e9003d1f436e1fcc783c4949f38e24d0d9b960ae9411609fe9c0a6",
"03a8cfcb10a61492b540734147888867f43e501322e17202bca8bfb4065197a7",
"db1bb8b11da98f97a9dcd58d4c204d82c0c059a45e54c13f59ef8a6cc84549fc",
"417f8e95cffbb97dba4ebc9f0c8dd226bc915314738431caeec0dc879a704794",
"ff9fbf4db360272b8350b5f1e3a827c7fbd12ce07b1728ad9407a61440f15d96",
"d55b376190b15b61f4c74a3cad999b1e8f083201306d0258053a00c30d29990c",
"6bb9e06812826df9539a9300e96c8b2c0281c7c3d566f5ce332d2dcfa6f1808f")
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
process.Ext.api.behaviors | wildcard |
| field:"process.Ext.api.behaviors" kind:wildcard |
process.Ext.api.name | eq |
| field:"process.Ext.api.name" kind:eq value:"VirtualProtect" |
process.thread.Ext.call_stack_final_user_module.code_signature | is_not_null | field:"process.thread.Ext.call_stack_final_user_module.code_signature" kind:is_not_null | |
process.thread.Ext.call_stack_summary | wildcard |
| field:"process.thread.Ext.call_stack_summary" kind:wildcard value:"ntdll.dll|*|ntdll.dll|*" |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
process.thread.Ext.call_stack_final_user_module.hash.sha256 | eq | fdb0c7af2ab2e821787222517531068ad01e333fe91e54d59bb80a8f49eb0bec, e4a0aa2bb7e9003d1f436e1fcc783c4949f38e24d0d9b960ae9411609fe9c0a6, 03a8cfcb10a61492b540734147888867f43e501322e17202bca8bfb4065197a7, db1bb8b11da98f97a9dcd58d4c204d82c0c059a45e54c13f59ef8a6cc84549fc, 417f8e95cffbb97dba4ebc9f0c8dd226bc915314738431caeec0dc879a704794, ff9fbf4db360272b8350b5f1e3a827c7fbd12ce07b1728ad9407a61440f15d96, d55b376190b15b61f4c74a3cad999b1e8f083201306d0258053a00c30d29990c, 6bb9e06812826df9539a9300e96c8b2c0281c7c3d566f5ce332d2dcfa6f1808f | excludes:process.thread.Ext.call_stack_final_user_module.hash.sha256 |