Back to Intelligence

Woodgnat 'Node.js Resurgence' Campaign: ClickFix → ModeloRAT + EtherHiding C2 — OTX Detection Engineering Pack

SA
Security Arsenal Team
September 3, 2026
11 min read

AlienVault OTX pulse "Node.js: Old Technique Makes a Comeback" (TLP:WHITE, modified 2026-09-03) documents a resurgence — observed since February 2026 — of Node.js abuse attributed to the threat actor tracked as Woodgnat. This is not a single-family operation: the pulse links seven distinct payloads (ModeloRAT, C2Looper, AdaptixC2, Cobalt Strike Beacon, Backdoor.Mistic, AsukaStealer, EtherRAT) to a shared delivery methodology, indicating an access-broker style operation where initial footholds are monetized or handed off to downstream ransomware affiliates.

The campaign targets government departments, technology firms, finance, hospitality, and education, with confirmed victimology in the United States and at least one intrusion at an Asian technology company. The core tradecraft: instead of dropping a bespoke executable, operators fetch the official, digitally signed Node.js installer (node.exe) and use it as a living-off-the-land proxy to execute malicious JavaScript. Because node.exe is a legitimate signed binary, signature-based AV and reputation-based allowlists largely ignore it — the malicious logic lives in the .js payload, often fetched in-memory.

Delivery leans heavily on the ClickFix social engineering technique: victims are presented with fake CAPTCHA or "browser verification" pages that instruct them to paste a command into Run/Terminal, which silently pulls Node.js and a malicious script. The intrusion timeline in the pulse — attackers downloading the official Node.js installer after repeated payload blocking — demonstrates adaptive operators who pivot to signed-binary proxy execution when conventional droppers fail. The objective chain is consistent with initial access brokerage: establish persistence (ModeloRAT / Backdoor.Mistic), steal credentials and session data (AsukaStealer), and stage frameworks (Cobalt Strike, AdaptixC2) for ransomware enablement.

A notable C2 innovation in this campaign is EtherHiding: C2 configuration is stored on-chain (BNB Smart Chain) and retrieved through legitimate RPC infrastructure — one indicator, mainnet.gateway.tenderly.co, is a legitimate blockchain development gateway being abused as a dead-drop resolver. This makes traditional domain blocking insufficient.

Threat Actor / Malware Profile

Woodgnat (Adversary)

Initial-access-focused operator leveraging LOLBins and social engineering rather than exploit-based intrusion. Pattern of behavior suggests access resale to ransomware crews (tagged "ransomware access broker" in the pulse).

Payload Suite

FamilyRoleNotes
ModeloRATPrimary remote access trojanDelivered via node.exe-executed JavaScript; handles recon, command execution, and payload staging
EtherRATRAT with EtherHiding C2Pulls C2 config from smart contracts via public RPC endpoints (tenderly.co, BSC); resilient to takedown
AsukaStealerCredential/session stealerHarvests browser cookies, saved credentials, crypto wallets; exfil over HTTPS
Cobalt Strike BeaconPost-exploitation frameworkStaged after RAT foothold; malleable C2 over the listed IPv4 infrastructure
AdaptixC2Emerging open-source C2 frameworkIncreasingly adopted as a Cobalt Strike substitute; beacons blend with HTTPS traffic
C2Looper / Backdoor.MisticPersistence backdoorsLightweight implants maintaining long-term access for handoff

Attack Chain

  1. Lure: ClickFix fake-verification page instructs victim to run a pasted command (T1204 — User Execution).
  2. Staging: Official Node.js installer downloaded from nodejs.org; node.exe invoked against a remote or dropped .js payload (T1218 — Signed Binary Proxy Execution, T1059.007 — JavaScript).
  3. Execution: ModeloRAT/EtherRAT install; AsukaStealer runs opportunistically for credential theft.
  4. C2: HTTPS to listed domains/IPs; EtherRAT resolves C2 through blockchain RPC (T1102 — Web Service, T1071.001).
  5. Persistence: Registry Run keys and scheduled tasks masquerading as Node.js update jobs (T1547.001 / T1053.005).
  6. Anti-analysis: Signed-binary proxy defeats hash reputation; EtherHiding defeats static IOC blocking; payload content lives in volatile script files that self-delete post-execution.

