DevTap npm 拼写错误攻击

DevTap npm 域名抢注攻击:六个恶意软件包瞄准开发者工作站

TL博士

2026年4月1日至5月3日期间,单个npm发布者, user0001使用未经验证的 Gmail 地址注册 tanvisoul9@gmail.com悄悄地推送了六个软件包,这些软件包的名称刻意平淡无奇,听起来像是基础设施相关的名称: centralogger, dom-utils-lite, node-fetch-lite, connector-agent, node-gyp-runtimenode-env-resolve.

最新两个版本的 node-env-resolve1.0.7 和 1.0.8 版本于 5 月 2 日被 Xygeni 的恶意软件预警 (MEW) 系统标记,并于 5 月 3 日确认为恶意版本。

该植入程序不同寻常之处在于它不具备的功能:没有 Telegram 机器人,没有 OAST 回调,也没有其他任何功能。 困惑并且没有尝试在安装时获取 AWS 凭证。相反, postinstall.js 使用 HKCU Run 键启动 Windows 启动持久化项 wscript.exe 针对 VBS 存根。然后它会生成一个分离的 Node.js 代理,该代理捆绑了用于麦克风捕获、浏览器历史记录窃取、屏幕截图和鼠标/键盘模拟的模块。

我们将这个集群称为“集群”。 DevTap之后,该工具包会在开发者的机器上运行。

截至发稿时,这六个软件包均已上线 npm。我们已将它们提交至注册表的滥用举报渠道。维护者应在移除前从发布者处撤下所有安装。

集群:六个软件包,一个出版商

出版商账户 user0001 未经证实。它没有 SCM 已验证,无域名绑定邮箱,且无历史记录。Gmail 账号 tanvisoul9 在我们能找到的任何其他 npm 发布者记录中都没有出现。

这六个软件包的维护者相同,均由同一账户发布,且共享相同的资源。 package.json 模板。没有。 repository,无 homepage, 和不 description 比一行更长。

命名策略才是最有趣的部分。与传统的依赖关系混乱或域名抢注不同,这些名称都不针对特定的上游库。相反,它们的设计旨在融入真实的命名环境中。 package.json or npm ls 输出。

小包装 首次发布 最新版本 选项 在集群中的角色
中央记录器 2026-04-01 12:46 UTC 1.0.9 5,从 1.0.5 到 1.0.9 集群的“日志实用程序”封面;最早发布
dom-utils-lite 2026-04-14 07:36 UTC 1.0.3 3 通用 DOM 辅助函数覆盖
node-fetch-lite 2026-04-19 10:22 UTC 1.0.2 3 模仿节点获取系列
连接器代理 2026-04-25 05:12 UTC 1.0.0 1 通用名称“代理”
node-gyp-runtime 2026-04-25 05:17 UTC 1.0.0 1 模仿原生模块构建工具
node-env-resolve 2026-04-25 05:21 UTC 1.0.9 10,从 1.0.0 到 1.0.9 主动式滴管;全植入

名字像 centralogger, node-fetch-litenode-gyp-runtime 这些语句旨在避免在代码审查中引起争议。它们听起来像是项目依赖树中原本就应该存在的内容。

再加上未经核实的新发布者和缺失的存储库链接,这些因素共同构成了一种可识别的模式:攻击者先在注册表中植入一些无关紧要的名称,然后迅速迭代,最终锁定真正重要的名称。在本例中, node-env-resolve 八天内收到了十个版本。

Windows 开发机上会装些什么呢?

恶意链 node-env-resolve:1.0.8 对于 npm RAT 来说,它简短、直接且功能异常丰富。

安装后:持久性和分离代理

package.json 声明一个安装钩子:

{ "scripts": { "postinstall": "node postinstall.js" } }

postinstall.js 按顺序做三件事。

首先,它会在 npm 树之外创建一个安装目录。该路径在脚本运行时计算得出。 INSTALL_DIR然后它运行一个内部程序 execSync('npm install --production --silent ...') 在其中拉取植入程序的运行时依赖项。这会将代理程序手动放置在磁盘上的某个位置。 node_modules 审计不会发现。

其次,它编写一个 VBS 启动器并将其注册为启动持久化程序:

