diff --git a/rules/macos/credential_access_python_sensitive_file_access_first_occurrence.toml b/rules/macos/credential_access_python_sensitive_file_access_first_occurrence.toml new file mode 100644 index 000000000..26ee109c5 --- /dev/null +++ b/rules/macos/credential_access_python_sensitive_file_access_first_occurrence.toml @@ -0,0 +1,95 @@ +[metadata] +creation_date = "2026/02/23" +integration = ["endpoint"] +maturity = "production" +updated_date = "2026/02/23" + +[rule] +author = ["Elastic"] +description = """ +Detects the first time a Python process accesses sensitive credential files on a given host. This behavior may indicate +post-exploitation credential theft via a malicious Python script, compromised dependency, or malicious model file +deserialization. Legitimate Python processes do not typically access credential files such as SSH keys, AWS credentials, +browser cookies, Kerberos tickets, or keychain databases, so a first occurrence is a strong indicator of compromise. +""" +from = "now-9m" +index = ["logs-endpoint.events.file-*"] +language = "kuery" +license = "Elastic License v2" +name = "First Time Python Accessed Sensitive Credential Files" +note = """## Triage and analysis + +### Investigating First Time Python Accessed Sensitive Credential Files + +Attackers who achieve Python code execution — whether through malicious scripts, compromised dependencies, or model file deserialization (e.g., pickle/PyTorch `__reduce__`) — often target sensitive credential files such as SSH keys, cloud provider credentials, browser session cookies, and macOS keychain data. Since legitimate Python processes do not typically access these files, a first occurrence from a Python process is highly suspicious. + +This rule leverages the Elastic Defend sensitive file `open` event, which is only collected for known sensitive file paths, combined with the New Terms rule type to alert on the first time a specific credential file is accessed by Python on a given host within a 7-day window. + +### Possible investigation steps + +- Examine the Python process command line and arguments to identify the script or command that triggered the file access. +- Determine if the Python process was loading a model file (look for `torch.load`, `pickle.load`), running a standalone script, or executing via a compromised dependency. +- Review the specific credential file that was accessed and assess the potential impact (SSH keys enable lateral movement, AWS credentials enable cloud access, browser cookies enable session hijacking). +- Check for outbound network connections from the same process tree that may indicate credential exfiltration. +- Investigate the origin of any recently downloaded scripts, packages, or model files on the host. +- Look for file creation events in `/tmp/` or other staging directories that may contain copies of the stolen credentials. + +### False positive analysis + +- Python-based secret management tools (e.g., `aws-cli`, `gcloud`) legitimately access credential files. Consider excluding known trusted executables by process path. +- SSH automation scripts using `paramiko` or `fabric` may read SSH keys. Evaluate whether the access pattern matches known automation workflows. +- Security scanning tools running Python may enumerate credential files as part of their assessment. + +### Response and remediation + +- Immediately rotate any credentials that were potentially accessed (SSH keys, AWS access keys, cloud tokens). +- Quarantine the Python process and investigate the source script, package, or model file that triggered the access. +- If a malicious file is confirmed, identify all hosts where it may have been distributed. +- Review outbound network connections from the host around the time of the credential access to check for exfiltration. +- Consider implementing `weights_only=True` enforcement for PyTorch model loading across the environment. +""" +references = [ + "https://blog.trailofbits.com/2024/06/11/exploiting-ml-models-with-pickle-file-attacks-part-1/", + "https://github.com/trailofbits/fickling", +] +risk_score = 47 +rule_id = "03b150d9-9280-4eb8-9906-38cfb6184666" +severity = "medium" +tags = [ + "Domain: Endpoint", + "OS: macOS", + "Use Case: Threat Detection", + "Tactic: Credential Access", + "Data Source: Elastic Defend", + "Resources: Investigation Guide", + "Domain: LLM", +] +timestamp_override = "event.ingested" +type = "new_terms" +query = ''' +event.category:file and host.os.type:macos and event.action:open and +process.name:python* +''' + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1555" +name = "Credentials from Password Stores" +reference = "https://attack.mitre.org/techniques/T1555/" +[[rule.threat.technique.subtechnique]] +id = "T1555.001" +name = "Keychain" +reference = "https://attack.mitre.org/techniques/T1555/001/" + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + +[rule.new_terms] +field = "new_terms_fields" +value = ["host.id", "file.path"] +[[rule.new_terms.history_window_start]] +field = "history_window_start" +value = "now-7d" diff --git a/rules/macos/execution_python_shell_spawn_first_occurrence.toml b/rules/macos/execution_python_shell_spawn_first_occurrence.toml new file mode 100644 index 000000000..6da50e09b --- /dev/null +++ b/rules/macos/execution_python_shell_spawn_first_occurrence.toml @@ -0,0 +1,98 @@ +[metadata] +creation_date = "2026/02/23" +integration = ["endpoint"] +maturity = "production" +updated_date = "2026/02/23" + +[rule] +author = ["Elastic"] +description = """ +Detects the first time a Python process spawns a shell on a given host. Malicious Python scripts, compromised +dependencies, or model file deserialization can result in shell spawns that would not occur during normal workflows. +Since legitimate Python processes rarely shell out to interactive shells, a first occurrence of this behavior on a +host is a strong signal of potential compromise. +""" +from = "now-9m" +index = ["logs-endpoint.events.process-*"] +language = "kuery" +license = "Elastic License v2" +name = "First Time Python Spawned a Shell on Host" +note = """## Triage and analysis + +### Investigating First Time Python Spawned a Shell on Host + +Attackers who achieve Python code execution — whether through malicious scripts, compromised dependencies, or model file deserialization (e.g., pickle/PyTorch `__reduce__`) — often spawn shell processes to perform reconnaissance, credential theft, persistence, or reverse shell activity. Since legitimate Python workflows rarely shell out with `-c`, a first occurrence is highly suspicious. + +This rule uses the New Terms rule type to detect the first occurrence of a Python process spawning a shell with the `-c` flag on a given host within a 7-day window. This approach reduces false positives from recurring legitimate Python workflows while surfacing novel, potentially malicious activity. + +### Possible investigation steps + +- Examine the parent Python process command line to identify the script or command that triggered the shell spawn. +- Determine if the Python process was loading a model file (look for `torch.load`, `pickle.load`), running a standalone script, or executing via a compromised dependency. +- Review the shell command arguments to assess intent (credential access, reverse shell, persistence, reconnaissance). +- Inspect the full process tree to determine if the Python process was launched from an interactive session, a cron job, or an automated pipeline. +- Investigate the origin of any recently downloaded scripts, packages, or model files on the host. +- Correlate with other hosts in the environment to determine if the same behavior is occurring elsewhere, which may indicate a supply chain compromise. + +### False positive analysis + +- Development environments where Python scripts legitimately shell out for system tasks (e.g., build scripts, CI/CD runners) may trigger this rule on first occurrence. Consider excluding known CI/CD working directories or build automation paths. +- Package installation via pip or conda may spawn shells during post-install scripts. These are excluded by the query filter. +- Jupyter notebooks executing system commands via `!` or `subprocess` may trigger this rule in data science environments. + +### Response and remediation + +- Investigate the shell command that was executed and assess its impact (credential access, persistence, data exfiltration). +- If a malicious file is confirmed, quarantine it and identify its source (PyPI, Hugging Face, shared drive, email attachment). +- Scan other hosts that may have received the same file. +- Review and rotate any credentials that may have been accessed. +- Consider implementing `weights_only=True` enforcement for PyTorch model loading across the environment. +""" +references = [ + "https://blog.trailofbits.com/2024/06/11/exploiting-ml-models-with-pickle-file-attacks-part-1/", + "https://github.com/trailofbits/fickling", + "https://5stars217.github.io/2024-03-04-what-enables-malicious-models/", +] +risk_score = 47 +rule_id = "92a36c98-b24a-4bf7-aac7-1eac71fa39cf" +severity = "medium" +tags = [ + "Domain: Endpoint", + "OS: macOS", + "Use Case: Threat Detection", + "Tactic: Execution", + "Data Source: Elastic Defend", + "Resources: Investigation Guide", + "Domain: LLM", +] +timestamp_override = "event.ingested" +type = "new_terms" +query = ''' +event.category:process and host.os.type:macos and event.type:start and event.action:exec and +process.parent.name:python* and +process.name:(bash or dash or sh or tcsh or csh or zsh or ksh or fish) and process.args:"-c" and +not process.command_line:(*pip* or *conda* or *brew* or *jupyter*) +''' + +[[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.006" +name = "Python" +reference = "https://attack.mitre.org/techniques/T1059/006/" + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + +[rule.new_terms] +field = "new_terms_fields" +value = ["host.id", "process.parent.executable"] +[[rule.new_terms.history_window_start]] +field = "history_window_start" +value = "now-7d" diff --git a/rules/macos/persistence_python_launch_agent_or_daemon_creation_first_occurrence.toml b/rules/macos/persistence_python_launch_agent_or_daemon_creation_first_occurrence.toml new file mode 100644 index 000000000..2c5cd8c46 --- /dev/null +++ b/rules/macos/persistence_python_launch_agent_or_daemon_creation_first_occurrence.toml @@ -0,0 +1,95 @@ +[metadata] +creation_date = "2026/02/23" +integration = ["endpoint"] +maturity = "production" +updated_date = "2026/02/23" + +[rule] +author = ["Elastic"] +description = """ +Detects the first time a Python process creates or modifies a LaunchAgent or LaunchDaemon plist file on a given host. +Malicious Python scripts, compromised dependencies, or model file deserialization can establish persistence on macOS by +writing plist files to LaunchAgent or LaunchDaemon directories. Legitimate Python processes do not typically create +persistence mechanisms, so a first occurrence is a strong indicator of compromise. +""" +from = "now-9m" +index = ["logs-endpoint.events.persistence-*"] +language = "kuery" +license = "Elastic License v2" +name = "First Time Python Created a LaunchAgent or LaunchDaemon" +note = """## Triage and analysis + +### Investigating First Time Python Created a LaunchAgent or LaunchDaemon + +macOS LaunchAgents and LaunchDaemons are plist files that configure programs to run automatically at login or boot. Attackers who achieve Python code execution — whether through malicious scripts, compromised dependencies, or model file deserialization (e.g., pickle/PyTorch `__reduce__`) — can drop plist files to establish persistence on the compromised host. This ensures their payload survives reboots and user logouts. + +This rule uses the Elastic Defend persistence event type (`event.action:"launch_daemon"`), which captures plist metadata including the program arguments, run-at-load configuration, and keep-alive settings. The New Terms rule type alerts on the first time a Python process creates a LaunchAgent or LaunchDaemon on a given host within a 7-day window. + +### Possible investigation steps + +- Review the persistence event fields (`Persistence.runatload`, `Persistence.keepalive`, `Persistence.args`, `Persistence.path`) to understand the plist configuration. +- Examine the program path and arguments specified in the plist to determine if they reference a known legitimate application or a suspicious binary. +- Determine if the Python process was loading a model file (look for `torch.load`, `pickle.load`), running a standalone script, or executing via a compromised dependency. +- Verify if the target binary referenced in the plist exists on disk and whether it is signed or trusted. +- Investigate the origin of any recently downloaded scripts, packages, or model files on the host. +- Check for other persistence mechanisms that may have been established around the same time. + +### False positive analysis + +- Some Python-based system management tools (e.g., Ansible, SaltStack) may legitimately create LaunchAgent or LaunchDaemon plist files. Evaluate whether the activity matches a known automation workflow. +- Python-based application installers may create plist files during setup. Check if the activity correlates with a known software installation. + +### Response and remediation + +- Immediately unload the suspicious LaunchAgent or LaunchDaemon using `launchctl unload` with the plist path. +- Remove the suspicious plist file and any associated binary it references. +- Kill any processes launched by the plist file. +- Investigate and quarantine the Python script, package, or model file that created the persistence mechanism. +- Scan the host for additional indicators of compromise. +- If a malicious file is confirmed, identify all hosts where it may have been distributed. +""" +references = [ + "https://blog.trailofbits.com/2024/06/11/exploiting-ml-models-with-pickle-file-attacks-part-1/", + "https://github.com/trailofbits/fickling", +] +risk_score = 47 +rule_id = "25368123-b7b8-4344-9fd4-df28051b4c6e" +severity = "medium" +tags = [ + "Domain: Endpoint", + "OS: macOS", + "Use Case: Threat Detection", + "Tactic: Persistence", + "Data Source: Elastic Defend", + "Resources: Investigation Guide", + "Domain: LLM", +] +timestamp_override = "event.ingested" +type = "new_terms" +query = ''' +host.os.type:macos and event.action:"launch_daemon" and +process.name:python* +''' + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1543" +name = "Create or Modify System Process" +reference = "https://attack.mitre.org/techniques/T1543/" +[[rule.threat.technique.subtechnique]] +id = "T1543.001" +name = "Launch Agent" +reference = "https://attack.mitre.org/techniques/T1543/001/" + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + +[rule.new_terms] +field = "new_terms_fields" +value = ["host.id", "file.path"] +[[rule.new_terms.history_window_start]] +field = "history_window_start" +value = "now-7d"