Executive Summary
EtherHiding represents a shift in how web-based attacks deliver malware. The technique moves payload delivery into smart contracts on the Binance Smart Chain testnet, allowing attackers to rotate payloads without modifying compromised sites. The injected JavaScript is disguised behind a counterfeit CAPTCHA page and uses the Ethers library to fetch OS-specific stages directly from on-chain storage. The result is a delivery model that relies on decentralized infrastructure, lightweight updates, and inexpensive gas-funded transactions.
A fake CAPTCHA acts as the lure for the Click-Fix technique. Victims are told they must “prove they are human” by copying attacker-controlled code and executing it locally through Terminal or the Windows Run dialog. This user-driven execution path bypasses many traditional detection mechanisms that rely on exploit behavior or browser sandbox signals. The payloads delivered through these chains remain fluid, but commonly include families such as Amos Stealer and Vidar.
This combination of decentralized staging, social engineering, and user-supplied execution marks a growing trend in attacker workflows. The architecture removes many predictable infrastructure pivot points and increases operational agility. Defenders must recognize that on-chain staging is becoming a practical alternative to the disposable infrastructure traditionally seen in web-based threats.
Introduction
Web-delivered malware continues to adopt infrastructure models that favor durability and operational flexibility. Attackers are steadily moving beyond fixed staging servers and disposable redirect chains in favor of decentralized platforms where payloads can be updated quickly and quietly. EtherHiding is one of the clearest examples of this change. It uses smart-contract storage to deliver dynamic payloads through malicious web injections and relies on the browser to act as the contract client.
Censys began tracking this behavior while monitoring clusters of Fake CAPTCHA lures across a wide range of web properties. These lures provide a consistent high-signal entry point for discovering injected sites. During one of these investigations, a compromised site revealed an EtherHiding chain that combined decentralized staging, platform-aware logic, and user-driven execution. The event provided a complete view of how blockchain storage, smart-contract evaluation, and social engineering operate as a unified workflow.
Case Study: EtherHiding Attack Chain
1. Initial Web Injection
The chain begins on a compromised website where an injected script tag is placed alongside a reused reCAPTCHA image originally hosted on Wikimedia. The visual lure is minimal, but the HTML contains a Base64-encoded JavaScript blob that serves as the entry point for the EtherHiding workflow. This stage prepares the environment for contract retrieval.



2. Base64 Loader and Obfuscated JavaScript
The Base64 payload decodes into an obfuscated JavaScript bundle that defines a helper function named load_(). This function constructs JSON-RPC requests, prepares ABI-style parameters, and imports the Ethers library directly inside the compromised page. The loader contains no static payload URLs, relying instead on contract lookups performed by the victim’s browser.


3. Contacting the First Smart Contract
The loader makes its first eth_call request to the contract at
0xA1decFB75C8C0CA28C10517ce56B710baf727d2e.
The contract returns a hex-encoded response that decodes into a Base64 string and finally into executable JavaScript. This stage inspects the victim’s browser for headless automation frameworks and evaluates the host’s user-agent string. If the browser appears automated, the chain stops.
4. OS-Aware Redirection to Second-Stage Contracts
If the browser passes validation, the script calls load_() again, directing the victim to an OS-specific contract.
Windows systems fetch: 0x46790e2Ac7F3CA5a7D1bfCe312d11E91d23383Ff.
macOS systems fetch: 0x68DcE15C1002a2689E19D33A3aE509DD1fEb11A5.
This structure allows a single injection to serve distinct malware families depending on platform.

5. The Contract Gate (Victim-ID Access Control)
A second contract call determines whether the victim is cleared to receive the next stage. The script generates or retrieves a persistent cookie (cjs_id) and passes it to a gate contract at
0xf4a32588b50a59a82fbA148d436081A48d80832A.
The browser issues an eth_call, sending the encoded user ID as a string parameter inside a fully padded ABI frame. The contract responds with an encoded string interpreted by the browser as either “yes” or another value. A return value of “yes” authorizes progression to the OS-specific payload stage.
This gate provides the attacker with a remotely controlled feature flag. By altering on-chain state, the operator can selectively enable or disable delivery for specific victims, throttle execution, or temporarily disable the entire campaign. The mechanism lets the attacker manage distribution with simple, low-cost blockchain transactions instead of modifying the compromised site.
6. Retrieving the OS-Specific JavaScript Stage
Each OS-specific contract returns another ABI-wrapped, hex-encoded blob containing the next JavaScript stage. The browser decodes the structure into a Base64 string and evaluates it. By placing stages in contract storage, the attacker bypasses traditional hosting models; payload updates are simply blockchain transactions rather than server updates.


7. Rendering the Fake CAPTCHA Lure
The decoded second-stage JavaScript renders a full-page fake CAPTCHA. The prompt states that “to prove you are human,” the user must click a copy button that loads attacker-controlled text into the clipboard. The lure then provides instructions tailored to the user’s operating system, guiding them toward a local execution surface.