IOC Analysis

The pulse exposes 180 indicators. The published sample breaks down as:

  • IPv4 (2): 94.156.114.250, 178.16.55.232 — hard C2 infrastructure, likely hosting Cobalt Strike / AdaptixC2 team servers. High-confidence block at egress firewall and EDR network rules.
  • Hostnames (3): mainnet.gateway.tenderly.co (abused legitimate blockchain RPC — EtherHiding resolver; do not blindly block without scoping, hunt for non-developer endpoints reaching it), www.xt24.com, mail.authorized-logins.net (typosquat-style phishing/C2 front; the "authorized-logins" pattern suggests credential-harvest lure infrastructure supporting ClickFix pages).
  • Domains (3): mueleer.com, grande-luna.top, oeannon.com — short-lived C2/payload-delivery domains. The .top TLD and randomized string patterns are consistent with DGA-adjacent throwaway registration.

Operationalization guidance:

  • Push IPv4 and domain indicators to DNS sinkhole (RPZ), proxy blocklists, and EDR custom indicators immediately. Set alert priority on any hit — these are low-false-positive artifacts.
  • For mainnet.gateway.tenderly.co: create an analytic, not a block. Alert on workstations (non-dev VLANs) initiating TLS to blockchain RPC endpoints; correlate with node.exe process ancestry.
  • Ingest the full 180-IOC set from the pulse into your TIP and expire none of it before 90 days — access brokers recycle infra across affiliates.
  • Tooling: decode JavaScript droppers with box-js / jsjiami deobfuscators, extract on-chain C2 config from EtherRAT samples by replaying their RPC calls against BSC, and pivot on TLS JA3/JA4 fingerprints since node.exe TLS stacks differ from browser traffic.

Detection Engineering

YAML
---
title: Node.exe Executing Remote or Suspicious JavaScript Payload
id: 7f3a9c21-4b8e-4d2a-9f6c-woodgnat0001
status: experimental
description: Detects the signed node.exe binary being used to execute JavaScript from suspicious locations or with inline/remote script arguments, consistent with Woodgnat ClickFix-to-ModeloRAT delivery (T1218, T1059.007).
author: Security Arsenal Threat Intel
references:
  - https://www.security.com/threat-intelligence/node-js-returns-ransomware
date: 2026/09/03
logsource:
  category: process_creation
  product: windows
detection:
  selection_img:
    Image|endswith: '\node.exe'
  selection_cli:
    CommandLine|contains:
      - ' -e '
      - '--eval'
      - 'http://'
      - 'https://'
      - '\Temp\'
      - '\AppData\Local\Temp\'
      - '\Downloads\'
      - '.js"'
      - ".js'"
  filter_legit_paths:
    CommandLine|contains:
      - '\node_modules\'
      - '\npm\'
      - 'Program Files\nodejs'
    CommandLine|endswith:
      - 'npm.js'
      - 'npx-cli.js'
  condition: selection_img and selection_cli and not filter_legit_paths
falsepositives:
  - Developer workstations running ad-hoc node scripts
level: high
tags:
  - attack.defense_evasion
  - attack.t1218
  - attack.execution
  - attack.t1059.007
---
title: ClickFix Execution Chain — Run Dialog Spawning Script or LOLBin Chain
id: 8a4bd732-5c9f-4e3b-a17d-woodgnat0002
status: experimental
description: Identifies explorer.exe (Run dialog) spawning mshta, powershell, cmd, wscript, or node — the hallmark ClickFix user-pasted command chain used by Woodgnat (T1204).
author: Security Arsenal Threat Intel
references:
  - https://www.security.com/threat-intelligence/node-js-returns-ransomware
date: 2026/09/03
logsource:
  category: process_creation
  product: windows
