PhantomVault — PHANTOMPULSE Blockchain-C2 RAT via Obsidian
Executive Summary
PhantomVault (Elastic Security Labs intrusion set REF6598) deploys PHANTOMPULSE, a modular remote-access trojan, by abusing the trusted Obsidian markdown note-taking application. The actor places a malicious DLL alongside the legitimate, signed Obsidian executable so that launching Obsidian side-loads the attacker DLL (DLL search-order hijack) — the signed app provides cover, and the malicious code runs inside a trusted process.
PHANTOMPULSE's most notable trait is blockchain-based C2 resolution: instead of hard-coding a C2 server, the implant reads its current C2 / next-stage configuration from data stored on a public blockchain (smart contract / on-chain payload, EtherHiding-style). This makes the C2 cheap to rotate and extremely resilient to takedown — there is no single domain or IP to sinkhole. Once resolved, the RAT performs command execution, file operations, staging, and exfiltration over standard web protocols.
Source Review & Web Hunter Notes
| Tier | Source | Key Finding | Carry |
|---|---|---|---|
| 1 · Vendor research | Elastic Security Labs — REF6598 / PHANTOMPULSE | Obsidian DLL side-load; modular RAT; blockchain-based C2 resolution | yes |
| 2 · Technique | EtherHiding / on-chain C2 reporting (Google/Mandiant) | Blockchain smart contracts as resilient, takedown-resistant C2/payload stores | yes |
| 2 · Technique | DLL search-order hijack literature (MITRE T1574.001/.002) | Side-loading trusted apps to run malicious DLLs under cover | partial |
Decisions: behavior-first because there is no stable C2 atom (on-chain resolver); anchor on the Obsidian side-load (trusted-process cover) and the blockchain-RPC egress from a non-wallet process; treat smart-contract/wallet-RPC reachability from servers/workstations without a business need as anomalous; module hashes rotate, so the side-load + resolver chain is the durable surface.
Hunt Brief & Attack Chain
Working hypothesis: The actor stages a malicious DLL next to a legitimate Obsidian install (or a portable copy); launching Obsidian side-loads it, spawning PHANTOMPULSE, which resolves C2 from a blockchain smart contract and then runs hands-on RAT operations.
| Step | Behavior | Telemetry | Hunt Angle |
|---|---|---|---|
| 1 · Delivery | Trojanized/portable Obsidian + malicious DLL staged to a user path | file; ProcessRollup2 | Q2; N1 |
| 2 · Side-load | Obsidian.exe loads an unsigned/unexpected DLL | module load; ProcessRollup2 | Q1; N2 |
| 3 · PHANTOMPULSE | RAT runs inside the trusted process; spawns children | ProcessRollup2 | Q3 |
| 4 · C2 resolve | Reads C2 config from a blockchain RPC/gateway | NetworkConnectIP4; DNS | Q4; N3 |
| 5 · Persistence | Run key / scheduled task / startup to relaunch Obsidian chain | registry; task | Q5 |
| 6 · Actions | Exec, file ops, staging, exfil over web protocols | ProcessRollup2; net | Q3 / Q6 |
Affected surface & telemetry
| Surface | Required Telemetry | Priority | Gap Risk |
|---|---|---|---|
| Workstations (Obsidian users) | Module-load + process lineage | Critical | Medium — needs module-load telemetry |
| Egress | Proxy/DNS + netflow to blockchain RPC | High | Medium — on-chain resolver |
| Persistence | Run keys / scheduled tasks | Medium | Low |
| App inventory | Obsidian install locations + signatures | Medium | Medium — portable copies |
Consolidated IOC Table
| Type | Value | Conf | Action | Context |
|---|---|---|---|---|
| Behavior | Obsidian.exe loading an unsigned/unexpected DLL from a user path | high | detect | Side-load — flagship |
| Behavior | Blockchain RPC/gateway egress from a non-wallet process | medium | hunt | On-chain C2 resolve |
| Malware | PHANTOMPULSE modular RAT (runs inside Obsidian) | medium | hunt | Implant |
| Behavior | Persistence relaunching the Obsidian chain (Run key / task) | medium | hunt | Persistence |
| File | Portable/relocated Obsidian + sideloaded DLL outside Program Files | medium | hunt | Staging |
ATT&CK Mapping
| Tactic | Technique | Observed Behavior | Query / Control |
|---|---|---|---|
| Execution / Defense Evasion | T1574.002 — DLL side-loading | Obsidian side-loads a malicious DLL | Q1; N2 |
| Defense Evasion | T1036 — Masquerading (trusted-process cover) | RAT runs inside signed Obsidian | Q1, Q3 |
| Command & Control | T1071 / T1102 — Web service / dead-drop (blockchain) | C2 config resolved on-chain | Q4; N3 |
| Persistence | T1547.001 / T1053.005 — Run key / scheduled task | Relaunch of the Obsidian chain | Q5 |
| Execution | T1059 — Command/script interpreter | RAT spawns shells / tooling | Q3 |
| Collection / Exfil | T1005 / T1041 — Local data / C2 exfil | File ops + exfil over web | Q6 |
Native Audit-Log Hunts
| Hunt | Source | Logic | Response |
|---|---|---|---|
| N1 · Obsidian inventory | Software / file inventory | Obsidian installs outside the standard path; portable copies; unexpected sibling DLLs | Verify signature/origin |
| N2 · Side-load module load | Sysmon 7 (Image Load) / EDR | Obsidian.exe loading an unsigned DLL from a user-writable path | Isolate; pull the DLL |
| N3 · Blockchain-RPC egress | Proxy / DNS / netflow | Connections to public blockchain RPC/gateway nodes from non-wallet processes | Block; identify host |
| N4 · Persistence | Registry (Run) / Task Scheduler | Run keys / tasks pointing at an Obsidian copy in a user path | Remove; investigate |
CrowdStrike LogScale CQL Hunt Queries
ImageLoad/ClassifiedModuleLoad events — verify field names in your sensor schema. C2 is on-chain, so Q4 keys on blockchain-RPC reachability from a non-wallet process; maintain an allow-list of sanctioned crypto/wallet apps to suppress FPs.Looks for: Obsidian.exe loading a DLL from a user-writable path (the side-load). Accomplishes: catches the trusted-process cover. FP: low — Obsidian's own DLLs load from its install dir; tune to your module-load schema.
// HUNT: PHANTOMPULSE DLL side-load into Obsidian // MITRE: T1574.002, T1036 | CONF: high FP: low COST: low // FP NOTES: genuine Obsidian DLLs load from its install dir; flag user-path/unsigned #event_simpleName=/ImageLoad|ClassifiedModuleLoad|ModuleLoadFromMemory/ | FileName=/^Obsidian\.exe$/i | ImageFileName=/\\(Temp|AppData|Downloads|Users\\Public|ProgramData)\\.+\.dll$/i | table([@timestamp, ComputerName, UserName, FileName, ImageFileName, SHA256HashData], limit=200)
Looks for: Obsidian.exe running from a non-standard path (portable/relocated copy used for side-load staging). FP: some legit portable use — correlate to Q1.
// HUNT: Obsidian running from a non-standard (staging) path // MITRE: T1574.002 | CONF: medium FP: medium COST: low // TUNING: baseline legit Obsidian install paths; flag user/temp/download dirs; correlate to Q1 #event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/ | FileName=/^Obsidian\.exe$/i | ImageFileName=/\\(Temp|Downloads|Users\\Public|ProgramData)\\/i | table([@timestamp, ComputerName, UserName, ImageFileName, CommandLine], limit=200)
Looks for: Obsidian.exe (a note app) spawning shells/LOLBins/recon — abnormal for a markdown editor. Accomplishes: the RAT running inside the trusted process. FP: low — Obsidian rarely spawns cmd/powershell.
// HUNT: PHANTOMPULSE child execution from Obsidian // MITRE: T1059, T1036 | CONF: med-high FP: low-med COST: low // FP NOTES: a note app should not spawn cmd/powershell/recon tooling #event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/ | ParentBaseFileName=/^Obsidian\.exe$/i | FileName=/^(cmd|powershell|pwsh|wscript|cscript|rundll32|regsvr32|mshta|whoami|net|net1|nltest|curl)\.exe$/i | table([@timestamp, ComputerName, UserName, ParentBaseFileName, FileName, CommandLine], limit=200)
Looks for: DNS for public blockchain RPC/gateway providers from a process that is not a sanctioned wallet/crypto app (the on-chain C2 resolve). FP: medium — allow-list sanctioned crypto apps; tune the provider list to current intel.
// HUNT: on-chain C2 resolution via blockchain RPC/gateway // MITRE: T1102, T1071 | CONF: medium FP: medium COST: med // TUNING: allow-list sanctioned wallet/crypto apps; tune the provider domain list #event_simpleName=DnsRequest | DomainName=/(infura\.io|alchemy\.com|ankr\.com|bsc-dataseed|binance\.org|cloudflare-eth\.com|llamarpc\.com|publicnode\.com|quiknode\.pro|drpc\.org)/i | ContextBaseFileName!=/^(metamask|exodus|electrum|ledger.*|trust.*|coinbase.*)\.exe$/i | table([@timestamp, ComputerName, ContextBaseFileName, DomainName], limit=200)
Looks for: Run keys / scheduled tasks pointing at an Obsidian copy in a user/temp path. FP: low-med — legit Obsidian auto-start is from its install dir, not a temp path.
// HUNT: persistence relaunching the side-loaded Obsidian // MITRE: T1547.001, T1053.005 | CONF: med-high FP: low-med COST: low // TUNING: legit auto-start is from the install dir; flag user/temp-path Obsidian #event_simpleName=/AsepValueUpdate|ScheduledTaskRegistered|RegGenericValueUpdate/ | RegStringValue=/Obsidian\.exe/i | RegStringValue=/\\(Temp|AppData|Downloads|Users\\Public|ProgramData)\\/i | table([@timestamp, ComputerName, UserName, RegObjectName, RegStringValue], limit=200)
Looks for: outbound connections attributed to Obsidian.exe beyond its normal sync/update endpoints (RAT C2/exfil under cover). FP: medium — baseline Obsidian's legit sync/update hosts.
// HUNT: anomalous egress attributed to Obsidian.exe // MITRE: T1071, T1041 | CONF: medium FP: medium COST: med // TUNING: baseline Obsidian sync/update endpoints; flag the remainder #event_simpleName=NetworkConnectIP4 | ImageFileName=/\\Obsidian\.exe$/i | in(RemotePort, values=[443, 80, 8080, 8443]) | groupBy([ComputerName, RemoteAddressIP4, RemotePort], function=count()) | table([ComputerName, RemoteAddressIP4, RemotePort, _count], limit=200)
CrowdStrike Custom IOA Recommendations
| IOA Name | Field Patterns | Benign Exclusions | Deployment Path |
|---|---|---|---|
| PhantomVault — Obsidian side-load | Image load: Obsidian.exe + DLL from %Temp%/%AppData%/Downloads | Genuine Obsidian install dir (allow) | Endpoint Security → Custom IOA → Image Load, Detect+Block |
| PhantomVault — Obsidian spawns shell | Parent Obsidian.exe; Child cmd/powershell/rundll32 | None (note app should not) | Custom IOA → Process Creation, Detect+Block |
Machine-Readable IOC Appendix
Grouped IOC Quick-Copy
One-click blocks for detection. C2 is on-chain (no durable domain) — behavior is the surface. Add per-incident atoms (DLL hashes, contract/wallet addresses, resolved C2) during triage.
Obsidian.exe loading an unsigned/unexpected DLL from %Temp%/%AppData%/Downloads/ProgramData (side-load) Obsidian.exe running from a non-standard (user/temp/download) path Obsidian.exe spawning cmd/powershell/rundll32/recon tooling (a note app should not) DNS to public blockchain RPC/gateway from a non-wallet process (on-chain C2 resolve) Run key / scheduled task pointing at an Obsidian copy in a user/temp path Anomalous egress attributed to Obsidian.exe beyond its sync/update endpoints
PhantomVault / REF6598 # Elastic intrusion set PHANTOMPULSE # modular RAT delivered via Obsidian DLL side-load Abused app: Obsidian (legitimate markdown note-taking application) Technique: DLL side-loading (T1574.002) into a signed, trusted process C2: blockchain smart-contract resolver (EtherHiding-style on-chain config) # No durable C2 domain/IP -- the config is read on-chain and rotated cheaply.
# Public RPC/gateway providers to watch from NON-wallet processes (tune to your intel): infura.io alchemy.com ankr.com bsc-dataseed*.binance.org cloudflare-eth.com llamarpc.com publicnode.com quiknode.pro drpc.org # Allow-list sanctioned wallet/crypto apps (metamask/exodus/ledger/etc.) before alerting.
App control (WDAC/AppLocker): only allow Obsidian from its signed install dir Block DLL loads from user-writable paths into signed apps where feasible Promote Q1 (Obsidian side-load) + Q3 (Obsidian spawns shell) to Detect+Block IOAs Egress: block/alert blockchain RPC from non-wallet processes (allow-list crypto apps) Restrict portable-app execution from Downloads/Temp; default-deny user-path EXEs Inventory Obsidian installs + signatures; remove unsanctioned portable copies
Hardening — Tiered & Deployable
Kill the side-load surface, then cut the on-chain C2 path.
- App control: allow Obsidian only from its signed install dir — M1038. Defeats the portable-copy side-load.
- Promote Q1 (side-load) + Q3 (Obsidian spawns shell) to Detect+Block — M1040.
- Block DLL loads from user-writable paths into signed apps — M1044. Breaks T1574.002.
- Restrict portable-app execution from Downloads/Temp — M1038.
- Egress: block/alert blockchain RPC from non-wallet processes — M1037. Allow-list sanctioned crypto apps (Q4/N3).
- Monitor Run keys / tasks pointing at user-path Obsidian — M1028. Feeds Q5/N4.
- Inventory + signature-verify Obsidian installs — M1033. Removes unsanctioned copies (N1).
- Application allowlisting fleet-wide; default-deny user-path execution — M1038.
- Crypto/wallet-app governance: define which hosts may reach blockchain RPC — M1037.
- Module-load / image-load telemetry coverage (Sysmon 7 / EDR) — M1047. Enables Q1/N2.
Containment Runbook
| Phase | Actions | Owner | Evidence |
|---|---|---|---|
| Isolate | Network-contain the host; preserve the Obsidian copy + sideloaded DLL + any resolved C2 / contract address | SOC L2 | Containment timestamp; Q1 module-load event; DLL |
| Triage | Map side-load → PHANTOMPULSE → on-chain resolve → C2; capture the blockchain RPC + contract/wallet addresses; scope persistence | IR | Module-load timeline; resolved C2; addresses |
| Eradicate | Remove the sideloaded DLL + portable Obsidian + persistence; block the resolved C2 and RPC path; reset creds | IR | Removal log; cred reset |
| Recover | Reimage if hands-on RAT control occurred; reinstall Obsidian from a verified source if needed | IR + IT | Rebuild ticket |
| Harden | App control on Obsidian; promote Q1/Q3; block blockchain RPC from non-wallet processes | Detection Eng | IOA enabled; egress rule |
Detection Coverage Map & Validation
| Technique | Behavior | CQL | IOA | Coverage |
|---|---|---|---|---|
| T1574.002 | Obsidian DLL side-load | Q1, Q2 | IOA-1 | Good + app control |
| T1036 / T1059 | RAT inside Obsidian (spawns shell) | Q3 | IOA-2 | Good |
| T1102 / T1071 | On-chain C2 resolution | Q4 | — | Partial + proxy (N3) |
| T1547.001 / T1053.005 | Persistence | Q5 | — | Good |
| T1071 / T1041 | RAT egress / exfil | Q6 | — | Partial baseline Obsidian egress |
| — | Initial delivery of the trojanized Obsidian | — | — | GAP web/email + inventory (N1) |
Validation gates: (1) confirm image-load + process lineage + DNS/proxy telemetry; (2) baseline genuine Obsidian install paths + its sync/update endpoints + sanctioned crypto apps; (3) lab-test a benign Obsidian launch (must NOT fire Q1/Q3) and a benign wallet RPC call (must NOT fire Q4 — allow-listed); (4) enable app control + promote Q1/Q3. No single C2 atom — anchor on behavior.
Hunt Summary Ticket
TITLE: Hunt — PhantomVault / PHANTOMPULSE (Obsidian side-load, blockchain C2)
SEVERITY: High (resilient on-chain-C2 RAT in a trusted process)
SCOPE: Workstations with Obsidian; egress; persistence
HYPOTHESIS: Malicious DLL staged next to Obsidian -> side-load -> PHANTOMPULSE RAT ->
resolves C2 from a blockchain smart contract -> hands-on exec/file ops/exfil.
QUERIES RUN: Q1 Obsidian side-load (IOA) | Q2 portable Obsidian staging | Q3 Obsidian spawns
shell (IOA) | Q4 blockchain-RPC C2 resolve | Q5 persistence | Q6 anomalous egress
+ Native N1-N4 (Obsidian inventory, side-load module load, blockchain egress, persistence)
DO FIRST: App control on Obsidian; Q1, Q3 -- escalate any side-load/shell-spawn hit
FINDINGS: <pending analyst execution>
GAPS: Initial delivery of the trojanized Obsidian; on-chain C2 has no durable atom
ACTIONS: App control (signed Obsidian only); block user-path DLL loads into signed apps;
promote Q1/Q3; block blockchain RPC from non-wallet processes; inventory Obsidian
OWNER: HuntPack
VERSION: v0.3 - 2026-06-12
Changelog
table() calls now carry an explicit row limit: the default is 200 and truncation is silent, so a capped result was indistinguishable from a complete one. Atomic-IOC sweeps (filters over 5+ hashes or C2 IPs) use limit=max so a wide infection is never silently under-scoped; behavioural hunts use limit=200, where exceeding the cap indicates the query needs tuning. Where present, event names that do not exist in the Falcon data model were corrected (e.g. ServiceInstalled is a Sysmon concept, not a Falcon event; ElfFileWritten is ELFFileWritten) — such queries could never return a row. No detection logic, fields, or IOCs changed.References
| Tier | Source | Used For |
|---|---|---|
| 1 | Elastic Security Labs — PhantomVault / REF6598 | Obsidian side-load, PHANTOMPULSE RAT, blockchain C2 resolution |
| 2 | Google / Mandiant — EtherHiding (on-chain C2/payloads) | Blockchain smart contracts as resilient C2/payload stores |
| 2 | MITRE ATT&CK T1574.002 — DLL Side-Loading | Side-loading technique mapping |
HuntPack v0.3 · PhantomVault / PHANTOMPULSE · Generated 2026-06-12 · Defensive use only — no offensive code. C2 is resolved on-chain, so there is no durable domain to block — anchor on the Obsidian DLL side-load and anomalous blockchain-RPC egress. Validate module-load field names and maintain a sanctioned-crypto allow-list before promoting any query.