8. Click-Fix Execution Path
When the victim follows the instructions, the browser has already populated the clipboard with malicious commands. On macOS, the user is directed to paste into Terminal, triggering a curl-to-bash retrieval and installation workflow that includes LaunchAgent plist persistence and AppleScript-based data theft. On Windows, the user pastes into the Run dialog, invoking MSHTA for remote retrieval and execution. This method bypasses exploit defenses by shifting execution responsibility to the user.

9. Dynamic C2 Resolution
The macOS payload uses AppleScript to resolve its active C2 domain through social channels. A function named `setdomain()` first attempts to pull a hostname from a Telegram page (`https://t[.]me/phefuckxiabot`) by running `curl` and using `sed` to extract text from a specific `<span>` element. It then constructs `https://<domain>/api.php?check=1` and issues another `curl` request. If the response equals `wait`, the script saves `https://<domain>/` as the active domain and returns success.
If the Telegram lookup fails, the script repeats the same process against a Steam profile (`https://steamcommunity[.]com/id/phefuckxia`), scraping the `actual_persona_name` span to derive a fallback domain and validating it with the same `api.php?check=1` pattern. Only when one of these checks returns `wait` does the script commit to an `activedomain`. If both attempts fail, the function returns false and no further action is taken.
When `setdomain()` returns true, the script constructs a final command string:

and executes it via `do shell script`. This pulls a remote AppleScript payload identified by the `BuildTXD` value and pipes it directly into `osascript` for execution, allowing the operator to deliver and update follow-on logic without modifying the initial macOS dropper.


10. macOS Credential Harvesting, Host Profiling, and Tasking
The macOS component implements a full authentication and synchronization routine that functions as a password stealer, state sync client, and task receiver. It begins by deriving the current username from the USER environment variable and the hardware UUID via system_profiler SPHardwareDataType | awk ‘/Hardware UUID/ { print $3 }’. These values form the host identity (username, deviceuuid) used in all subsequent API calls. The script first calls sendResult(deviceuuid, username), which performs a curl request to api.php?hwid=<uuid>&username=<user>&oid=<BuildTXD>. The server’s response drives the rest of the logic and encodes whether this is a new victim, a victim with no password, a victim with a known password, or an invalid/disabled build.
Credential verification is performed locally using the checkPassword(username, pwd) handler, which calls dscl . authonly <username> <password> and interprets success as a valid password. The getPassword(username) function abuses this to interactively prompt the user. If the account has no password and checkPassword(username, “”) returns true, the function returns a sentinel string N!O!P!A!S!S to represent a passwordless account. Otherwise, it enters a loop that displays a fake “System Preferences” dialog with a caution icon and hidden answer, asking the user to “enter your password” in order to change settings and run the application. The loop continues until the user enters a password that passes dscl validation, at which point the plaintext password is returned. Helper routines encodeToBase64Text and decodeFromBase64Text wrap the password in printf | iconv | base64 pipelines so that credentials can be stored and transported as Base64 text.
The authAndSync() routine orchestrates the server dialogue. If sendResult returns “error”, the script aborts with “deadoid”, indicating a disabled or unknown build identifier. If the response contains “newuser” or “nullpwd”, the victim is treated as new or without a known password. In that case, the script calls getPassword(username), then either sends the sentinel N!O!P!A!S!S via sendPassword for passwordless accounts or sends a Base64 encoded password using sendPassword(deviceuuid, username, password_base64). It also calls sendSpecs, which collects system_profiler SPSoftwareDataType SPHardwareDataType SPDisplaysDataType -json and POSTs it to api.php as spec=<json>&hwid=<uuid>&username=<user>&oid=<BuildTXD>, giving the operator a full JSON snapshot of software, hardware, and display configuration.
If the server already holds state for this victim, authAndSync() takes one of two paths. If the response contains N!O!P!A!S!S, the server believes the account is passwordless. The script re-checks locally using checkPassword(username, “”). If that still holds, it exits quietly. If the account now has a password, it prompts the user via getPassword, Base64 encodes the result, and updates the server with sendPassword. If the response does not contain the sentinel, the server returns a Base64 encoded password. The script decodes it and verifies it against the local account. If the stored password remains valid, no further action is taken. If it fails, the script assumes the user changed their password and re-prompts via getPassword, then either sends the sentinel or a Base64 encoded new password back to the C2. In all cases, the goal is to keep the server’s credential view synchronized with the actual local account state.
The listenCommands() routine then turns the system into a polling backdoor. It uses the same username and deviceuuid pair and enters an infinite loop that calls getTask(deviceuuid, username). That function performs a curl against task.php?hwid=<uuid>&username=<user>&oid=<BuildTXD> and returns either “notasks” or an arbitrary shell command. When a task is present, the script executes it via do shell script “nohup sh -c ” & quoted form of taskData & ” > /dev/null 2>&1 < /dev/null &”, detaching it from the current context and suppressing output. The loop sleeps for 30 seconds between polls. Combined with setDomain(), authAndSync(), and listenCommands(), this AppleScript establishes a persistent, credential-aware macOS agent that keeps the C2 updated on host identity, configuration, and password state while periodically executing remote shell commands.

