RuntimeBroker npm Typosquat Plants Crypto Clipper

RuntimeBroker:一个 npm Typosquat 植入了一个 40 链加密剪币器,作为跨操作系统的“系统运行时助手”。

TL博士

2026年05月21日,npm 发布者 jaggle 发布了九个版本(1.0.0 通过 1.0.8)的 @jaggle/resizeobserves 大约在两个小时的时间窗口内。

该软件包是对合法软件包的拼写错误抢注。 @juggle/resize-observer polyfill 是一个广泛使用的软件包,每周下载量达数百万次,但它并没有提供实际的 ResizeObserver 实现。

相反,包裹的 安装后钩子 安装捆绑的 Python 有效载荷,将持久性注册为平台原生的运行时代理,并部署针对加密货币交易的跨平台剪贴板劫持程序。

Linux 持久性表现为 python3-dbus-helper, macos as com.apple.python.runtimeWindows as PyRuntimeBroker.

该有效载荷持续监控剪贴板,查找钱包地址。 超过40个区块链 并悄无声息地将复制的地址替换为攻击者控制的钱包地址。

该恶意软件完全在本地运行,没有出站 C2 基础设施,因此剪贴板替换本身就是一种数据泄露机制。

主要 IOC 就是软件包名称本身: @jaggle/resizeobserves — 注意“jaggle”中省略的元音和“resizeobserves”中添加的“s”。

严重程度:高。

攻击原理

npm:@jaggle/resizeobserves 从表面上看不像恶意软件 npm 视图。 其 README.md 这是 README 的逐字原文 npm:@juggle/resize-observer — 相同的代码示例,相同的使用说明,相同的 import { ResizeObserver } from '@juggle/resize-observer' 全文引用过多。抄袭如此彻底,以至于任何瞥一眼文档的人都会以为自己在阅读正版软件包的文档。

的package.json相比之下,则十分稀疏:没有 知识库 字段,单个 箱子 入口指向 bin/clipboard-guardian.js,以及 安装后 运行的脚本 node npm-install.jsREADME 文件中的“基本用法”示例引用了一个 tar 包中根本不存在的 JavaScript 实现。该软件包中唯一的 JavaScript 文件是安装脚本。

第一阶段 — npm postinstall 引导 Python 有效载荷

npm-install.js 它具有平台感知能力。它可以定位一个 点子 沿固定搜索路径可执行(/usr/bin/pip3, /usr/local/bin/pip,回到 python3 -m pip),从 tarball 目录安装捆绑的 Python 包,并且在 Linux 系统上,会拉取 剪辑 or Xsel 通过 apt-get的, 吃豆子DNF 如果两者都不存在:

指某东西的用途 –break-system-packages 这是有意为之:现代 Linux 发行版默认启用了 PEP 668 中关于外部管理环境的 Python 标记,这会在默认情况下阻止全站范围内的 pip 安装。安装脚本会强制执行此安装。

该脚本也支持 sudo。当运行的 uid 是以下结果时: sudo npm install脚本内容如下: 须藤用户 并掏钱 获取密码 找到了 真实 然后将其持久化文件写入用户的主目录,而不是写入其他目录。 /根持久化是针对每个用户的,而不是系统范围的。

第二阶段——运行时代理名称下的跨操作系统持久化

安装完 Python 包后,该脚本会在每个操作系统上注册一个名称不同的自动启动项:

  • Linux — 一个 systemd 用户单元 ~/.config/systemd/user/python3-dbus-helper.service该单元的 描述 is Python D-Bus 运行时助手该脚本还会尝试通过以下方式启用它: systemctl –user enable回退到手动符号链接 default.target.wants/ 当 systemctl 失败时。如果以 sudo 运行,脚本将切换到 sudo -u systemctl –user, XDG_RUNTIME_DIR 设置用户总线调用功能。
  • macos — LaunchAgent plist ~/Library/LaunchAgents/com.apple.python.runtime.plist - RunAtLoad=trueKeepAlive=true然后通过以下方式加载 launchctl 加载.
  • Windows — 一个名为 PyRuntimeBroker 的计划任务,在 AtLogOn 触发,执行时间限制为零(即无超时),通过 PowerShell 注册。