reg add HKCU\Software\Microsoft\Windows\CurrentVersion\Run \
    /v ${AGENT_NAME} \
    /t REG_SZ \
    /d "wscript.exe \"${vbsPath}\"" /f

wscript.exe 是 Windows 脚本宿主程序,这是一个经过签名的 Microsoft 二进制文件,运行于 .vbs 没有控制台窗口的文件。那是预处理文件。cis这就是为什么它被青睐用于自动运行存根的原因。

还有一个匹配项 reg delete 路径内部 src/index.js这表明该植入物的设计使其能够根据操作者的指令轻松移除。

第三,它会生成一个分离的子进程:

spawn(node, [path.join(INSTALL_DIR, 'src/index.js')], {
  detached: true,
  env: { ...process.env, SERVER_URL }
})

这里有两个细节很重要。

SERVER_URL 是从环境中读取的。因此,C2 端点是可针对每个部署进行配置的,而不是预先集成到软件包中的。这个虽小但经过深思熟虑的选择可以绕过大多数静态 IOC 扫描。

此外,生成的子进程会继承父进程的完整环境。因此,任何 NPM_TOKEN, AWS_*, GITHUB_TOKEN或者,在安装时存在于开发者 shell 中的 SSH 代理套接字会进入长期存在的代理的内存中。

特工随附物品

捆绑的 src/ 树状结构包含三个模块,单从它们的名称就能看出其含义: audioCapture.js, browserHistory.jssystemInfo.js.

运行时依赖项列表,在暂存期间解析 npm install证实了这一点。

这种方法可以将混乱的事件转化为可控的应对措施。

团队不会盲目反应,而是会积极行动。 明确的优先级和快速的补救措施.

依赖 在此语境下它的用途是什么?
屏幕截图-桌面 定期屏幕截图
@nut-tree-fork/nut-js 鼠标和键盘自动化/输入模拟
更好的sqlite3 直接读取 Chrome、Edge 和 Firefox 的历史记录 SQLite 数据库
管理员压缩 在撤离前将收集到的文物捆扎起来。
尖锐 调整屏幕截图大小/压缩以及图像瑕疵
socket.io客户端 持续双向C2通道
节点机器 ID 用于受害者追踪的稳定主机指纹

systemInfo.js 电话 os.networkInterfaces() 在第一个信标之前进行额外的指纹采集。

为什么音频采集是突出的信号

在 MEW 中,我们筛选出的大多数 npm RAT 都止步于安装时窃取机密信息。它们会读取信息。 ~/.npmrc,读 ~/.aws/credentials刮擦 process.env然后向 webhook 发送 POST 请求,最后退出。这符合“速战速决”的经济模式。凭证的有效期很短,攻击者需要迅速获利。

node-env-resolve 形状不同。

持久化设置旨在确保重启后仍然存在。代理程序以分离模式运行,并具有较长的生命周期。 wscript.exe它携带的工具包是为开发者的机器准备的,而不是为了拿走就走:麦克风录音机、键盘/鼠标驱动程序、完整的浏览器历史记录采集、屏幕截图以及与可配置的 C2 服务器之间的交互式 Socket.IO 通道。

尤其值得一提的是,该恶意软件攻击手段包括麦克风捕获,而大多数 npm 恶意软件则不会这样做。

如今,开发者工作站越来越多地成为开发者进行站会、客户电话、设计讨论和值班的场所。植入式麦克风录音设备并非真正想要记录开发者的 npm 令牌,而是想要记录开发者在笔记本电脑前所说的话。

这种能力组合,加上缺乏混淆和没有任何花哨的安装时数据泄露,表明这是为了有针对性地访问而预先部署,而不是为了伺机窃取凭证。

我们并非仅凭此就断定归因。我们只是注意到其运行模式。

npm 拼写错误抢注攻击 - DevTab

八天的迭代节奏 node-env-resolve 这是时间线中最具实际意义的细节。

这并非一次性投放。发布者正在积极维护投放器,这通常意味着以下两种情况之一:要么他们在大规模部署前针对测试环境进行调优,要么他们已经收到安装遥测数据并正在做出相应调整。

其他五个软件包在首次发布后几乎没有进行任何更改。这符合“一次部署,保留原名”的支持集群模式,而工程工作则集中在执行实际工作的软件包上。

归属:线索虽少,但结论尚不明确

