ChainDropnpm蠕虫分析:Runner内存窃密、区块链C2与自传播"

admin 2026-10-17 07:03:51 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

ChainDrop npm 蠕虫分析:Runner 内存窃密、区块链 C2 与自传播

原创

Ti
Ti

TIPFactory情报工厂

2026年8月24日 20:20
江苏

在小说阅读器读本章

去阅读

ChainDrop 把一次 npm 包投毒扩展成了自动传播的供应链蠕虫。受污染包仍保留正常功能,只增加 setup.mjs、math_init.js 和一条 preinstall lifecycle hook;安装过程结束时没有明显错误,但后台载荷已经开始扫描开发者工作站、CI runner、云凭据与发布权限。

Unit 42 在调查中匹配到 453 个公开 GitHub 仓库、5 个账号,并在 10 个环境观察到执行。这个规模只是公开可见部分,不能直接等同于已确认受害组织数量,但说明攻击者正在利用开发者身份和自动化发布链持续放大影响。

从 preinstall 到 727 KB 混淆载荷

感染包的 package.json 只需增加一条命令:

{\"scripts\":{\"preinstall\":\"node setup.mjs\"}}

图 1:感染包通过 preinstall 在用户安装依赖前启动 dropper。

setup.mjs 首先检查 PATH 中是否存在 Bun;不存在时,按平台和架构从官方 Oven GitHub release 下载 Bun 1.3.13。Bun 本身没有遭入侵,它只是被用作跨平台执行器。随后 dropper 运行压缩成两行、约 727 KB 的 math_init.js,并删除临时 runtime 目录。

非 CI 环境中,payload 以 detached background process 运行,并设置 _NODE_RUNTIME_INIT=1 防止递归重启;CI 环境中则在 job 内联执行,因此 debug 输出可能留在 workflow log。载荷还检查系统语言,遇到俄语环境会直接输出退出提示并终止。

凭据收集与 Runner 内存读取

ChainDrop 搜索的目标远超 .npmrc:云 metadata 与短期 IAM token、GitHub/npm/PyPI/RubyGems 凭据、Docker/Helm、Terraform state、Vault token、SSH key、Kubernetes service account、kubeconfig、.env、shell history、wallet 文件以及多种开发和 AI 工具配置都在扫描范围内。

更关键的是,一个藏在加密 blob 中的 Python helper 会定位 GitHub Actions 的 Runner.Worker 进程,读取:

/proc/<pid>/maps
/proc/<pid>/mem

它在 live memory 中搜索 OIDC token 和 runner secret,而不是等待凭据写入磁盘。即使短期 token 会随 job 结束消失,只要恶意依赖在同一 runner 上执行,就可能在生命周期内完成提取。

图 2:从定位 Runner.Worker、解析内存映射到提取 OIDC token 与 secret 的流程。

VS Code 与 Claude Code 交叉持久化

蠕虫写入五个文件:

.claude/math_init.js
.claude/settings.json
.claude/setup.mjs
.vscode/setup.mjs
.vscode/tasks.json

.vscode/tasks.json 使用 folder-open task 调用 .claude/setup.mjs;.claude/settings.json 则在 SessionStart 调用 .vscode/setup.mjs。两个配置交叉引用,让每一侧看起来像另一工具的正常文件。

图 3:项目打开和 coding session 启动都可成为自动执行触发点。

这个样本存在实现缺陷:真正 payload 只写到 .claude/math_init.js,而 .vscode/setup.mjs 会寻找并不存在的 .vscode/math_init.js。因此已分析 build 中只有 VS Code 触发路径能执行到载荷。样本还携带 macOS LaunchAgent 与 Linux systemd user service installer,但主执行路径没有调用点,只能标记为潜在能力,不能写成已安装事实。

两条传播路径

常规自传播依赖被盗 npm token。只有 token 具备 package write 权限并可 bypass_2fa 时,蠕虫才会:

    1. 枚举账号可发布的包;
    1. 下载最新 tarball;
    1. 注入 dropper 和 payload;
    1. 修改 package.json 添加 preinstall;
    1. 增加 patch version,重新打包并发布。

它还会创建 .github/workflows/codeql_analysis.yml,把 ${{ toJSON(secrets) }} 序列化为 artifact;若持有 GitHub App token,可向最多 50 个可访问分支写入 .claude/settings.json 和 .vscode/tasks.json。

第二条路径专门检查 opensearch-js 和 release-drafter.yml。满足条件时,蠕虫不做常规收集,而是向 npm trusted-publishing exchange 请求 OIDC publish credential,再修改 @opensearch-project/opensearch 包。

图 4:静默路径不添加 lifecycle script,而是植入近似官方 scope 的 optionalDependencies。

发布前它还获取 Sigstore audience 的第二枚 OIDC token,通过 Fulcio 证书和 ephemeral P-256 key 生成 in-toto SLSA v1 provenance,写入 Rekor,并把 bundle 附加到 npm publish。该 provenance 不是伪造的:恶意 tarball 确实由证书指定的仓库和 workflow 构建。签名只证明构建来源,不证明 workflow 没有被攻击者控制。

Unit 42 没有观察到这条 OpenSearch 路径实际执行;它在 payload 主入口中可达且实现完整,应标记为可用但未观测能力。

Ethereum 智能合约作为 C2 路由器

payload 不硬编码 C2 domain,而是查询合约:

0xE1f2395ee43e45A1556EC6438a88c31B83493103

合约是一个简单的 StringListStore,支持读取 domain list、读取 owner 和 owner-only setter。蠕虫轮询约 60 个公共 Ethereum RPC provider,任何一个可用即可取得当前外传端点。合约不发 event,operator 改写字符串时不产生直观业务告警。

初始列表包含 npm-cache[.]com、pypi-get[.]com 和 js-mirror[.]com,随后缩减为 npm-cache[.]com。2026 年 8 月 4 日,operator 通过一次链上 transaction 把 active C2 切换为 awqhnjewqjkl[.]icu,已部署样本无需更新。

合约解析失败时,蠕虫搜索 GitHub commit 中的 thebeautifulmarchoftime,验证 RSA 签名后接受备用 domain;再失败则使用受害者账号建立 Dune 主题公开仓库外传。

返回代码执行与加密外传

domain-based sender 会读取 HTTP response,解析 JSON,并对 code 字段执行 eval。这让 operator 能按 UUID 向特定受害者返回第二阶段代码,且不必落盘。

图 5:外传请求完成后,客户端解析并执行 C2 返回的 code。

研究人员使用完全匹配的加密格式向 live endpoint 发送 dummy data,服务器返回 200 OK 和空 body。可确认代码通道存在,但测试时可能处于关闭、按受害者条件 gate,或采用异步下发;不能声称 C2 已向该 probe 返回第二阶段。

收集结果先 JSON serialize 和 gzip,再用随机 AES-256-GCM key 加密;AES key 使用内嵌 RSA public key,以 RSA-OAEP-SHA256 包装。请求包含 encrypted envelope、wrapped key 和 host-derived UUID。

图 6:C2 请求中的 envelope、RSA 包装密钥与主机标识。

GitHub sender 还会把被盗 token 双重 Base64 编码,拼到以下固定 marker 后作为公开 commit message:

IfYouBlockThisAPIKeyItWillCrashTheLiveProductionServersOfAllThirdPartyClients

其他感染实例可搜索该 marker、解码 token 并检查 repo scope,让一个受害者的凭据变成整个蠕虫网络的共享资源。

基础设施与解混淆

三个早期 C2 domain 在 8 秒内完成注册;14 分 23 秒后,FixedFloat 向 operator wallet 转入 ETH;三天后同一 wallet 部署 resolver contract。资金流只能说明 funding rail,不能单独证明攻击者身份,Binance deposit address 才是更强的后续调查 pivot。

图 7:domain 注册、钱包入金、合约部署、C2 列表变化和交易所转账。

行为遥测中还出现 Bun 执行 Math_Symbol.js,随后启动 cmd.exe 调用 gh auth token 窃取 GitHub PAT。

图 8:从 VS Code 环境中的 Bun 载荷到 gh auth token 的进程链。

Unit 42 对 727 KB payload 完成了三层还原:

  • • Layer 1:73 套 function-specific alphabet 的 Base91,加 14 位 array rotation,恢复 4,613 个 string entry;
  • • Layer 2:PBKDF2-SHA256 200,000 次迭代和 seeded Fisher-Yates shuffle 组成的 byte permutation cipher,恢复 727 个 string;
  • • Layer 3:AES-256-GCM 加 gzip 的 10 个 blob,包含 Bash/Python helper、runner memory scraper、workflow、持久化文件与 RSA key。

图 9:Base91、custom permutation cipher 与 AES-GCM blob 的逐层还原。

检测与处置

定位感染不能只回滚 npm tag。lockfile、cache、mirror、tarball 和 CI image 可能仍固定在恶意版本。处置至少包括:

  • • 搜索 Math_Symbol.js、math_init.js、setup.mjs、router_runtime.js 和新增 preinstall;
  • • 检查 .vscode/tasks.json、.claude/settings.json、codeql_analysis.yml 及 OS-level latent artifacts;
  • • 检测 Bun/Node 子进程调用 gh auth token、读取 /proc/*/mem、查询 cloud metadata 和访问 Ethereum RPC;
  • • 监控对 resolver contract 的 eth_call 和 setStrings(),并阻断 domain/SNI,而不是误伤共享 CDN IP;
  • • 搜索两个固定 GitHub marker、Dune 仓库描述和异常 patch publish;
  • • 轮换所有可能暴露的 npm、GitHub、cloud、Kubernetes、Vault、SSH 与 automation credentials;
  • • 使用 disposable CI runner、workload-bound identity、egress allowlist 和 canary credential 缩小爆炸半径。

ChainDropnpm蠕虫分析:Runner内存窃密、区块链C2与自传播" 网络安全文章

ChainDropnpm蠕虫分析:Runner内存窃密、区块链C2与自传播"

ChainDrop是npm供应链蠕虫,通过preinstall注入三层混淆载荷并利用Bun执行。其深度窃取云凭据,且直接读取CIRunner内存提取OIDCtoken。蠕虫借被盗token自传播,首创利用以太坊智能合约作C2路由器动态切换域名,以强加密外传数据。建议全面排查lockfile中的恶意文件,监控读进程内存与链上RPC调用,立即轮换所有凭据,并采用一次性CIrunner与出站白名单缩小攻击面。
【古法渗透】aesrsa自加密" 网络安全文章

【古法渗透】aesrsa自加密"

本文演示了针对AES+RSA自加密的渗透测试方法。通过分析JS文件发现key和iv固定不变,利用Burpsuite的autodecoder插件替换加密数据,成功绕过加密验证。提供了可操作步骤,适用于类似加密场景的测试。
评论:0   参与:  0