OXLOADER → CastleStealer — Node.js Malvertising Loader (REF8372)
Executive Summary
OXLOADER (Elastic Security Labs campaign REF8372) is a previously-unreported Windows loader distributed through malicious Google Ads that impersonate the Node.js installer. Victims in the US searching for legitimate Node.js are redirected to a lookalike landing page, download a batch package (BATPackageBuilderSetup.bat) that renders a fake install wizard, and silently fetch a Storj-hosted next-stage executable. That executable — OXLOADER — elevates via a Start-Process -Verb RunAs UAC prompt, runs an array of anti-analysis checks, then reflectively loads CastleStealer, a .NET information stealer that harvests browser, wallet, and credential data.
The loader is built for stealth: control-flow flattening, opaque predicates, mixed Boolean-Arithmetic (MBA) obfuscation, self-modifying decryption stubs, abuse of the PE .reloc section to stage shellcode, a DonutLoader wrapper for in-memory .NET execution, and Chaskey-LTS payload encryption. The actor is assessed Russian-speaking and financially motivated — it explicitly skips machines in the CIS region and with Russian locale (LANGID 0x419).
The best defensive angle is the delivery seam: a fake-installer batch script spawning powershell.exe that downloads from link.storjshare.io and re-launches a freshly-dropped EXE with -Verb RunAs. That process lineage is rare in benign software installs and gives a high-fidelity, low-FP catch before the stealer ever runs.
Defender priority: Hunt for powershell.exe downloading from *.storjshare.io and any process re-launching a just-written EXE with -Verb RunAs. Block the published C2 IPs (89.124.95.161, 89.124.115.82) and the malvertising domains, and load the OXLOADER/CastleStealer hashes as prevent IOCs.
Source Review & Web Hunter Notes
| Tier | Source | Key Finding | Carry Forward |
|---|---|---|---|
| 1 | Elastic Security Labs — OXLOADER deep-dive | Campaign REF8372; full IOC set (hashes, Storj URLs, C2 IPs), anti-VM checks, obfuscation chain, DonutLoader + Chaskey-LTS | Yes |
| 1 | The Hacker News — OXLOADER coverage (2026-06-22) | Node.js malvertising lure, Russian-speaking financially-motivated actor, CastleStealer linkage to CastleLoader / BackgroundFix | Yes |
| 2 | Cyberpress — "Fake Node.js Ads Spread OXLOADER and CASTLESTEALER" | Corroborates Node.js installer impersonation and Google Ads delivery | Partial |
Atomic IOCs in this pack (hashes, domains, C2 IPs) are carried directly from the Elastic Security Labs appendix. No IOC here is inferred or fabricated — see §18 References for source mapping.
Hunt Brief & Attack Chain
Hunt Hypotheses (fidelity-ordered)
- H1 (high): A fake-installer batch/PowerShell chain downloads a payload from
*.storjshare.io— visible inProcessRollup2command lines. Very low FP. - H2 (high): A process re-launches a freshly-dropped EXE with
Start-Process -Verb RunAsto force a UAC elevation — rare outside installers. - H3 (high): Known OXLOADER / CastleStealer SHA256 hashes execute or are written to disk.
- H4 (high): Beacon to CastleStealer C2 IPs
89.124.95.161/89.124.115.82. - H5 (medium): DNS / connection to the malvertising landing + redirector domains (
prentiva99.info,miloyannopoulos.com). - H6 (medium): DLL side-loading —
dui70.dllcopied to a random.ocxand loaded from a user-writable path. - H7 (medium): Binaries masquerading as
node-v*-x64-86.exe/apimonitor-x64.exelaunched from a browser download directory.
Attack Chain
| Step | Behavior | Telemetry | Hunt Angle |
|---|---|---|---|
| 1 · Malvertising | Malicious Google Ad for "Node.js" → redirector → lookalike landing page | DnsRequest, NetworkConnectIP4 | Q5 |
| 2 · Delivery | User downloads BATPackageBuilderSetup.bat (fake wizard) | PeFileWritten, ProcessRollup2 | Q1, Q7 |
| 3 · Download | Batch spawns PowerShell to fetch Storj-hosted OXLOADER EXE | ProcessRollup2 CommandLine | Q1 |
| 4 · Elevation | Start-Process -Verb RunAs forces UAC prompt | ProcessRollup2 CommandLine | Q2 |
| 5 · Evasion | Anti-VM / locale checks; CIS + Russian exclusion; DLL side-load via random .ocx | PeFileWritten | Q6 |
| 6 · Payload | DonutLoader reflectively loads CastleStealer (.NET) in memory | ProcessRollup2 (hash) | Q3 |
| 7 · C2 / exfil | CastleStealer beacons to hardcoded C2 IPs | NetworkConnectIP4 | Q4 |
Consolidated IOC Table
| Type | Value | Confidence | Action | Context |
|---|---|---|---|---|
| sha256 | fdfc7831e5c24cfa80152860dfe8c056ba079f7df1393bf6bb7b18ed974eda37 | high | detect | BATPackageBuilderSetup.bat (OXLOADER downloader) |
| sha256 | de4f51649ec1a33071854aefe93ffb3fc225e19f802d8dd914676dd5dfef2615 | high | detect | BATPackageBulderSetup.bat (OXLOADER downloader) |
| sha256 | 9a9939dff297997732aaade9b243d695632cbd64033c5fbcb9de3d09b7e6c28d | high | detect | apimonitor-x64.exe (OXLOADER variant) |
| sha256 | c85f2765a6c3c3f3907c17e57df12f8f68826f74bff3bbfd272af50666d065fe | high | detect | node-v24.15.0-x64-86.exe (OXLOADER variant) |
| sha256 | 4ec9d9d4d10ad78fc6d7bda7cb17d52984878ccd2dd4302fd1cef152313b9741 | high | detect | CastleStealer payload |
| sha256 | 39019279686c820c3af5684012a0085a7e2109f612c9fab886dd0577ace5b5c6 | high | detect | CastleStealer payload |
| ipv4 | 89.124.95.161 | high | detect | CastleStealer C2 |
| ipv4 | 89.124.115.82 | high | detect | CastleStealer C2 |
| domain | node-js.prentiva99.info | high | detect | Malvertising landing (Node.js impersonation) |
| domain | app.miloyannopoulos.com | medium | hunt | Redirector (download?subid1=download) |
| url | link.storjshare.io/raw/…/BATPackageBuilderSetup.bat | medium | hunt | Storj payload hosting (path rotates) |
Affected Surface & Telemetry Matrix
| Surface | Required Telemetry | Priority | Gap Risk |
|---|---|---|---|
| Windows endpoints (developer workstations especially) | ProcessRollup2 / SyntheticProcessRollup2 | High | Low — default Falcon coverage |
| Endpoint → internet egress | NetworkConnectIP4, DnsRequest | High | Low |
| File writes to user download/temp dirs | PeFileWritten, NewExecutableWritten | Medium | Medium — module-load side-load is partial |
| Browser credential / wallet stores | ProcessRollup2 (CastleStealer access) | Medium | Medium — read access not always logged |
ATT&CK Mapping
| Tactic | Technique | Observed Behavior | Query / Control |
|---|---|---|---|
| Resource Development | T1583.008 Malvertising | Malicious Google Ads for Node.js | Q5 / web filtering |
| Initial Access / Execution | T1204.002 Malicious File | Fake installer batch package | Q1, Q7 |
| Execution | T1059.001 PowerShell | Batch spawns PowerShell downloader | Q1 |
| Privilege Escalation / Defense Evasion | T1548.002 Bypass UAC | Start-Process -Verb RunAs | Q2 / M1052 |
| Defense Evasion | T1574.002 DLL Side-Loading | dui70.dll copied to random .ocx | Q6 / M1052 |
| Defense Evasion | T1027.009 Embedded Payloads / T1027.013 Encrypted | .reloc shellcode staging; Chaskey-LTS | Q3 / M1040 |
| Defense Evasion | T1620 Reflective Code Loading | DonutLoader in-memory .NET | Q3 |
| Defense Evasion | T1497.001 Virtualization/Sandbox Evasion | CPU/RAM/refresh checks; locale exclusion | — / behavioral |
| Collection / Exfiltration | T1555 / T1041 (CastleStealer) | Browser, wallet, credential theft → C2 | Q4 |
Native Audit-Log Hunts
- Secure web gateway / proxy: Block and alert on any download from
*.storjshare.ioby an interactive browser session, and on the malvertising domains. Storj raw-object hosting is rare in enterprise traffic. - Google Ads / DNS: Hunt newly-registered lookalike domains containing
node/nodejsresolved shortly before a binary download. - Windows Sysmon (if deployed): Event ID 1 —
powershell.exewith-Verb RunAsand a URL in the command line; Event ID 7 — module load of a.ocxfrom a user profile path. - EDR quarantine review: Cross-check any blocked
node-v*-x64-86.exeorapimonitor-x64.exedetection against the hash list in §4.
CrowdStrike LogScale CQL Hunt Queries
Looks for: powershell.exe whose command line references Storj raw-object hosting — the OXLOADER download step.
// HUNT: PowerShell downloading OXLOADER payload from Storj (REF8372) // MITRE: T1059.001, T1204.002 // CONF: high FP: low COST: low | REQUIRES: ProcessRollup2 #event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/ | ImageFileName=/\\(powershell|pwsh)\.exe$/i | CommandLine=/storjshare\.io/i | table([ComputerName, UserName, ParentBaseFileName, CommandLine, SHA256HashData], limit=200)
Looks for: Start-Process … -Verb RunAs spawned from a script interpreter — OXLOADER's UAC elevation. FP: some legitimate admin install scripts self-elevate; scope to PowerShell parented by cmd.exe/wscript.exe or to download dirs.
// HUNT: Self-elevation via Start-Process -Verb RunAs from interpreter (REF8372) // MITRE: T1548.002 // CONF: high FP: medium COST: low | REQUIRES: ProcessRollup2 // TUNING: exclude known software-deployment tooling (SCCM/Intune agents) #event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/ | ImageFileName=/\\(powershell|pwsh)\.exe$/i | CommandLine=/Start-Process.*-Verb\s+RunAs/i | ParentBaseFileName=/^(cmd|wscript|cscript|explorer)\.exe$/i | table([ComputerName, UserName, ParentBaseFileName, CommandLine], limit=200)
Looks for: Execution of any known REF8372 sample by SHA256. Direct, atomic, near-zero FP.
// HUNT: Known OXLOADER/CastleStealer SHA256 execution (REF8372) // MITRE: T1204.002, T1620 // CONF: high FP: low COST: low | REQUIRES: ProcessRollup2 #event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/ | SHA256HashData=/^(fdfc7831e5c24cfa80152860dfe8c056ba079f7df1393bf6bb7b18ed974eda37|de4f51649ec1a33071854aefe93ffb3fc225e19f802d8dd914676dd5dfef2615|9a9939dff297997732aaade9b243d695632cbd64033c5fbcb9de3d09b7e6c28d|c85f2765a6c3c3f3907c17e57df12f8f68826f74bff3bbfd272af50666d065fe|4ec9d9d4d10ad78fc6d7bda7cb17d52984878ccd2dd4302fd1cef152313b9741|39019279686c820c3af5684012a0085a7e2109f612c9fab886dd0577ace5b5c6)$/i | table([ComputerName, UserName, ImageFileName, ParentBaseFileName, SHA256HashData], limit=max)
Looks for: Outbound connections to the hardcoded CastleStealer C2 IPs.
// HUNT: CastleStealer C2 connection (REF8372) // MITRE: T1041 // CONF: high FP: low COST: low | REQUIRES: NetworkConnectIP4 #event_simpleName=/NetworkConnectIP4/ | RemoteAddressIP4=/^89\.124\.(95\.161|115\.82)$/ | table([ComputerName, ContextBaseFileName, RemoteAddressIP4, RemotePort], limit=200)
Looks for: DNS resolution of the OXLOADER malvertising infrastructure. FP: redirector domains can be reused; treat prentiva99.info as the high-confidence anchor.
// HUNT: OXLOADER malvertising domain resolution (REF8372) // MITRE: T1583.008 // CONF: high FP: medium COST: low | REQUIRES: DnsRequest // TUNING: prentiva99.info is the high-confidence anchor; miloyannopoulos.com can be reused — enrich, don't alert alone #event_simpleName=/DnsRequest/ | DomainName=/(prentiva99\.info|miloyannopoulos\.com)/i | table([ComputerName, DomainName, ContextBaseFileName], limit=200)
Looks for: A PE written with an .ocx extension into a user-writable path — the DLL side-load staging step. FP: legacy ActiveX installers also drop .ocx; pair with a recent Storj download on the same host.
// HUNT: OCX PE staging for DLL side-loading (REF8372) // MITRE: T1574.002 // CONF: medium FP: medium COST: low | REQUIRES: PeFileWritten // TUNING: exclude C:\Windows\ and trusted vendor install paths #event_simpleName=/PeFileWritten|NewExecutableWritten/ | TargetFileName=/\\(Users|ProgramData|Temp)\\.*\.ocx$/i | table([ComputerName, ContextBaseFileName, TargetFileName], limit=200)
Looks for: OXLOADER variants masquerading as a Node.js or apimonitor installer launched from a user download path. FP: genuine Node.js installers are named node-v<ver>-x64.msi, not -x64-86.exe; the malformed suffix is the tell.
// HUNT: OXLOADER masquerading binary execution (REF8372) // MITRE: T1036.005, T1204.002 // CONF: medium FP: medium COST: low | REQUIRES: ProcessRollup2 // TUNING: confirm hash against the §4 list; benign Node is *-x64.msi #event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/ | ImageFileName=/\\(node-v[\d.]+-x64-86|apimonitor-x64)\.exe$/i | table([ComputerName, UserName, ImageFileName, ParentBaseFileName, SHA256HashData], limit=200)
CrowdStrike Custom IOA Recommendations
| IOA Name | Pattern | Exclusions | Action |
|---|---|---|---|
| OXLOADER — Storj PowerShell Download | Process powershell.exe, CommandLine contains storjshare.io | None needed (Storj raw-hosting rare) | Block |
| OXLOADER — Script Self-Elevation | PowerShell CommandLine matches -Verb RunAs, parent in cmd/wscript/cscript | SCCM/Intune deployment agents | Detect (high) |
| OXLOADER — Masquerading Installer | Image name matches node-v*-x64-86.exe from a user download dir | None | Detect (high) |
Q1 and Q7 are strong Custom IOA promotion candidates. Q2 should run as Investigate-only until the deployment-agent exclusions are validated in-tenant.
Machine-Readable IOC Appendix
type,value,action,severity,expiration,description,tags sha256,fdfc7831e5c24cfa80152860dfe8c056ba079f7df1393bf6bb7b18ed974eda37,prevent,critical,2026-12-24,OXLOADER batch downloader,campaign:REF8372 sha256,de4f51649ec1a33071854aefe93ffb3fc225e19f802d8dd914676dd5dfef2615,prevent,critical,2026-12-24,OXLOADER batch downloader,campaign:REF8372 sha256,9a9939dff297997732aaade9b243d695632cbd64033c5fbcb9de3d09b7e6c28d,prevent,critical,2026-12-24,OXLOADER variant,campaign:REF8372 sha256,c85f2765a6c3c3f3907c17e57df12f8f68826f74bff3bbfd272af50666d065fe,prevent,critical,2026-12-24,OXLOADER variant,campaign:REF8372 sha256,4ec9d9d4d10ad78fc6d7bda7cb17d52984878ccd2dd4302fd1cef152313b9741,prevent,critical,2026-12-24,CastleStealer payload,campaign:REF8372 sha256,39019279686c820c3af5684012a0085a7e2109f612c9fab886dd0577ace5b5c6,prevent,critical,2026-12-24,CastleStealer payload,campaign:REF8372 ipv4,89.124.95.161,detect,high,2026-09-24,CastleStealer C2,campaign:REF8372 ipv4,89.124.115.82,detect,high,2026-09-24,CastleStealer C2,campaign:REF8372 domain,node-js.prentiva99.info,detect,high,2026-09-24,Malvertising landing,campaign:REF8372 domain,app.miloyannopoulos.com,detect,medium,2026-07-24,Redirector,campaign:REF8372
powershell.exe CommandLine ~ storjshare.io powershell.exe CommandLine ~ "Start-Process .* -Verb RunAs" parent in (cmd,wscript,cscript) PE written with .ocx extension under \Users\ or \ProgramData\ process image name ~ node-v*-x64-86.exe (benign Node is *-x64.msi) NetworkConnectIP4 RemoteAddressIP4 in (89.124.95.161, 89.124.115.82)
Campaign: REF8372 (Elastic Security Labs) Loader: OXLOADER (control-flow flattening, MBA, opaque predicates, .reloc shellcode staging) Wrapper: DonutLoader (in-memory .NET) Crypto: Chaskey-LTS (key 6E0A1F8F77F7011561F6F9CA96B71B8F) Payload: CastleStealer (.NET infostealer; CastleLoader / BackgroundFix lineage) Hosting: link.storjshare.io (raw object store) Actor: Russian-speaking, financially motivated; CIS + LANGID 0x419 exclusions
block *.prentiva99.info block *.miloyannopoulos.com alert download of .bat/.exe from *.storjshare.io by browser session audit Google Ads click-through to non-nodejs.org "Node.js" downloads
Detection Validation Gates
| Gate | Check | Pass Criteria |
|---|---|---|
| Telemetry ready | ProcessRollup2, NetworkConnectIP4, DnsRequest, PeFileWritten flowing | All four event types present in last 24h |
| Benign baseline | Run Q2 over 7 days in audit mode | Deployment-agent self-elevation excluded; residual hits triaged |
| Positive test | In a lab, run powershell -c "Start-Process notepad -Verb RunAs" and a benign Storj fetch | Q1/Q2 fire as expected |
| Promotion | Q1, Q7 promoted to Custom IOA after baseline | Zero FP across pilot ring |
Hardening — Tiered & Deployable
- Block the IOCs — load §10 hashes as prevent, C2 IPs + domains as detect/block (M1040, M1031).
- SWG rule — block executable downloads from
*.storjshare.ioinitiated by browsers; rare in legitimate enterprise use. - ASR rule — enable "Block executable content from email/web that don't meet a prevalence/age/trust criterion" and "Block process creations from PSExec/WMI" where compatible (M1042).
- Constrained Language Mode + script-block logging for PowerShell (M1038, M1049) to surface download cradles.
- Restrict software-install ad surface — push internal package sources (winget private repo / artifactory) so developers fetch Node.js from a vetted channel, not search ads (M1018).
- Application control (WDAC / AppLocker) — allow-list signed installers and block execution from user download/temp paths (M1038).
- UAC to "Always notify" + admin-approval mode so a
-Verb RunAselevation is a conscious user action, not a silent install step (M1052).
Deployable Playbooks
1 · Enable PowerShell script-block + module logging (GPO/registry)
REG ADD "HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging" /v EnableScriptBlockLogging /t REG_DWORD /d 1 /f REG ADD "HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging" /v EnableModuleLogging /t REG_DWORD /d 1 /f REG ADD "HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging\ModuleNames" /v "*" /t REG_SZ /d "*" /f
2 · Block executable content from web (ASR, Defender)
Add-MpPreference -AttackSurfaceReductionRules_Ids 3B576869-A4EC-4529-8536-B80A7769E899 -AttackSurfaceReductionRules_Actions Enabled Add-MpPreference -AttackSurfaceReductionRules_Ids D4F940AB-401B-4EFC-AADC-AD5F3C50688A -AttackSurfaceReductionRules_Actions Enabled
3 · Hunt residual fake installers on disk
Get-ChildItem "$env:USERPROFILE\Downloads","$env:TEMP" -Recurse -Include *.bat,*.exe -ErrorAction SilentlyContinue |
Where-Object { $_.Name -match 'node-v.*-x64-86|apimonitor-x64|BATPackage' } |
Select-Object FullName,Length,LastWriteTime
Test ASR rules in audit mode (-AttackSurfaceReductionRules_Actions AuditMode) on a pilot ring before enforcing.
Containment Runbook
| Phase | Actions | Owner | Evidence |
|---|---|---|---|
| Isolate | Network-contain the host in Falcon; preserve memory if CastleStealer is suspected resident | SOC L2 | Containment timestamp, host AID |
| Eradicate | Kill OXLOADER/PowerShell tree; remove dropped .bat/.exe/.ocx; clear Run keys / scheduled tasks created post-infection | SOC L2 | File hashes, process tree export |
| Credentials | Force-reset browser-saved + SSO creds and any crypto wallet seeds on the host (CastleStealer is a credential/wallet thief) | IAM | Reset audit log |
| Recover | Reimage if side-load persistence confirmed; re-issue Node.js from vetted internal source | Endpoint Eng | Rebuild ticket |
| Lessons | Promote Q1/Q7 to IOA; brief developers on malvertising risk for dev-tool downloads | Detection Eng | This pack, updated |
Detection Coverage Map
| Technique | Behavior | CQL | IOA | Coverage |
|---|---|---|---|---|
| T1583.008 | Malvertising domains | Q5 | — | Good |
| T1059.001 | PowerShell Storj download | Q1 | Yes | Good |
| T1548.002 | UAC self-elevation | Q2 | Candidate | Partial |
| T1204.002 | Known sample execution | Q3, Q7 | Yes | Good |
| T1574.002 | OCX side-load staging | Q6 | — | Partial |
| T1041 | CastleStealer C2 | Q4 | — | Good |
| T1497.001 | Sandbox/locale evasion | — | — | Gap |
| T1555 | Browser/wallet credential access | — | — | Gap |
Two gaps remain: in-memory sandbox-evasion logic (T1497.001) and CastleStealer's local credential/wallet read (T1555) are not directly observable in standard Falcon process telemetry — rely on the hash/C2/behavioral catches upstream and downstream of those steps. Validation gates (§11) must pass before promoting Q1/Q7 to Custom IOAs.
Hunt Summary Ticket
TITLE: OXLOADER → CastleStealer (REF8372) — Node.js malvertising loader hunt SEVERITY: High — active in-the-wild loader + infostealer SCOPE: All Windows endpoints; prioritize developer workstations HYPOTHESIS: Fake Node.js installer drops OXLOADER via Storj, self-elevates, loads CastleStealer QUERIES: Q1 Storj PS download · Q2 RunAs elevation · Q3 known hashes · Q4 C2 · Q5 malvert DNS · Q6 OCX side-load · Q7 masquerade DO FIRST: Run Q1, Q3, Q4 across the fleet; load §10 hashes as prevent IOCs FINDINGS: ____________________________________________ GAPS: T1497.001 sandbox evasion, T1555 local cred/wallet read — not in process telemetry ACTIONS: Block C2 IPs + malvert domains; SWG-block storjshare.io browser downloads; promote Q1/Q7 to IOA OWNER: ____________________ VERSION: v0.2 (2026-06-24)
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 | Access Date |
|---|---|---|---|
| 1 | Elastic Security Labs — OXLOADER deep-dive (REF8372) | All atomic IOCs (hashes, Storj URLs, C2 IPs), obfuscation chain, anti-VM checks, ATT&CK mapping | 2026-06-24 |
| 1 | The Hacker News — New OXLOADER Loader Uses Malicious Google Ads (2026-06-22) | Node.js lure, actor attribution, CastleStealer lineage | 2026-06-24 |
| 2 | Cyberpress — Fake Node.js Ads Spread OXLOADER and CASTLESTEALER | Corroboration of delivery vector | 2026-06-24 |
| R | MITRE ATT&CK | Technique IDs and mitigation (M-number) mapping | 2026-06-24 |