乍一看,这三个名字都可信。 python3-dbus-helper 遵循 Linux 桌面上合法的 Python-D-Bus 集成命名约定。 com.apple.python.runtime 模仿苹果公司对其自身服务的反向 DNS 标签。 PyRuntimeBroker 这与Windows的声明相呼应 RuntimeBroker.exe — 一个真实存在的、经过签名的微软服务,用于代理 UWP 应用的权限请求。在此上下文中,这些都不是真正的苹果/微软/Python 服务,而是一位防御者在快速目视检查时发现的。 systemctl –user list-units or GET-ScheduledTask 不太可能退缩。

第三阶段——剪贴板劫持者

安装在以下位置的 Python 有效载荷 clipboard_guardian/guardian.py运行一个无限循环,每 400 毫秒轮询一次系统剪贴板。每次循环,它都会通过以下方式拉取当前剪贴板内容: pyperclip.paste() 并针对四十多个预编译的正则表达式列表运行它们,这些正则表达式涵盖了以太坊、比特币、门罗币、索拉纳、波场、TON、瑞波币、莱特币、狗狗币、波卡币、NEAR、Cosmos、Algorand、恒星币、卡尔达诺、比特币现金、达世币、Zcash、Aptos、Sui、Tezos、MultiversX、Harmony、Terra、Injective、Osmosis、Kava、Celestia、Nano、Filecoin、Ronin、Ergo、DigiByte、Hedera、BNB 智能链以及其他一些在默认配置中被存根但为空的加密货币(Sei、IOTA、Kaspa、Flow、Nervos、Decred、Ravencoin)。

当匹配成功时,脚本会从该链中读取攻击者的地址。 ~/.config/clipboard-guardian/config.json (或其平台等效项)并用替换后的文本覆盖剪贴板:

没有网络信标。该窃取器不会向服务器发送数据,不会记录受感染的主机,也不会窃取任何数据。窃取行为本身就是替换:当用户从钱包界面复制收款地址并粘贴到发送对话框中时,粘贴的地址实际上属于攻击者。资金在用户不知情的情况下以带内方式丢失。

这里有什么新内容

与通用的加密剪枝模板相比,有几个细节比较突出:

1. npm → Python 交叉。 我们在 npm 上看到的加密代码剪辑器大多是纯 JavaScript,通常会使用混淆技术进行处理。 _0x 数组旋转或 eval(atob(…)) 堆栈。此示例使用 npm tarball 作为 Python 包(干净的 Python)的交付包装器,并让 pip 处理依赖项安装(pyperclip, 实用工具, 可选的 设置程序标题) 在捆绑包中声明 pyproject.toml不存在需要破解的 JavaScript 混淆。代码剪辑器本身就是纯正易读的 Python 代码。

