ChainScript's operator moved its C2 twice for a quarter of a cent, and the blockchain logged both moves
A ClickFix campaign installs ChainScript, a Node.js remote access trojan that asks a Polygon smart contract where its server is. The operator rewrote that answer twice on 31 August, and the public ledger shows exactly when, where and for how much.
By Parminder Kumar Sharma · · 17 min read

Two writes, sixteen minutes apart, for a fraction of a cent
At 16:58:34 UTC on 31 August 2026 a Polygon wallet ending ...0000 called a function on a smart contract it had deployed a week earlier. At 17:14:42 UTC it called the same function again. Each call replaced one short string: the WebSocket address that every installed copy of the ChainScript remote access trojan built against that contract asks for when it needs to find its operator. The first write pointed agents at moweros[.]net on port 3851. The second pointed them at bedotiq[.]net on port 3854. The two transactions cost 0.0239 POL in fees between them, which at the POL price Blockscout displayed on 21 September is about a quarter of a US cent.
We read those transactions ourselves from the public ledger, and on 21 September we asked the contract for its current answer through a neutral public RPC node. It still returns ws[:]//bedotiq[.]net:3854, 20 days after the rotation and three days after Blackpoint Cyber published its analysis of the malware on 18 September.
That arithmetic establishes something narrow: the operator can move every agent to a new server cheaply, without shipping new malware, and the move is written permanently into a public record. It does not establish how many machines are infected, who is behind the campaign, whether any victims are in the UK, which websites carried the ClickFix lure, or why the operator rotated when it did. Neither primary source answers those questions, and we do not pretend to.
What the record says, and what it leaves out
Blackpoint names the malware ChainScript. Justice-Hammer, who found the same sample first, calls it ComponentTask33 after its install folder and notes the agent's own internal name, win-agent-client. Both describe the same Spotify-branded MSI with the same SHA-256 hash. Neither attributes it to any actor or country.
ChainScript on the record: what the two primary reports state, and what they do not (Blackpoint APG, 18 September 2026; Justice-Hammer RES-0007, updated 2 September 2026)
| Question | Stated | Not stated |
|---|---|---|
| How it starts | ClickFix activity led the user to run msiexec.exe against a tokenised URL | The lure page, the exact pasted text, the sites that hosted it |
| What gets installed | Per-user MSI posing as Spotify, Zoom Workplace or Microsoft Teams, four builds named | How many builds exist in total |
| How C2 is found | Polygon contract read with eth_call, returning a ws:// panel address | Whether the newer builds use the same contract |
| What it can do | Shells, files, screenshots, payload deployment, wallet inventory, remote JavaScript, update, self-removal | Any confirmed data theft from a real victim |
| Scale and targets | Nothing | Victim numbers, sectors, countries |
| Who is behind it | Both decline to attribute | Any actor or country |
That last row matters. Blackpoint is a managed detection and response vendor and its report ends in a sales panel; Justice-Hammer publishes detection rules on GitHub. Both have reasons to be seen finding things first. Neither overreaches: both separate what they observed from what they infer, and both explicitly decline to name a culprit. We follow the same line.
The chain, step by step
1. The lure. ClickFix pages pose as a verification check or a fix for a fault, copy a command to the clipboard in the background, and ask the visitor to press Win+R, paste and press Enter. Microsoft's August 2025 analysis documents the pattern in detail. Blackpoint says only that ClickFix activity started this chain; it does not publish the page or say where it was hosted. Justice-Hammer, working from a sandbox report, says the parent campaign and distribution method are unknown.
2. The pasted command. The command ran msiexec.exe against api-configuard[.]com, requesting capher.php with a token parameter, which served the MSI. Justice-Hammer observed the file arriving over cleartext HTTP from 82.25.63[.]146 and judges the token likely single-use or short-lived, which is a simple way to stop researchers fetching the payload later. The delivery domain was registered on 21 August, three days before the MSI was built.
3. The installer. ComponentTask33-4d14e6ac.msi is 56,943,312 bytes, claims to be from Spotify AB, and was built with the WiX toolset. It is configured with ALLUSERS=2 and MSIINSTALLPERUSER=1, so it installs into the user profile with no administrator prompt. Spotify is impersonated, not involved. Two custom actions run after installation: hidden PowerShell executes ._scatter.ps1, then wscript.exe runs ._agent.vbs.
4. The scatter. ._scatter.ps1 splits the package across four Microsoft-looking folders: the Node.js runtime under %LOCALAPPDATA%\Microsoft\Windows\Libraries, the agent under %APPDATA%\Microsoft\Windows\Themes, configuration under INetCache, and two small .NET helpers under Shell. No single folder looks like malware. Justice-Hammer adds that uninstalling the MSI removes none of this.
5. The agent. The VBScript starts the bundled node.exe against app\src\index.js with no console window. The configuration file, HiddenVirtualSilentLoader.dat, is Base64 then XOR with a per-build key (c8c384083f in this build). Decoded, it sets a 12 minute heartbeat, a 15 second reconnect delay, a five minute cache for the contract answer, and the Polygon resolver settings. The first connection waits a random 10 to 30 seconds; Blackpoint's sandbox recorded 24,540 milliseconds.
6. Persistence. The agent, not the installer, runs StreamServiceSharedBridge.ps1 to create a hidden scheduled task, ComponentTask33Agent, at user logon, running wscript.exe //B against the VBScript. If that fails it writes the same value to HKCU\Software\Microsoft\Windows\CurrentVersion\Run. Both stay in the user context. Justice-Hammer points out the useful tell: persistence appears as node.exe launching PowerShell seconds after msiexec has exited, not as part of the install.
7 and 8. Finding the operator. Covered in the next section. Once connected, the agent authenticates to the WebSocket panel with an X-Agent-Token header, registers the host by hostname and Windows MachineGuid with username, architecture, memory, CPU count, local IPv4 address and domain, and waits for tasks.
How the contract stores and rotates the C2
The contract is small: 1,481 bytes of bytecode when we read it. It holds one string, the panel URL. Anyone can read it; only the owner can change it.
To read it, the agent sends a JSON-RPC eth_call to Polygon mainnet (chain ID 137) asking contract 0xf9099d0d747368cce8C10226CC9AF2bFD4DDbCF4 to run the function with selector 0x4ab7874e. The node executes the read locally and returns an ABI-encoded string. An eth_call creates no transaction and costs nothing, so the malware's lookups leave no trace on the chain. Blackpoint says the agent checks the answer begins with ws:// or wss://, caches it for five minutes and uses it in place of the panel written into its configuration. Justice-Hammer, decoding the same configuration, says that with contract discovery enabled the agent deletes the static panel and relies on the contract alone.
To write it, the owner sends an ordinary transaction to a setter (function selector 0x3042438a in the two transactions we decoded; Justice-Hammer names it setPanelUrl). Every write is signed by the owner's wallet, timestamped in a block and kept forever.
The resolver contract's complete write history, read from Polygon on 21 September 2026 (Blockscout; fees in POL)
| Time (UTC) | What the transaction did | Fee (POL) |
|---|---|---|
| 24 Aug 2026 11:20:09 | Deployed the contract, block 92576921, panel set to shift-api-control[.]com:3847 | 0.1204 |
| 31 Aug 2026 16:58:34 | Rewrote the panel to moweros[.]net:3851, block 92993658 | 0.0119 |
| 31 Aug 2026 17:14:42 | Rewrote the panel to bedotiq[.]net:3854, block 92994303 | 0.0120 |
The build timing says the process is automated. shift-api-control[.]com was registered at 10:52:17 UTC on 24 August. The contract naming it was deployed 27 minutes 52 seconds later. The MSI's internal creation timestamp is 11:20:32, 23 seconds after the deployment block. Justice-Hammer spotted that gap first and argues, reasonably, that 23 seconds is too short for a human; Blackpoint repeats the point. We confirmed the block time independently. Six hours later, at 17:31:07 and 17:31:11, moweros[.]net and bedotiq[.]net were registered four seconds apart through the same registrar and the same name servers, then left unused for seven days. The replacement addresses were bought on build day.
One more detail lines up. Blackpoint describes watching a live session in which the contract first returned shift-api-control[.]com:3847, the operator sent a drive-enumeration task after about 18 minutes, the session reset about 12 minutes later, and the contract then returned bedotiq[.]net:3854. Blackpoint does not date that session. The chain shows the answer changed away from shift-api-control exactly once, at 16:58:34 on 31 August. So, as an inference from the public record, Blackpoint's live observation must have straddled that moment. Justice-Hammer had published the contract address three days earlier and notes that the rotation is consistent either with reacting to publication or with routine hygiene. Neither report can say which, and nor can we. Blackpoint also found it could not tell what prompted the change.
Why blockchain-hosted C2 resists takedown, and where it does not
The traditional way to kill a C2 channel is to take away its address: suspend the domain, sinkhole it, or get the hosting company to pull the server. A hardcoded domain in malware makes that final. ChainScript moves the one address that matters, the pointer, onto a public blockchain. There is no registrar to ask, no single host to seize, and a deployed contract cannot be deleted by anyone else. Guardio Labs named the technique EtherHiding in October 2023, when attackers stored malicious JavaScript in BNB Smart Chain contracts behind compromised WordPress sites. Google's threat intelligence group reported in October 2025 that a North Korean cluster had adopted it, and noted one contract updated more than 20 times in four months at an average of US$1.37 per update. ChainScript's rotations cost a fraction of that.
The friendly label here is "takedown-proof". It describes the pointer, not the operation. Three things still fall:
- The panels are ordinary servers. Every ChainScript panel domain resolved to
176.65.144[.]127, according to Justice-Hammer, and Blackpoint links newer activity to176.65.144[.]40, in the same /24. Taking a panel down costs the operator one write of about 0.012 POL and one domain from a reserve pool, but it does cost them. - Reading the chain goes through someone. This build's configuration names one RPC endpoint,
polygon-bor.publicnode[.]com. Google makes the general point that attackers use "permissioned services to interact with permissionless blockchains", and those services are points of observation and control. - Every move is published. A rotation is a signed, timestamped, permanent record of the operator's new infrastructure, readable by any defender for free, from any node, without ever contacting the attacker. Justice-Hammer calls it a public audit log. The trade EtherHiding makes is resilience in exchange for transparency.
As of 21 September, 21 days after the last rotation, none of the six domains in the two reports showed a registrar or registry hold in RDAP. All were still simply registered. That is not evidence nobody tried, but it does mean the pointer has not yet been tested by a takedown.
What the RAT does once it is in
Blackpoint's table lists 11 built-in task types; Justice-Hammer counts 13, adding control messages such as reconnect, capabilities and load_script. The substance matches.
ChainScript's built-in tasks (Blackpoint APG figure 8, cross-checked with Justice-Hammer RES-0007)
| Task | What it does |
|---|---|
| cmd, powershell | Run a command and return the output; PowerShell runs from %TEMP%\wra-ps-* with -ExecutionPolicy Bypass |
| shell | Interactive CMD or PowerShell terminal through node-pty |
| files | List drives, read, write, download and recursively delete files |
| screenshot | Full virtual desktop as PNG, via a .NET helper or a PowerShell fallback |
| download_run, deploy | Fetch and run arbitrary files, or install MSI, PowerShell or CMD payloads per user |
| wallet_scan | Report which desktop wallets and browser wallet extensions are installed |
| eval | Run JavaScript inside the agent process |
| agent_update, kill | Replace the agent from a ZIP, or remove persistence and wipe its folders |
Two points deserve precision. First, the wallet feature is reconnaissance, not theft: Blackpoint found no code to extract seed phrases, private keys, browser passwords, cookies or DPAPI-protected secrets, and Justice-Hammer counts roughly 37 desktop wallet folders and 48 extension IDs that it only reports as present. With shell and file access, an operator can take the rest by hand. Second, the built-in list is a floor. A remoteScript.js module asks the panel's /api/agent/script path for extra JavaScript, runs it in a Node.js vm context and lets it register new commands. When Blackpoint tried that path it got a 404, so it was not in use on that listener at the time. Justice-Hammer also notes the agent has no sandbox, virtual machine or geography checks at all; its evasion is looking like a developer tool.
What defenders can actually block
ChainScript's clever part is the resolver. Most of the useful controls sit elsewhere in the chain, where it is ordinary.
Controls against the ChainScript chain: what each stops, and what it does not (Microsoft documentation; Blackpoint and Justice-Hammer recommendations; our analysis)
| Control | What it stops here | What it does not stop |
|---|---|---|
| Remove Run menu from Start Menu (NoRun) | Win+R, the route this lure used | Terminal, PowerShell, File Explorer address bar |
| DisableMSI set to 1 | Non-elevated per-user installs of unmanaged MSIs, which this installer relied on | Script-only ClickFix payloads; legitimate per-user MSIs need exceptions |
| App control on user-writable paths | node.exe and the helpers running from AppData folders | Anything already allowed by publisher or hash |
| Default-deny egress on odd ports | ws:// to 3847, 3851 and 3854 | A future build using wss:// on 443, which the agent already accepts |
| Alert or block public EVM JSON-RPC from non-crypto hosts | This build's single configured resolver | A rebuild pointing at another RPC provider |
| PowerShell script block logging | Nothing, but records the scatter, persistence and operator scripts | Node.js and VBScript activity outside PowerShell |
The Run dialog. Microsoft recommends the Group Policy setting "Remove Run menu from Start Menu" where users do not need Win+R. It is worth doing, and it is a comforting name. The policy's own documentation says it "affects the specified interface only" and does not stop other ways of running programs. ClickFix operators already ask victims to paste into Windows Terminal, and in June 2025 a researcher showed the File Explorer address bar works too. Treat NoRun as removing one door. Monitoring the RunMRU registry key, which records Run dialog entries, still pays: Microsoft's hunting query for ClickFix explicitly looks for msiexec there.
Per-user installers. This is the control most specific to ChainScript. Setting the Windows Installer policy DisableMSI to 1 disables the installer for unmanaged applications, and Microsoft's documentation says in so many words that "non-elevated per-user installations are blocked" while managed and elevated installs continue. ChainScript's MSI was built precisely to install per user without elevation. Test first: some collaboration and developer tools ship per-user MSIs, and your software deployment tool must be the managed path.
The blockchain lookup. Both vendors advise against blocking public RPC infrastructure outright, because wallets and dApps depend on it, and Justice-Hammer puts polygon-bor.publicnode[.]com in a "do not block" table. That advice is right for them: they write for many customers at once, some of whom trade crypto. For a typical UK organisation whose laptops have no business reason to call an Ethereum-compatible JSON-RPC endpoint, blocking the category at the web proxy with named exceptions is a defensible choice, and at a minimum it should raise an alert. That is our judgement, not theirs. Justice-Hammer's packet captures show the RPC call runs over HTTPS, so the proxy sees the server name, not the request body; Blackpoint's advice is to correlate RPC access followed by node.exe opening a WebSocket, which is more useful than either signal alone. Blocking the lookup only breaks this build if the agent has no other way to find a panel; Justice-Hammer's reading of the configuration says it does not, while Blackpoint does not describe the failure case.
PowerShell logging. Every PowerShell stage in this chain would be captured by script block logging, which records "the content of all script blocks" to event ID 4104 in the Microsoft-Windows-PowerShell/Operational log. That covers ._scatter.ps1, the persistence script and every operator command sent through the powershell task. Microsoft also suggests execution policies such as AllSigned. ChainScript passes -ExecutionPolicy Bypass on every run, and Microsoft's own documentation is blunt that execution policy "isn't a security boundary". Logging is the control here; execution policy is a speed bump.
Hunting. The artefacts that stayed constant across all builds are the ones to hunt: ._agent.vbs, app\src\index.js, connect-delay-state.json and a Node.js runtime inside %LOCALAPPDATA% or %APPDATA% shell and cache folders, plus process lineage of msiexec.exe to wscript.exe to node.exe, and node.exe to powershell.exe creating a scheduled task. The query below is a starting point for Microsoft Defender XDR; adapt the field names for other EDR tools.
// Node.js runtime running from Windows shell or cache folders in the user profile
DeviceProcessEvents
| where FileName =~ "node.exe"
| where FolderPath has_any (@"\AppData\Local\Microsoft\Windows\", @"\AppData\Roaming\Microsoft\Windows\")
| project Timestamp, DeviceName, AccountName, FolderPath, ProcessCommandLine, InitiatingProcessFileName
// Run dialog entries that launch msiexec against a URL
DeviceRegistryEvents
| where RegistryKey has @"\CurrentVersion\Explorer\RunMRU"
| where RegistryValueData has "msiexec" and RegistryValueData has "http"
Watch the pointer. Because the contract is public, any team can check it on a schedule from an RPC of its own choosing and alert when the answer changes. A change is the operator announcing its new panel. Remember that domains, ports and IP addresses in the table below are short-lived by design; Blackpoint says as much, and Justice-Hammer had to rewrite two network rules that had pinned port 3847.
How this differs from the Brevo ClickFix incident
We covered a different ClickFix case last week: an attacker with a stolen Cloudflare key rewrote Brevo's embedded scripts at the CDN edge so that visitors to customers' websites saw a fake verification page. That story was about how the lure reached people. This one is about what arrives after someone pastes the command. The two are not linked in any source, and ClickFix is a technique used by many unrelated groups; Microsoft reports ClickFix builder kits on sale for US$200 to US$1,500 a month. The defences overlap at the paste: whichever site serves the lure, the Run dialog, the installer policy and the logging are the same.
Indicators, defanged
From Blackpoint's report unless noted. Use them for retrohunting and enrichment, not as your main detection: the operator has already shown it rotates infrastructure.
ChainScript indicators of compromise (Blackpoint APG, 18 September 2026; delivery IP from Justice-Hammer RES-0007)
| Type | Indicator | Context |
|---|---|---|
| MSI SHA-256 | 20a9e297220fe4cb9f939eaa82582c6e9a8f6dd4424635206dec08fa1986b8fa | ComponentTask33, posing as Spotify |
| MSI SHA-256 | 6e07d2de3618bb92265248653361ff39c63c0cfba2f4aa2538b3128fa9ce3a50 | UpdateDigital, posing as Spotify |
| MSI SHA-256 | bad0600a850436154f8d7b6f7a191dc45bd136897780cd032b336cb4b358d241 | HostShared, posing as Zoom Workplace |
| MSI SHA-256 | 496c202abf53984164f5f319a72b02c8e06016d0f35681353ef07db8e6d1b31f | OrchidViolet66, posing as Microsoft Teams |
| Delivery | api-configuard[.]com /capher.php, 82.25.63[.]146 | MSI download |
| Panels | shift-api-control[.]com:3847, moweros[.]net:3851, bedotiq[.]net:3854 | Resolved from the contract |
| Other C2 | kerosand[.]net:3847, giperon[.]net:3847 | Other builds |
| Hosting | 176.65.144[.]127, 176.65.144[.]40 | C2 servers |
| Contract | 0xf9099d0d747368cce8C10226CC9AF2bFD4DDbCF4, chain 137 | Resolver, selector 0x4ab7874e |
| Host | ComponentTask33Agent task, ._agent.vbs, HiddenVirtualSilentLoader.dat | Persistence and config |
What to do, in order
Take this with you
Actions worth taking this week
- Search endpoint telemetry for node.exe running from AppData Microsoft Windows shell or cache folders, and for the files ._agent.vbs, app\src\index.js and connect-delay-state.json.
- Retrohunt proxy and DNS logs for the defanged domains and the 176.65.144.0/24 range above, and treat any hit as a full remote access compromise.
- Pilot the Windows Installer policy DisableMSI set to 1 on a test group, list the per-user MSIs it breaks, and move those to managed deployment.
- Deploy the Remove Run menu from Start Menu policy to staff who do not need Win+R, and monitor the RunMRU registry key for msiexec, PowerShell and mshta entries regardless.
- Turn on PowerShell script block logging across the estate, ship event 4104 to your SIEM, and enable protected event logging as Microsoft recommends.
- Decide deliberately whether laptops may reach public blockchain RPC endpoints; if not, block the category at the proxy with exceptions, and if so, alert on it from hosts with no crypto role.
- Enforce default-deny egress for unusual ports from user endpoints so that plain ws:// connections to high ports fail.
- Tell staff plainly that no genuine website will ever ask them to press Win+R, open Terminal or paste into the File Explorer address bar, and give them a one-click way to report it.
The question to ask
On 31 August the operator told every ChainScript agent where to go next, in public, for less than a penny. Anyone could have read it the moment it happened. So the question for your security team is not whether you can take down a blockchain. It is this: if one of your laptops had asked a Polygon node for directions that afternoon, would anything you log have noticed?
Key facts
Sources
- PrimaryChainScript: Tracing a Node.js RAT Through the Blockchain. Primary report: chain, configuration, Polygon resolver, command set, live rotation, recommendations, IOCsBlackpoint Cyberaccessed 2026-09-21
- PrimaryRES-0007, ComponentTask33 MSI Loader with On-Chain C2 Discovery. Independent first disclosure: MSI metadata, decoded config, contract history, domain batch, hosting, detectionsJustice-Hammer (GitHub)accessed 2026-09-21
- PrimaryPolygon explorer record of the resolver contract: deployment and both setter transactions, timestamps, blocks, feesBlockscoutaccessed 2026-09-21
- PrimaryRegistry records for the .net and .com panel and delivery domains: registration times, registrar, name servers, statusVerisign RDAPaccessed 2026-09-21
- PrimaryThink before you Click(Fix): ClickFix mechanics, RunMRU forensics, mitigations, hunting query, builder kit pricesMicrosoft Threat Intelligenceaccessed 2026-09-21
- PrimaryDisableMSI policy values: value 1 blocks non-elevated per-user installs of unmanaged applicationsMicrosoft Learnaccessed 2026-09-21
- PrimaryADMX_StartMenu NoRun (Remove Run menu from Start Menu): scope and the note that it affects that interface onlyMicrosoft Learnaccessed 2026-09-21
- PrimaryWindows PowerShell 5.1 about_Logging: script block logging, event 4104, Group Policy pathMicrosoft Learnaccessed 2026-09-21
- Primaryabout_Execution_Policies: execution policy is not a security boundaryMicrosoft Learnaccessed 2026-09-21
- PrimaryDPRK adopts EtherHiding (16 October 2025): background on the technique, update costs, centralised intermediaries as control pointsGoogle Threat Intelligence Groupaccessed 2026-09-21
- PrimaryEtherHiding (13 October 2023): original naming of the technique on BNB Smart ChainGuardio Labsaccessed 2026-09-21
- PrimaryFileFix (23 June 2025): ClickFix variant using the File Explorer address barmr.d0xaccessed 2026-09-21
- Reported byNews report of 21 September 2026 used only as a pointer to the Blackpoint reportThe Hacker Newsaccessed 2026-09-21


