npm 上的 node-ipc 被攻陷:通过 DNS 渗透窃取凭据

摘要

三个版本的 node-ipc(9.1.6、9.2.3、12.0.1)于 2026 年 5 月 14 日被一个遭到入侵的维护者账户(atiertant)发布到 npm。每个版本都包含相同的 80KB 混淆有效载荷,附加到 node-ipc.cjs,窃取超过 100 类敏感文件(SSH 密钥、云服务提供商凭据、.env 文件、Kubernetes 配置、AI 工具配置),并通过 DNS 隧道以 gzip 压缩的 tar 归档形式外传数据。该包的周均下载量为 822,000 次

影响范围:​

  • 窃取 SSH 密钥、AWS/Azure/GCP 凭据、.npmrc.env 文件、Kubernetes 配置等(Linux 系统上 113 个目标路径,macOS 系统上 127 个)
  • 通过 DNS TXT 记录查询以外传收集到的数据,使用 HMAC 签名和 gzip 压缩的 tar 归档
  • 创建一个分离的子进程用于后台执行,即使父进程退出也能继续运行
  • 专门针对 AI 编程工具配置(.claude.json.kiro/settings/mcp.json

失陷指标(IoC):​

  • 软件包:[email protected](SHA-256:449e4265979b5fdb2d3446c021af437e815debd66de7da2fe54f1ad93cbcc75e)、[email protected](SHA-256:c2f4dc64aec4631540a568e88932b61daebbfb7e8281b812fa01b7215f9be9ea)、[email protected](SHA-256:78a82d93b4f580835f5823b85a3d9ee1f03a15ee6f0e01b4eac86252a7002981
  • 注入的有效载荷 SHA-256:3427a90c8cb9af764445448648176e120ebc6af0a538158340cf6220de4d01b7
  • C2 端点:sh[.]azurestaticprovider[.]net:443
  • HMAC 签名密钥:qZ8pL3vNxR9wKmTyHbVcFgDsJaEoUi
  • 防重复执行环境变量:__ntw=1
  • 临时目录模式:~/nt-{PID}/
  • 归档文件名模式:{hmac}.tar.gz
  • 发布账户:atiertant[email protected]

分析

软件包概述

node-ipc 是一个广泛使用的 Node.js 进程间通信库,支持 Unix/Windows 套接字、TCP 和 UDP。npm 注册表显示其过去一周的下载量为 822,257 次。该软件包有一个值得关注的历史记录:2022 年 3 月,原始维护者(riaevangelist)故意引入了抗议软件有效载荷,针对来自俄罗斯和白俄罗斯 IP 地址的用户(CVE-2022-23812)。

这次的入侵事件有所不同。2026 年 5 月 14 日,三个版本在几分钟内相继发布,全部由 atiertant 发布,这位合作维护者的账户可能已被攻陷:

bash
$ curl -s "https://registry.npmjs.org/node-ipc" | jq '.time | {"9.1.6", "9.2.3", "12.0.1"}'
json
{ "9.1.6": "2026-05-14T14:26:25.106Z", "9.2.3": "2026-05-14T14:26:01.584Z", "12.0.1": "2026-05-14T14:25:30.311Z" }

干净版本(9.1.5、12.0.0)由原始维护者 riaevangelist 发布。三个恶意版本均由 atiertant 发布,该维护者大约在 npm 上维护着 20 个其他软件包。12.0.1 版本被标记为 latest,这意味着任何 npm install node-ipc(未指定固定版本)的用户都会获取到被植入恶意代码的版本。

入口点和有效载荷注入

攻击者的策略在不同的版本线上有所不同。对于 12.0.1,与 12.0.0 的差异显示 package.json 有两处变更:

diff
// package.json diff: 12.0.0 → 12.0.1 "version": "12.0.0", "version": "12.0.1", "prepare": "esbuild node-ipc.js --bundle --format=cjs --target=es2018 --platform=node --outfile=node-ipc.cjs",

prepare 脚本被移除,node-ipc.cjs 被替换为包含有效载荷的预编译捆绑包。没有安装钩子。当 node-ipc.cjsrequire() 时,恶意代码作为副作用运行。

注入点在 node-ipc.cjs 的第 1271 行,紧接在合法模块的 module.exports 赋值之后:

javascript
// node-ipc.cjs — line 1269 (legitimate) module.exports = singleton; // line 1271 — injected payload begins (function(_0xaed59b,_0x282d65){var _0x4524e4=_0x1a49,_0x41d0c3=...

附加的有效载荷是 80,079 字节的混淆 JavaScript 代码。三个被入侵的版本包含字节完全相同的有效载荷(SHA-256:3427a90c8cb9af764445448648176e120ebc6af0a538158340cf6220de4d01b7)。

对于 9.1.6,攻击者更进一步。版本 9.1.5 原本没有 node-ipc.cjs 文件。攻击者添加了它,将 package.json 改为设置 "main": "node-ipc.cjs"(同时支持 ESM 和 CJS 导出),并将整个包结构升级以匹配 12.x 版本线。这个重新构建的捆绑包携带了相同的有效载荷。

混淆与反混淆

该有效载荷使用了标准 JavaScript 混淆器,带有轮换字符串查找数组。一个 443 元素的字符串数组(_0x3afe)在加载时被乱序,直到校验和匹配 0xb5c88。所有字符串字面量都通过 _0x1a49(index) 进行索引查找访问,控制流使用带有间接函数调用的辅助对象。

敏感字符串(C2 地址、HMAC 密钥和文件路径列表)使用了一层额外的保护:一种自定义的十六进制编码,其中十六进制数字 af 被替换为 GHJKMP(跳过了容易与数字混淆的字母)。最后一个字符用作校验和。解码时半字节顺序是反转的(低位半字节优先)。

将这应用于三个编码的常量:

编码后解码后
3786M216G757275637471...34343339sh.azurestaticprovider.net:443
17G58307J43367M487259...54P655966qZ8pL3vNxR9wKmTyHbVcFgDsJaEoUi
2647M2M6P64656M2G637Hbt.node.js

还有两个额外的编码字符串(分别为 5,141 和 5,601 个字符),解码为平台特定的的文件路径列表。

目标凭据

该有效载荷根据 os.platform() 选择目标列表。Linux 列表包含 113 个 glob 模式;macOS(darwin)列表包含 127 个。以下是部分目标路径的示例:

云服务提供商凭据:​

plaintext
~/.aws/credentials ~/.aws/sso/cache/* ~/.azure/accessTokens.json ~/.azure/msal_token_cache.* ~/.config/gcloud/application_default_credentials.json ~/.config/gcloud/credentials.db ~/.oci/config ~/.config/doctl/config.yaml ~/.aliyun/config.json ~/.bluemix/config.json

SSH 和 Git 凭据:​

plaintext
~/.ssh/id_rsa ~/.ssh/id_ed25519 ~/.ssh/id_ecdsa ~/.ssh/authorized_keys ~/.ssh/config ~/.git-credentials ~/.gitconfig

开发环境密钥:​

plaintext
**/.env **/.env.local **/.env.production ~/.npmrc ~/.pypirc ~/.netrc ~/.docker/config.json

Kubernetes 和基础设施:​

plaintext
~/.kube/config /etc/rancher/k3s/k3s.yaml ~/.terraform.d/credentials.tfrc.json **/terraform.tfvars /var/run/secrets/kubernetes.io/serviceaccount/token

AI 编程工具配置:​

plaintext
~/.claude.json ~/.claude/mcp.json .kiro/settings/mcp.json

CI/CD 和 DevOps:​

plaintext
**/.github/workflows/ci.yml **/.github/workflows/deploy.yml **/.github/workflows/release.yml **/.gitlab-ci.yml /etc/gitlab-runner/config.toml

值得注意的是 .claude.json.claude/mcp.json.kiro/settings/mcp.json 的包含。这些是 AI 编程助手的配置文件,可能包含 MCP 服务器凭据和 API 密钥。这表明攻击者正在跟踪 AI 开发工具的采用情况,并专门针对其凭据存储。

数据收集与归档创建

恶意软件的执行流程,从 _0x541368 中的混淆 switch-case 结构重构而来:

  1. ~/nt-{PID}/ 创建临时目录
  2. 生成随机字节,使用硬编码密钥派生 HMAC 签名
  3. 解析系统主机名
  4. 遍历文件路径列表,展开 glob 并读取匹配的文件
  5. 将收集的文件打包成 tar 归档(使用 ustar 格式头手动实现 tar)
  6. 使用 zlib.gzipSync() 压缩
  7. 将归档写入 ~/nt-{PID}/{hmac}.tar.gz

然后归档被外传,临时文件被删除。

DNS 外传

该有效载荷通过 DNS TXT 记录查询外传数据。这种技术绕过了大多数出口防火墙和网络监控,因为 DNS 流量很少在应用层被检查。

外传函数(_0x39bb3b)的工作原理如下:

  1. 将 gzip 压缩的归档分割成适合 DNS 标签大小的块
  2. 将每个块编码为 base64
  3. 构建包含 machineHexcloudarchivePathgzipBytes、块计数和 hostLabel 的 JSON 元数据头
  4. 使用硬编码密钥以及 |p|t 后缀对头和数据块进行 HMAC 签名
  5. 构建 DNS 查询域:{chunk}.{sig}.{metadata}.{c2_domain}
  6. 通过 dns.Resolver 发送查询,使用自定义 DNS 服务器(1.1.1.18.8.8.8
  7. 发送包含总块计数的最终“完成”消息

C2 域 sh[.]azurestaticprovider[.]net 旨在乍看之下与合法的 Azure 静态 Web 应用基础设施相融合。

持久化机制

该有效载荷使用 child_process.fork() 生成一个分离的后台进程:

javascript
// Reconstructed from obfuscated code child_process.fork(modulePath, [], { cwd: process.cwd(), detached: true, stdio: 'ignore', // String.fromCharCode(0x69,0x67,0x6e,0x6f,0x72,0x65) env: { ...process.env, __ntw: '1' }, // anti-re-execution flag });

__ntw 环境变量防止分叉的子进程再次分叉。分离的进程在父 Node.js 进程退出后继续运行,使恶意软件有足够时间完成文件收集和 DNS 外传,即使导入它的应用程序快速关闭也是如此。

SHA-256 哈希比较(fdba4191831a13debf9d8c0c940b0301c7b7f01d27f1b1c73ed3ceaa2db4103b)在分叉前验证模块的文件路径,这可能是作为一种反分析措施,避免在意外环境中执行。

根本原因:维护者账户被接管

atiertant 账户一直是 npm 上 node-ipc 的合作维护者,与原始作者并列。该账户还维护着约 20 个其他软件包(node-turnasynkoffshore 等)。三个恶意版本在 56 秒内发布,跨越三个不同的主要版本线,并被标记为最大化安装覆盖范围(latestunpublishedlegacy-9.1)。

这一模式指向凭据泄露而非恶意维护者:同时发布多个版本且有效载荷完全相同表明使用了自动化工具,而且该有效载荷本身与 atiertant 维护者的正常发布活动毫无相似之处。

结论

这次入侵事件针对的是 npm 上下载量最高的 IPC 库之一,使用了复杂的凭据窃取器。攻击者选择 DNS 隧道而不是更简单的 HTTP 外传,使用 HMAC 签名有效载荷,实现自定义十六进制编码来隐藏失陷指标,并针对异常广泛的凭据集,包括 AI 工具配置。C2 域名模仿 Azure 基础设施命名。

如果您安装了 node-ipc 版本 9.1.6、9.2.3 或 12.0.1,请轮换受感染机器上的所有凭据。检查 ~/nt-*/ 临时目录和正在运行的分离 Node.js 进程。将版本固定到已知干净的版本(9.1.5、12.0.0),或使用 vet 进行审计,以在恶意版本到达 CI 之前标记它们。

  • npm
  • oss
  • malware
  • supply-chain
  • node-ipc
  • credential-theft
  • dns-exfiltration
  • account-takeover

来自 SafeDep 博客的最新内容

关注我们,获取开源安全与工程的最新更新和见解