diff --git a/rules/cross-platform/execution_command_interpreter_spawned_by_obsidian.toml b/rules/cross-platform/execution_command_interpreter_spawned_by_obsidian.toml new file mode 100644 index 00000000000..47194b14b40 --- /dev/null +++ b/rules/cross-platform/execution_command_interpreter_spawned_by_obsidian.toml @@ -0,0 +1,196 @@ +[metadata] +creation_date = "2026/06/20" +integration = ["endpoint"] +maturity = "production" +updated_date = "2026/06/20" + +[rule] +author = ["Aryu-RU"] +description = """ +Identifies the Obsidian note-taking application spawning a command or script interpreter, such as PowerShell or a Unix +shell. Obsidian has no built-in need to launch interpreters on its own, and this behavior is characteristic of the +Obsidian "Shell Commands" community plugin (`obsidian-shellcommands`) being abused to auto-execute attacker-supplied +commands when a weaponized vault is opened, as observed in the PhantomPulse (REF6598) campaign. +""" +false_positives = [ + """ + The Obsidian "Shell Commands" community plugin can be used legitimately to run user-defined commands, which causes + Obsidian to spawn an interpreter as designed. PowerShell, pwsh, and osascript children are matched directly; + validate the commands configured in the plugin's data.json and add exceptions for trusted users or hosts. + """, + """ + A legitimate Shell Commands configuration that shells out to a download or scripting utility (for example, fetching + notes over HTTP) can match the argument-based conditions on cmd or a Unix shell. Review the child process command + line and the destination, and exclude known-good plugin activity. + """, +] +from = "now-9m" +index = ["logs-endpoint.events.process-*"] +language = "eql" +license = "Elastic License v2" +name = "Command Interpreter Spawned by Obsidian" +note = """## Triage and analysis + +### Investigating Command Interpreter Spawned by Obsidian + +Obsidian is a Markdown note-taking application that does not natively execute shell commands. The only common way for +Obsidian to spawn an interpreter is through a community plugin, most notably the "Shell Commands" plugin +(`obsidian-shellcommands`), which can be configured to run arbitrary commands automatically when a vault is opened. In +the PhantomPulse campaign, a victim was socially engineered into logging into an attacker-controlled Obsidian Sync vault +and enabling community plugin sync, which pulled down a weaponized configuration that launched a PowerShell download +cradle on vault open. + +### Possible investigation steps + +- Confirm the parent is the legitimate, signed Obsidian binary by reviewing its code signature and hash, and identify + the user and host context of the execution. +- Review the child process command line for download-and-execute behavior, such as `Invoke-WebRequest`/`iwr`, + `Start-BitsTransfer`, `curl`, base64 or `-EncodedCommand`, `-ExecutionPolicy Bypass`, and `-WindowStyle Hidden` on + Windows, or `do shell script` and base64-decoded payloads launched via `osascript` on macOS. +- Inspect the vault's plugin configuration at `.obsidian/plugins/obsidian-shellcommands/data.json` and + `.obsidian/community-plugins.json` for attacker-defined commands and recently enabled plugins. +- Correlate surrounding network telemetry from the child process to identify connections to staging or command and + control infrastructure, and assess the reputation of any contacted IPs or domains. +- On macOS, check `~/Library/LaunchAgents/` for newly created property list files that establish persistence. + +### False positive analysis + +- The Obsidian "Shell Commands" community plugin can run user-defined commands legitimately, which will cause Obsidian + to spawn an interpreter. Validate the commands configured in the plugin's `data.json` and add exceptions for trusted + users or hosts. +- Other community plugins that shell out to local tooling can spawn an interpreter during normal use. Review the child + process command line and exclude known-good plugin activity. + +### Response and remediation + +- Terminate the interpreter process and any follow-on processes, and isolate the host if a payload was retrieved or + executed. +- Disable or remove the malicious Obsidian plugin configuration (`obsidian-shellcommands` data.json) and any unexpected + community plugins, and turn off community plugin sync for the affected vault. +- Remove dropped artifacts and persistence (for example, files staged in the user temp directory or macOS LaunchAgents), + and block the observed staging/command and control indicators at the firewall and DNS layers. +- Rotate any credentials that were entered into, or accessible from, the compromised host. +""" +references = [ + "https://www.elastic.co/security-labs/phantom-in-the-vault", + "https://github.com/Taitava/obsidian-shellcommands", + "https://attack.mitre.org/techniques/T1059/", + "https://attack.mitre.org/techniques/T1204/002/", +] +risk_score = 47 +rule_id = "8fed0d43-cf06-47c3-a5b8-11f1179d5000" +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 +""" +severity = "medium" +tags = [ + "Domain: Endpoint", + "OS: Windows", + "OS: macOS", + "Use Case: Threat Detection", + "Tactic: Execution", + "Data Source: Elastic Defend", + "Resources: Investigation Guide", +] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and + ( + /* Windows: Obsidian launching PowerShell is the documented PhantomPulse behavior and is + strongly anomalous on its own; cmd.exe is gated behind download/execution arguments to + suppress benign community-plugin shell-outs. */ + ( + host.os.type == "windows" and + process.parent.name : "Obsidian.exe" and + ( + process.name : ("powershell.exe", "pwsh.exe") or + ( + process.name : "cmd.exe" and + process.command_line : ( + "*http*", "*curl*", "*certutil*", "*bitsadmin*", "*powershell*", + "*mshta*", "*rundll32*", "*regsvr32*", "*wscript*", "*cscript*", + "*-enc*", "*base64*" + ) + ) + ) + ) or + /* macOS: Obsidian launching osascript is the documented AppleScript vector; bare shells are + gated behind download/decode arguments. */ + ( + host.os.type == "macos" and + process.parent.name : "Obsidian" and + ( + process.name : "osascript" or + ( + process.name : ("sh", "bash", "zsh") and + process.command_line : ( + "*http*", "*curl*", "*wget*", "*nscurl*", "*base64*", "*osascript*", "*/dev/tcp*" + ) + ) + ) + ) + ) +''' + + +[[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.001" +name = "PowerShell" +reference = "https://attack.mitre.org/techniques/T1059/001/" + +[[rule.threat.technique.subtechnique]] +id = "T1059.002" +name = "AppleScript" +reference = "https://attack.mitre.org/techniques/T1059/002/" + +[[rule.threat.technique.subtechnique]] +id = "T1059.003" +name = "Windows Command Shell" +reference = "https://attack.mitre.org/techniques/T1059/003/" + +[[rule.threat.technique.subtechnique]] +id = "T1059.004" +name = "Unix Shell" +reference = "https://attack.mitre.org/techniques/T1059/004/" + + +[[rule.threat.technique]] +id = "T1204" +name = "User Execution" +reference = "https://attack.mitre.org/techniques/T1204/" +[[rule.threat.technique.subtechnique]] +id = "T1204.002" +name = "Malicious File" +reference = "https://attack.mitre.org/techniques/T1204/002/" + + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + +[rule.investigation_fields] +field_names = [ + "host.os.type", + "user.name", + "process.parent.name", + "process.parent.executable", + "process.name", + "process.executable", + "process.command_line", +] +