2. 选择合理的 Tri-OS 持久性标签。 许多跨平台安装程序以通用名称注册持久性(更新程序服务, helper.plist这个样本煞费苦心地选择了与各操作系统原生运行时代理相似的标签。命名是唯一的隐蔽尝试——没有rootkit,没有用户空间隐藏,也没有路径混淆。其目的在于,防御者很少会进行审计。 ~/.config/systemd/user/ 以及一项名为 python3-dbus-helper 在一般的评价中不会脱颖而出。

3. 过程标题的伪装是真实的,但反分析是休眠的。 Python有效载荷定义了一个 _disguise_process() 通过以下方式设置流程标题的函数 设置程序标题 (Linux/macOS)或 设置控制台标题W (Windows)——以及 主() 确实这么叫。所以 ps aux 将会呈现 python3-dbus-helper 而不是 python3 …/guardian.py然而,同一个模块定义了一个 is_monitor_running() 列举已知过程监控工具的函数(HTOP, btop(例如任务管理器、活动监视器、进程黑客、资源监视器、GNOME/KDE/Xfce/MATE 系统监视器等等)——以及 主() 它从未被调用。无论用户是否打开进程监视器,替换循环都会无条件运行。该函数在已发布的版本中已失效。它很可能是早期迭代遗留下来的代码,或是尚未实现的功能的框架。无论如何,已发布的有效载荷的反分析手段仅仅是重命名进程名称,而不是主动规避监视器。

4. 捆绑配置合并行为。 npm-install.js 将默认钱包列表写入 ~/.config/clipboard-guardian/config.json 如果配置文件已存在,则会合并所有现有值为空的键。这意味着之前已被感染并部分清理过配置文件的用户(例如,通过清空配置文件)也会受到影响。 复仇 该值会在每次后续恶意软件安装时重新填充。任何代码路径中都不会清理持久化文件。

日期/时间(UTC) 创建
2026-05-21 18:50:32 @jaggle/resizeobserves@1.0.0 出版。
2026-05-21 19:55:55 1.0.1 发布——第一个版本被外部扫描标记。
2026-05-21 19:58:10 1.0.2 出版。
2026-05-21 20:05:03 1.0.3 出版。
2026-05-21 20:09:24 1.0.4 出版。
2026-05-21 20:13:48 1.0.5 出版。
2026-05-21 20:41:52 1.0.6 出版。
2026-05-21 20:43:56 1.0.7 已发布 — 添加一个 try/catch 对 wallet-config 写入步骤的封装 npm-install.js.
2026-05-21 20:46:15 1.0.8 发布 — 安装程序已重命名 npm-install.jsnpm-install.cjs (字节相同的内容)。
2026-05-22 裁决和国际奥委会意见书已发布。版本在发布时仍保留在注册表中(持续更新)。

一小时五十六分钟内发布九个版本,即使对于一个拼写错误占位符来说也相当快了。这种模式与……一致 发布即销毁活动 — 使用一个句柄向注册表中大量写入数据,让检测过程自行完成,并在删除单个版本后切换到新的句柄。运行过程中可见的差异仅为外观上的:1.0.1 版本添加了显式的 /usr/bin/pip31.0.7 版本将 pip 搜索列表的路径样式改为了 sudo 兼容模式,并将 wallet-config 写入操作封装在 try/catch 语句中,1.0.8 版本则将安装程序重命名为 -style 格式。 JS。.cjs 同时保持其内容字节完全相同。 .cjs 重命名曲目时,npm 会发出关于包中模块解析不明确的警告,提示缺少显式模块解析。 “类型” 这或许是为了抑制安装时可能引起注意的干扰。Python有效载荷——唯一真正窃取数据的部分——在所有九个版本中都保持不变。

妥协指标

生态系统 小包装 选项 状态
NPM @jaggle/resizeobserves 1.0.0 通过 1.0.8 发布时已上线;已要求下架。

文件与灰烬

途径 笔记
clipboard_guardian/guardian.py
(md5 f7935c2c82bc881288611ab6cd634f17)
所有九个已出版版本均相同(1.0.0 通过 1.0.8)快船有效载荷。
npm-install.js (1.0.0 – 1.0.7)
npm-install.cjs (1.0.8)
持久化安装程序;端到端行为相同。 1.0.7's .js1.0.8's .cjs 字节完全相同。
~/.config/clipboard-guardian/config.json Linux 持久化配置和钱包包。
~/Library/Application Support/clipboard-guardian/config.json macOS 持久化配置和钱包包。
%APPDATA%\clipboard-guardian\config.json Windows 持久化配置和钱包包。
~/.config/systemd/user/python3-dbus-helper.service Linux 自动启动持久化。
~/Library/LaunchAgents/com.apple.python.runtime.plist macOS LaunchAgent 持久化。
~/Library/Logs/com.apple.python.runtime.log 代理的 macOS 标准输出/标准错误日志。
Scheduled Task PyRuntimeBroker Windows 自动启动任务(AtLogOn(无超时)。

行为指标

信号 描述
pip install --break-system-packages 来自 npm postinstall 强制全站安装 Python,绕过 PEP 668 保护措施。
apt-get install -y xclip (或吃豆人/dnf) 在Linux系统上安装软件包时,安装剪贴板实用程序。
python3-dbus-helper.service systemd 用户单元 持久化程序注册在一个看起来很合理的运行时辅助程序名称下。
com.apple.python.runtime 启动代理 持久化标签位于合法的苹果系统路径之外。
PyRuntimeBroker 计划任务 伪造的 Windows 运行时代理持久化机制,没有合法的安装程序来源。
Python进程名为 python3-dbus-helper 输入 pyperclippsutil 显示的进程名称与导入的库不匹配。
钱包地址复制后约 0.4 秒剪贴板发生变化 加密货币地址替换的特征行为。

攻击者钱包捆绑包(防御者猎杀列表)

钱包列表是硬编码在系统中的。 npm-install.jsclipboard_guardian/guardian.py防御者可以将此列表用作黑名单(将企业钱包向这些地址的任何转账视为可疑交易)和狩猎密钥(将未经身份验证的配置文件、构建工件或开发人员机器中出现的任何这些字符串视为感染指标)。

攻击者钱包捆绑包

链条类型 地址
以太坊/BSC 0x450c0E58Fc2ba03632d3F5780ad8C966648B6F18
浪人(EVM) ronin:450c0E58Fc2ba03632d3F5780ad8C966648B6F18
比特币 bc1qs2mpls4p0f7fng073gy2rcdgjpf7la4eugpt6y
比特币现金 bitcoincash:qqmvyxxklzp7l3eslxavhc8phl6hprdf25lwc29nlt
莱特币 ltc1qnefc8x59a9cwtqnflt8hmqvezqw4hc7lt3fkqe
多吉币 DNEJmYRZtzyK44tZea4S7wV3otTyRk48Fy
Dash 达世币 XtJ7E6mnhPK93Vib29PGQrTmQjhTTqFwbS
ZCash t1d4hcEnBjdh9X6Wb6R2dxqjnxddJ6ocP8M
DigiByte DPmH2dhiGK3hk3A69tZUMz6tHzGFHBzSrH
Monero 42zhAidVhP7QETk83JAspS59ASALSHFio44vmu6MdDCz15cSqtqsG4QVyzY8vTrjGrTEA6zMbWW6Yft1Ynz1xLfCN5FVbXf
索拉纳 DWBAmQLi9gP6mk7UfJfQGYTV1UPK32WekLTqg83q1mc5
创新福星 TVgEgMemmJABYYnbNr1Wi8bSgADEkdEBt2
TON UQDTSkvwmptU9eG988KgxS3WjnYAZlXgfpJxnz4mhWZAvULr
纹波 r9tj3cMCiqRijNYqNVYNuwKykkQfS8FE4H
波尔卡圆点 1JSkYqXQE4d28HdcmTPhbgCrdiPFTfSHxD67tam16p53oBG
5d6aec44551529e8cd9ebd3aaa84b3832fc3c7463596b2b6e72635b80096a364
宇宙 cosmos1pzfl3kv5g8g0ernj86rwpar08u2zl9suthx28e
Osmosis osmo1pzfl3kv5g8g0ernj86rwpar08u2zl9surv463t
勒斯蒂亚 celestia1pzfl3kv5g8g0ernj86rwpar08u2zl9su6ah6a5
内射 inj1g5xquk8u9wsrvvkn74uq4kxfvejgkmccn578gh
卡瓦 kava1kjfvgcz4q0y9yae2f3pa33vhj2estxxj3sqqux
和谐 one19hn0n7dzkhtl9ta9ekv5592s85jwstpka76t3a
terra1h0dwu8z405jagdlr0fgr9jllac2sxajzlgme5x
Algorand XSAMN3FTB5SUHUQFENBDDRXIMOPNFVLKAWA3RNOU54DWROMDZ6SR7DZ2PI
恒星 GACNZSV4EQO65NZZUOBS3TMJM7GFTSRNKQBVJOX5P2G7U7SEBQ2ZUDJE
卡尔达诺 addr1qyj050vla4cglmyrgm4vzf3dxtn0gynpks4t7vp7s3lg49e9wt0s94hcztzdgecxcz5hu9uk56q60yth6d66w026s2kq3ma56f
多元宇宙X erd1slvlgqsmwzk0c8xtksm4eq5vdfnc26slpzqsyxhz456zvme5rpasue6ge0
阿普托斯 0x580ecda1ebd6ca5a46be2097568d013308bd54ef1d147acb880b59f7709f280e
0xf7e8a9a970fa65c058745c4b2cf2a856cc0283863e4ed1e142648f26097b0c78
纳米 nano_393n56a5pfz8zg3nkzf7mytfgagzhu5mn9i3xiqg54weq8n1u8jgezxas7dn
Filecoin f1fypyww3xubopfnv7q6yh5l4bko44wmfktf3ckui
Tezos tz1RccjnorHk61bt73ArLXcdgFjEj6T1ochk
ERGO 9g1pNQGnFg7Hk1d9Z66bgHMkguGU7R41btypAnbG1NF5FJoNdBA
常春藤 0.0.10488092

默认配置中钱包槽位为空但正则表达式覆盖的链(例如 Sei、IOTA、Kaspa、Flow、Nervos、Decred、Ravencoin 和 Beacon-Chain BNB)在此版本中不会被主动替换,但会被检测到。请将它们视为监控范围而非替换范围。

归因与动机

该广告系列的归因分析数据有限。我们尚未能确认运营者的身份。我们可以记录的信息如下:

  • 发布商元数据。 npm 帐户 晃动 其电子邮件地址列为 olgascarlet@deltajohnsons.com. 域 deltajohnsons.com 无法解析为我们可验证的企业身份。npm 帐户未显示电子邮件验证,也没有其他信息。 SCM 已验证。没有关联的公开 GitHub 实例。
  • 存储库字段。的package.json 不携带 知识库 领域。合法的 npm:@juggle/resize-observer 指向一个拥有数千颗星和活跃 issue 的真实 GitHub 代码库。缺少代码库链接是 npm 用户界面上最直观的判断依据。
  • README文件抄袭。 该软件包的 README 文件是合法的。 @juggle/resize-observer README 逐字节说明,包括 进口 引用示例 @juggle/resize-observer 是程序本身(而非发布包)。运营者甚至懒得重写导入语句——这通常表明README文件是直接照搬而非修改的。
  • 没有可以依靠的基础设施。 没有C2端点,没有DNS查询,也没有IP地址。恶意行为完全封装在本地的Clipper程序和硬编码的钱包包中。这使得基于域名或ASN的横向移动攻击无法进行。跨攻击活动进行横向移动的防御者应该将钱包与之前存档的Clipper程序进行哈希匹配;在不同攻击包中重复使用钱包是最容易追踪的跨攻击活动关联。
  • 命名选择。 @jaggle/resizeobserves 比……少一个字符 @juggle 与众所周知的稍稍不同 调整大小观察者合并后的编辑距离为两个字形。这是一种刻意营造的视觉碰撞效果,并非普通的蹲姿。

动机源于有效载荷行为:纯粹通过机会主义的剪贴板替换进行货币化。不涉及凭证窃取、主机指纹识别或环境变量读取。攻击者并不关心受害者是谁——他们只关心受害者的下一次转账是否指向已列出的地址之一。四十条链的覆盖范围就像是彩票模型:广撒网,希望每 N 次安装中能有一次高价值的粘贴内容命中。

该运营者似乎并不担心被下架。在两小时内发布九个相同版本的恶意软件,这明显是一种“发布即销毁”的策略:在下架延迟到来之前,尽可能扩大其在注册表中的占用空间,然后继续下一步。我们尚未观察到 @jaggle 撰写本文时,该出版物已根据新的范围重新出版,但我们预计会出现类似的范围(@jaggie, @juggle-, @啮合如果运营商仍然活跃,则将在未来几天内出现。

影响、趋势及防守者应采取的措施

 冲击

根据现有数据集,无法量化实际影响。该剪币器不写入遥测数据,且截至分析截止日期,尚未观察到钱包接收到替代转账(我们计划对列出的链进行后续扫描)。合法 npm:@juggle/resize-observer 平均每周下载量高达七位数——这是一个高流量的域名抢注目标——而且该恶意软件在披露时上线时间不到 24 小时,这限制了受影响的人群,但并没有使其为零。

值得追踪的爆炸半径并非直接下载 @jaggle/resizeobserves — 这些可能很小。这是**传递安装**:开发人员将软件包添加到沙盒项目中,运行 npm安装然后,他们忘记了安装钩子曾经运行过。现在,所有处理过安装后处理的机器都会自动运行一个针对每个用户的剪贴板劫持程序,无论项目是否仍在磁盘上。从……中移除包目录 节点模块 **不会**移除持久性。

新兴模式

此次活动体现了两大趋势。

npm 作为 Python 有效载荷传递包装器。 npm tarball 是一个 4 行的安装程序;真正窃取资源的是 Python,它通过系统级安装的方式获取资源。 点子 从捆绑目录中。这并非新鲜事——我们之前就见过 npm 包放弃 Python——但这在加密剪贴板攻击活动中正变得越来越普遍。对攻击者而言,优势有两方面:Python 剪贴板库(pyperclip 其中最重要的是)比 JavaScript 等效代码更简洁、更具跨平台性,而且 大多数自动化的 npm 扫描器对 JavaScript 文件和 Python 文件赋予很高的权重。 的.py 轻轻地捆扎起来。 代价是安装体积更大,噪音也更大——一个全新的 点安装 在通常不会出现问题的开发人员机器上很难隐藏。 点安装 ,我们将参加 npm安装.

平台原生名称是唯一的隐蔽手段。 最近一些代码剪辑器和小有效载荷窃取器完全放弃了代码级混淆,转而使用看起来很合法的持久化标签。 python3-dbus-helper, com.apple.python.runtimePyRuntimeBroker 这些都是典型的例子——在四十个用户服务列表中,防御者会忽略这些名称。这是一种廉价而持久的隐蔽手段:虽然下架是针对每个软件包的,但持久化文件却能幸存下来,而且一个以看似真实的平台组件命名的服务,除了明确的审计之外,不会受到任何影响。

防守队员应该怎么做

  • 审核 ~/.config/systemd/user/、~/Library/LaunchAgents/ 和 Get-ScheduledTask 产量 在开发者机器上,IOC 中列出的条目仍然存在。移除 npm 包后,这些条目仍然保留;需要手动移除。
  • 阻止向列出的钱包地址进行转账 在公司财务部门和 DeFi 钱包边界,地址允许列表可用。
  • 查找 ~/.config/clipboard-guardian/config.json (以及平台上的同等版本)在开发者的所有机器上均存在。无论该文件是由哪个软件包版本提供的,只要存在该文件,就高度确信已感染病毒。
  • 在 node_modules/ 目录中查找 clipboard_guardian/guardian.py 文件。 在可能早于文件下架的构建缓存快照中,该文件的 MD5 值在所有已审核的版本中均保持稳定。
  • Lockfile-pin @juggle/resize-observer (合法的软件包),因此,即使输入一个字符错误,未来的安装也不会解析成其他任何内容,尤其是在没有锁定文件的工作流程中,例如 像素.
  • 将任何调用 pip install 的 npm postinstall 操作都视为已完成 严重程度高 内置-pipeline 政策方面,npm 包在安装时没有理由需要 pip——Python 工具集本身就包含 Python 工具集。
  • 搜索名为 python3-dbus-helper 且导入了 pyperclip 的进程的 process_iter() 可比较的监控数据 — 伪装不匹配(D-Bus 助手持有剪贴板库)是我们拥有的最清晰的行为指标。
  • 轮换从受感染机器粘贴的钱包地址。 剪贴板劫持程序会破坏钱包用户界面和粘贴目标之间的路径;在感染期间复制的地址可能会被悄悄篡改。在感染期间发送的任何信息都应视为可能被错误发送。

关键在于:持久性比下架更持久。注册表最终会被删除。 @jaggle/resizeobserves 在所有九个版本中,systemd 单元、LaunchAgent 和 Scheduled Task 都不会自行删除。

案例

sca-tools-软件-成分分析工具
确定软件风险的优先级、进行补救并加以保护
注册免费账号。
不需要信用卡。

保护您的软件开发和交付

使用 Xygeni 产品套件