detection:
  selection_parent:
    ParentImage|endswith: '\explorer.exe'
  selection_child:
    Image|endswith:
      - '\powershell.exe'
      - '\pwsh.exe'
      - '\mshta.exe'
      - '\cmd.exe'
      - '\wscript.exe'
      - '\cscript.exe'
      - '\node.exe'
  selection_suspicious:
    CommandLine|contains:
      - 'iex'
      - 'Invoke-Expression'
      - 'downloadstring'
      - 'curl'
      - 'msiexec'
      - 'nodejs.org'
      - '.js'
      - 'bit.ly'
      - 'pastebin'
  condition: selection_parent and selection_child and selection_suspicious
falsepositives:
  - IT admin quick tasks via Run dialog (rare in most orgs)
level: critical
tags:
  - attack.execution
  - attack.t1204
  - attack.t1059
---
title: EtherHiding C2 — Non-Browser Process Querying Blockchain RPC Gateways
id: 9c5ce843-6d1a-4f4c-b28e-woodgnat0003
status: experimental
description: Detects non-browser processes (especially node.exe) making network connections to blockchain RPC infrastructure such as tenderly.co, indicative of EtherRAT EtherHiding C2 resolution (T1102, T1071.001).
author: Security Arsenal Threat Intel
references:
  - https://www.security.com/threat-intelligence/node-js-returns-ransomware
date: 2026/09/03
logsource:
  category: network_connection
  product: windows
detection:
  selection_dst:
    DestinationHostname|contains:
      - 'tenderly.co'
      - 'bsc-dataseed'
      - 'mainnet.infura.io'
      - 'rpc.ankr.com'
      - 'cloudflare-eth.com'
  selection_proc:
    Image|endswith:
      - '\node.exe'
      - '\powershell.exe'
      - '\wscript.exe'
      - '\mshta.exe'
      - '\rundll32.exe'
  filter_browsers:
    Image|endswith:
      - '\chrome.exe'
      - '\firefox.exe'
      - '\msedge.exe'
      - '\brave.exe'
  condition: selection_dst and selection_proc and not filter_browsers
falsepositives:
  - Web3 development workstations
  - Crypto trading tools on finance team endpoints
level: high
tags:
  - attack.command_and_control
  - attack.t1102
  - attack.t1071.001
