Triage
EtherHiding: the C2 that keeps its own audit trail
· 5 min read
Last month, a coworker of mine was working an IR case and found a payload pulling its command-and-control (C2) config from a contract deployed on the Ethereum testnet - enough to get me digging further.
On August 4th, a compromised maintainer account pushed keyv 6.0.0 to npm, and about four hours later the payload inside it had republished itself into 433 other packages, taking the campaign to 2,212 affected versions in all. StepSecurity named it ChainDrop, Wiz traced its lineage back to the Shai-Hulud worms (the self-replicating npm attacks from 2025), and most of the coverage has (reasonably) focused on the blast radius. The part I keep coming back to is how the worm found its way home. It doesn’t ship a C2 address at all - it makes an eth_call against a smart contract on Ethereum mainnet (a read-only query that costs nothing and leaves no transaction behind) and gets back a list of domains before connecting to whatever is in it that day. The operator rotates infrastructure by signing one transaction, and every infected host reads the new value for free, with no wallet and no key of its own.
On August 10th, Sonatype found six more npm packages tied to DPRK’s Contagious Interview campaign. But this loader doesn’t bother with a contract - it looks up an outbound transaction from a wallet the attacker controls and decodes the recipient address (20 bytes the sender can set to anything) into two IPv4 addresses. Microsoft also recently published on DeadLock, a ransomware group whose chat page pulls its proxy address from a Polygon contract and hosts their leak site blog post data on-chain, which admittedly is pretty slick. Three different actors, three different tricks, all in a single month of reporting.
From all of this, I learned this technique is called EtherHiding, and it isn’t new - Google traced it back to ClearFake in 2023 and watched UNC5342 adopt it last year. What has changed is the breadth: unrelated campaigns are now applying the same design to supply-chain malware, DPRK-linked loaders, and ransomware infrastructure. Google’s phrase for it was “next-generation bulletproof hosting,” which seems about right for an immutable blockchain.
Two details from the write-ups that stood out to me:
- ChainDrop’s payload cycles through 75 different public RPC providers before it gives up. If one is blocked, it moves to the next. If all 75 are blocked, it falls back to searching GitHub commits for a marker string. Known RPC endpoints can be blocked, but endpoint churn and legitimate Web3 traffic make provider-by-provider blocking difficult.
- The infrastructure can cost literally nothing. Google put UNC5342’s contract updates on BNB Smart Chain at about $1.37 in gas each (the per-transaction fee), and noted the actor moved between chains partly because the fees were cheaper. Acreed, the stealer binaryanalys.is documented last October, ran its payload and victim-tracking contracts on the BSC testnet. Testnets have something called a faucet that hands out all the gas you need, usually for developer testing.
The first detail is what makes takedowns so frustrating, as every previous generation of resilient C2s (e.g. dead drops on Pastebin or Telegram or GitHub) still had somebody you could send an abuse report to. A contract on a public chain has no registrar or hosting provider who can simply take it offline. Granted, its controlling wallet can update the current state, but identifying or compelling the operator is a whole other problem. Plus, the RPC providers are just reading a ledger anyone can read, and blocking them is just a big game of whack-a-mole.
The second detail is the one I’d expect to drive copycats if these attacks continue. Free testnet gas means there’s no financial trail to follow at all. Also, I believe one of the reasons most malware still hardcodes a domain is that domains are cheap and simple - a testnet contract is cheaper, and once you’ve written the loader once, just as simple.
For illustrative purposes, I had Claude give me a snippet of what ChainDrop’s C2 lookup, a standard eth_call, would look like using the contract address and function selector from StepSecurity’s report:
{
"jsonrpc": "2.0",
"id": 1,
"method": "eth_call",
"params": [
{ "to": "0xE1f2395ee43e45A1556EC6438a88c31B83493103", "data": "0x53ed5143" },
"latest"
]
}That is the entire thing. No auth header, no signature, no wallet - one HTTPS POST to any of those 75 providers, and the response is the current domain list. On a build runner with no expected Web3 activity, a node or bun process speaking JSON-RPC during npm install is an extremely high-signal detection.
Everything above is the story every vendor has been telling, and I’m not disagreeing with it. But I do think it’s only half of the story.
A blockchain is takedown-resistant because it’s immutable. Immutable cuts both ways, though. Every time ChainDrop’s operators rotated their domain list, they signed a transaction that is now permanently, publicly recorded with a timestamp, a sender, and the exact bytes they wrote. The Acreed researchers pulled the actor’s entire history of C2 domains off the block explorer’s API and published it as an appendix. Wiz noticed that the address funding the ChainDrop contract had already been flagged for scam activity, which means the operator’s C2 now has a financial lineage attached to it that no domain registration ever did.
Last month I wrote about JADEPUFFER leaving self-narrated payloads behind, and how that was essentially attacker-authored data that could just as easily be stripped or faked next time. This is different. The attacker can point the contract somewhere new, but they cannot un-write where it pointed before. For every update written through the contract, the adversary leaves behind a durable, publicly queryable infrastructure history - an audit trail the operator keeps on our behalf without meaning to. This could be a huge source of information for threat researchers, and the kind that would previously have been much harder to obtain.
One more thing, because I keep writing about it: ChainDrop’s stage 2 specifically harvests .claude/credentials.json, .codex/auth.json and .cursor/credentials.json, plants a Claude Code SessionStart hook for persistence, and disguises the commits that install it as coming from claude <[email protected]>. In June I discussed the coding agent as the method of malware delivery, but now their credential stores are the loot and their names are coming up as camouflage in the commit log.
Bulletproof hosting used to just mean a provider that ignored abuse reports. Now it can also mean a ledger nobody can take down and nobody can edit - and only one of those was the original point.
ZB