公共 OSINT 信号很弱,我们不会对其进行拉伸。可观察的是:

Gmail 用户名 tanvisoul9 部分类似于南亚名字“Tanvi”。这是一个微弱的信号。Gmail用户名并不能代表身份,而且末尾的 soul9 这是通用信息。仅凭电子邮件的本地部分来推断地理位置是不安全的。

Node.js 的代码风格平平无奇: standard 库调用,例如 os, child_process, spawnreg add这里没有使用任何混淆技术、字符串轮换或反调试逻辑。作者熟悉 Windows 注册表原语和分离子进程编排,但似乎并没有采用他们可能使用的更隐蔽的手段。

依赖项完全是现成的,并且众所周知: screenshot-desktop, nut-js, better-sqlite3socket.io-client没有自定义协议,没有从零开始构建的C2协议栈,也没有任何超出教科书范畴的新颖持久化技巧。 HKCU 运行键这是一位称职的集成商,而不是工具开发者。

我们在已发布的工件中没有发现非英语字符串、嵌入式注释、区域设置数据或编译器输出时区指纹。

我们检查了代码是否与我们已跟踪的先前活动存在重叠,包括 沙伊胡鲁德, 猫头鹰之殇Buildkite,以及最近的黑白/ claude-code-best Anthropic-CLI 克隆家族。我们没有发现任何克隆:没有共享的 C2 模式,没有共享的文件布局,也没有共享的惯用法。

我们不会说:这是一个国家行为体、一个已知组织,或者与任何特定国家有地理上的联系。

行动模式与一支规模较小、技术水平中等的团队执行开发者工作站监视任务相符。其动机很可能是为了从下游利用访问权限获取经济利益,但也可能是为了向其他买家提供侦察服务。

有两个间接点支持这一观点:一是避免使用会迅速耗尽集群资源的引人注目的数据外泄机制,例如 Telegram 机器人; oastify.com或者说 canarytokens,以及刻意平淡的软件包名称,这种做法有利于安静的长期安装,而不是短暂的高流量高峰。

入侵和检测指标

软件包和发布者
领域 价值
npm 发布者 user0001
出版商电子邮件 tanvisoul9@gmail.com,未经核实
centralogger、dom-utils-lite、node-fetch-lite、connector-agent、node-gyp-runtime、node-env-resolve
已确认恶意行为 node-env-resolve@1.0.7,node-env-resolve@1.0.8
宿主工件
类型 价值
持久键 HKCU \软件\微软\ Windows \ CurrentVersion \运行
持久性值 变量名;数据格式为 wscript.exe“ \\ .vbs”
安装钩子 postinstall:在包清单中运行 postinstall.js 文件
植入模块 src/audioCapture.js、src/browserHistory.js、src/systemInfo.js
暂存目录 INSTALL_DIR 解析于项目 node_modules 目录之外;该位置由 postinstall.js 在安装时设置。
网络
类型 价值
C2运输 socket.io-client,持久双向通道
C2 终点 通过 SERVER_URL 环境变量提供给代理;不会硬编码到已发布的工件中。

检测记录

两条规则可以捕获这个家族,而无需 C2 端点。

首先,标记执行内部操作的安装后脚本。 npm install 放到软件包自身目录之外的路径中。任何合法的预编译下载器,例如 node-gyp 重新构建或预构建二进制下载器,写入软件包内部或平台内部standard 缓存路径包含已验证的哈希值。它不会写入新创建的缓存路径。 INSTALL_DIR 磁盘上的其他位置。

其次,标记发出以下问题的安装后脚本 reg add HKCU\…\Run - wscript.exe 作为启动器。这基本上从来都不是 npm 包的合法行为。请标记并隔离它。

第三种启发式方法可用于在确认之前发现下一个同级包:一个全新的 npm 发布者,没有 SCM 验证方式,Gmail邮箱,无 repository 仅凭这一点,以及几天内发布的多个简短、通用、听起来像基础设施的软件包名称,就足以引起人工审查的必要性。

已向 npm 注册表报告。我们将在发布者帐户被移除后更新此帖。

sca-tools-软件-成分分析工具
确定软件风险的优先级、进行补救并加以保护
7-day免费试用
无需信用卡

保护您的软件开发和交付

使用 Xygeni 产品套件