Censys Perspective
EtherHiding shows how decentralized staging reduces predictable infrastructure signals. The chain centers on Binance Smart Chain testnet smart contracts rather than mainnet assets. The injected scripts use Ethers library calls inside the victim’s browser to perform JSON-RPC eth_call operations. Because RPC access depends on gateways that can be public, private, or entirely custom, the attacker can host new RPC endpoints under fresh domains with minimal effort.
A consistent pattern emerges across compromised sites. The same contract addresses appear repeatedly, implying a shared staging operator even when the injection points differ. The injection itself remains static, while the contract state determines the payload. This differs from earlier threats such as SocGholish, where domain churn served as a primary operational tactic. Here, the blockchain absorbs the rotation.
Censys telemetry plays a distinct role. Censys captures HTML bodies that reference ethers.js and ethers-min.js. These references are rare on non-crypto web properties and form a strong signal for malicious loaders preparing to interact with blockchain RPC nodes. Their presence appears sparsely but consistently across injected sites, reflecting an operational style that prioritizes concealment.
The Censys Platform exposes these chains through targeted search. The reuse of the Wikimedia reCAPTCHA logo provides a high-value lure artifact that appears across many Fake CAPTCHA pages. Searching for unexpected reuse of that asset narrows the investigation quickly. Additional precision comes from identifying HTML bodies that load Ethers libraries on domains unrelated to cryptocurrency. When these two features appear together, the correlation with EtherHiding is strong.
Even when the JavaScript is heavily obfuscated, the combination of lure assets and Ethers library imports reveals the underlying activity. These signals give defenders a durable detection surface even as RPC nodes move and contract states change. Internet-wide scanning and structured querying provide consistent visibility into these emerging patterns.
A Note on Fake CAPTCHAs
Fake CAPTCHAs have become a central social engineering mechanism across web-based attack chains. These pages mimic familiar interaction models such as “verify you are human,” a simple checkbox, or Cloudflare-style verification banners. Their purpose is to replicate a trusted interaction and condition users to continue without suspicion. Attackers frequently reuse assets such as the Wikimedia reCAPTCHA logo to normalize the lure across compromised properties.
The behavior behind these lures has evolved. Earlier Fake CAPTCHA chains delivered payloads directly after user interaction without involving clipboard manipulation. Newer campaigns use the Copy-Paste Click-Fix model, shifting execution responsibility to the victim. The distinction matters because it changes how defenders detect, contextualize, and respond to these threats.
Fake CAPTCHAs, Click-Fix, and EtherHiding are not inherently linked. Many campaigns use Fake CAPTCHAs without decentralized staging, and many EtherHiding chains do not involve clipboard abuse. The case documented here is notable because it combines decentralized staging, a Fake CAPTCHA lure, and OS-specific Click-Fix execution in one workflow. The convergence reflects increasing sophistication and layered deception.
Censys telemetry shows how widespread these lures have become. Between October 21 and November 20, Censys observed a minimum of 1,403 and a maximum of 1,671 web properties hosting Fake CAPTCHAs, with an average of 1,549 during the period. This dataset spans all varieties, not just EtherHiding. The breadth underscores the importance of monitoring for these lures as a high-signal entry point for early detection.

Understanding this evolution is critical. Fake CAPTCHAs will continue to serve as the foundation for multiple attack families, regardless of whether they incorporate decentralized technologies.
Conclusion
EtherHiding represents a clear break from static payload hosting techniques. The model uses smart-contract storage for payload delivery, Fake CAPTCHA overlays for social engineering, and Click-Fix mechanics for execution. Together, these components create an agile and durable attack chain that sits outside many traditional detection boundaries.
Host-level monitoring remains critical. macOS chains exhibit predictable Terminal-driven curl-to-bash execution and LaunchAgent plist creation, while Windows chains rely on MSHTA retrieval linked to clipboard activity. These sequences taper into credential theft and exfiltration.
Network-level detection must adapt to blockchain-oriented patterns. While browser-originated RPC calls may be difficult to catch directly, the presence of large hex-encoded RPC payload logic in injected JavaScript provides a reliable signal. Custom RPC endpoints complicate static filtering, but the supporting behaviors remain identifiable.
Threat hunting should prioritize html bodies containing scripts that reconstruct hex data, import Ethers libraries, or decode Base64 loaders before execution. These sequences rarely appear in legitimate web stacks. Contract queries followed by OS-specific Click-Fix behavior complete the attack chain. After suspected interaction, defenders should enforce MFA and rotate credentials given the prevalence of commodity stealers.
By combining lure-asset searches with Ethers-library detection, defenders can surface EtherHiding chains before payload rotations propagate across the network. The pace of attacker evolution will continue, but the underlying signals remain observable and actionable.