KQL — Microsoft Sentinel / Defender
// Woodgnat Node.js Campaign Hunt — Microsoft Sentinel
// Hunts for node.exe execution anomalies, ClickFix chains, EtherHiding C2, and pulse IOCs
let Lookback = 14d;
let IOC_IPs = dynamic(["94.156.114.250", "178.16.55.232"]);
let IOC_Domains = dynamic(["mueleer.com", "grande-luna.top", "oeannon.com", "www.xt24.com", "mail.authorized-logins.net"]);
let EtherHiding_RPC = dynamic(["mainnet.gateway.tenderly.co", "bsc-dataseed.binance.org", "rpc.ankr.com", "mainnet.infura.io"]);
// Part 1: node.exe executing JS from user-writable paths or with remote URLs
let NodeAbuse = DeviceProcessEvents
| where TimeGenerated > ago(Lookback)
| where FileName =~ "node.exe"
| where ProcessCommandLine has_any ("-e ", "--eval", ".js", "http://", "https://")
| where ProcessCommandLine has_any (@"\Temp\", @"\AppData\", @"\Downloads\", "http")
| where not(ProcessCommandLine has_any ("node_modules", "npm", "npx"))
| project TimeGenerated, DeviceName, AccountName, ProcessCommandLine, InitiatingProcessFileName, InitiatingProcessCommandLine, SHA256;
// Part 2: ClickFix chain — explorer spawning script interpreters
let ClickFix = DeviceProcessEvents
| where TimeGenerated > ago(Lookback)
| where InitiatingProcessFileName =~ "explorer.exe"
| where FileName in~ ("powershell.exe","pwsh.exe","mshta.exe","cmd.exe","wscript.exe","node.exe")
| where ProcessCommandLine has_any ("iex", "downloadstring", "Invoke-Expression", "nodejs.org", "msiexec", ".js")
| project TimeGenerated, DeviceName, AccountName, FileName, ProcessCommandLine;
// Part 3: EtherHiding — non-browser processes reaching blockchain RPC
let EtherC2 = DeviceNetworkEvents
| where TimeGenerated > ago(Lookback)
| where RemoteUrl has_any (EtherHiding_RPC)
| where not(InitiatingProcessFileName in~ ("chrome.exe","msedge.exe","firefox.exe","brave.exe"))
| project TimeGenerated, DeviceName, InitiatingProcessFileName, InitiatingProcessCommandLine, RemoteUrl, RemoteIP;
// Part 4: Direct IOC hits
let IOCHits = DeviceNetworkEvents
| where TimeGenerated > ago(Lookback)
| where RemoteIP in (IOC_IPs) or RemoteUrl has_any (IOC_Domains)
| project TimeGenerated, DeviceName, InitiatingProcessFileName, RemoteIP, RemoteUrl, RemotePort;
union NodeAbuse, ClickFix, EtherC2, IOCHits
| sort by TimeGenerated desc
PowerShell
# Woodgnat Node.js Campaign — Endpoint IOC & Artifact Hunt
# Run via EDR live response or PS remoting across fleet. Checks persistence,
# node.exe artifacts, staging dirs, and live C2 connections.

$ErrorActionPreference = 'SilentlyContinue'
$IOC_IPs     = @('94.156.114.250','178.16.55.232')
$IOC_Domains = @('mueleer.com','grande-luna.top','oeannon.com','xt24.com','authorized-logins.net')
$report = @()

Write-Host '[*] Checking persistence: Run keys referencing node/.js payloads...' -ForegroundColor Cyan
$runKeys = @(
  'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run',
  'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run',
  'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce',
  'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce'
)
foreach ($key in $runKeys) {
  if (Test-Path $key) {
    Get-ItemProperty $key | Get-Member -MemberType NoteProperty | ForEach-Object {
      $val = (Get-ItemProperty $key).($_.Name)
      if ($val -match 'node\.exe|\.js|wscript|cscript') {
        $report += [pscustomobject]@{Type='Persistence-RunKey'; Path=$key; Name=$_.Name; Value=$val}
      }
    }
  }
}

Write-Host '[*] Checking scheduled tasks masquerading as Node.js update jobs...' -ForegroundColor Cyan
Get-ScheduledTask | Where-Object {
  $_.TaskName -match 'node|npm|jsupdate' -or
  ($_.Actions.Execute -match 'node\.exe|wscript|cscript|mshta') -or
  ($_.Actions.Arguments -match '\.js|http')
} | ForEach-Object {
  $report += [pscustomobject]@{Type='Persistence-SchedTask'; Path=$_.TaskPath+$_.TaskName; Name=$_.Actions.Execute; Value=$_.Actions.Arguments}
}

Write-Host '[*] Hunting dropped JS payloads in user-writable staging dirs...' -ForegroundColor Cyan
$stagingDirs = @("$env:TEMP", "$env:LOCALAPPDATA\Temp", "$env:USERPROFILE\Downloads", "$env:APPDATA", 'C:\ProgramData')
foreach ($dir in $stagingDirs) {
  Get-ChildItem $dir -Recurse -Include *.js -ErrorAction SilentlyContinue |
    Where-Object { $_.LastWriteTime -gt (Get-Date).AddDays(-30) -and $_.DirectoryName -notmatch 'node_modules' } |
    ForEach-Object {
      $head = Get-Content $_.FullName -TotalCount 5 -ErrorAction SilentlyContinue | Out-String
      if ($head -match 'eval\(|child_process|require\(.http|fetch\(|ActiveXObject|WScript\.Shell') {
        $hash = (Get-FileHash $_.FullName -Algorithm SHA256).Hash
        $report += [pscustomobject]@{Type='Suspicious-JSPayload'; Path=$_.FullName; Name=$_.LastWriteTime; Value=$hash}
      }
    }
}

Write-Host '[*] Checking live network connections to campaign C2 and EtherHiding RPC...' -ForegroundColor Cyan
Get-NetTCPConnection -State Established | ForEach-Object {
  $proc = (Get-Process -Id $_.OwningProcess).ProcessName
  if ($IOC_IPs -contains $_.RemoteAddress -or ($proc -in @('node','powershell','wscript','mshta','rundll32'))) {
    try {
      $dns = (Resolve-DnsName $_.RemoteAddress -ErrorAction Stop).NameHost
    } catch { $dns = '' }
    if (($IOC_IPs -contains $_.RemoteAddress) -or ($dns -match ($IOC_Domains -join '|')) -or ($dns -match 'tenderly\.co|bsc-dataseed|infura|ankr')) {
      $report += [pscustomobject]@{Type='Network-C2'; Path=$proc; Name=$_.RemoteAddress; Value="$dns :$($_.RemotePort)"}
    }
  }
}

Write-Host '[*] Checking for rogue Node.js installs outside Program Files...' -ForegroundColor Cyan
Get-ChildItem "$env:LOCALAPPDATA","$env:TEMP",'C:\ProgramData' -Recurse -Filter node.exe -ErrorAction SilentlyContinue |
  ForEach-Object {
    $sig = Get-AuthenticodeSignature $_.FullName
    $report += [pscustomobject]@{Type='Rogue-NodeBinary'; Path=$_.FullName; Name=$sig.SignerCertificate.Subject; Value=$sig.Status}
  }

Write-Host "`n[+] Hunt complete. $($report.Count) findings:" -ForegroundColor Green
$report | Format-Table -AutoSize | Out-String -Width 300
$report | Export-Csv -Path ".\woodgnat_hunt_$(hostname)_$(Get-Date -Format yyyyMMdd).csv" -NoTypeInformation

Response Priorities

Immediate (0-4h)

  • Block pulse IOCs at egress: IPv4 94.156.114.250, 178.16.55.232; domains mueleer.com, grande-luna.top, oeannon.com, xt24.com, authorized-logins.net. Pull the full 180-indicator set from the OTX pulse into your TIP.
  • Deploy the Sigma and KQL analytics above; run the PowerShell hunt across internet-facing user populations first (hospitality front-desk, education staff, government clerical — prime ClickFix targets).
  • Hunt execution artifacts: rogue node.exe outside Program Files\nodejs, .js files in Temp/Downloads modified in the last 30 days, and explorer-spawned script interpreter chains.

24 Hours

  • AsukaStealer is a confirmed payload — treat any endpoint with a detection as fully credential-compromised. Force resets for the interactive user plus any service accounts touched from that host; revoke active sessions/tokens (M365 refresh tokens, VPN, SSO cookies) rather than just changing passwords.
  • Audit browser credential stores and crypto wallet extensions on flagged hosts; check for session-cookie exfil indicators (unexpected logins from new ASN/geography within the dwell window).
  • Review VPN/IdP logs for access-broker behavior: new device enrollments, MFA fatigue events, or impossible-travel authentications since February 2026.

1 Week

  • Architecture hardening against signed-binary abuse: implement WDAC/AppLocker rules constraining node.exe to developer groups only; block node.exe execution from user-writable paths; alert on node.exe network egress for non-dev endpoints.
  • Deploy browser isolation or content disarm for CAPTCHA/verification pages; launch user-awareness specifically on ClickFix ("never paste commands from a webpage into Run/Terminal").
  • Restrict outbound TLS from servers and standard workstations to categorized destinations; sinkhole or alert on blockchain RPC endpoints (tenderly, infura, BSC dataseeds) from any host that is not an approved Web3 development asset.
  • Establish a retro-hunt window back to February 2026 for all analytics — this campaign has been running for seven months.

Related Resources

Security Arsenal Incident Response Managed SOC & MDR Services AlertMonitor Threat Detection From The Dark Side Intel Hub

Is your security operations ready?

Get a free SOC assessment or see how AlertMonitor cuts through alert noise with automated triage.