沙伊-胡鲁德与外部依赖的风险
沙伊-胡鲁德是由TeamPCP创建的恶意软件,针对NPM以扩展到节点供应链。它的名字指的是巨人沙虫居住在科幻系列中沙漠星球阿拉基斯的居民沙丘作者弗兰克·赫伯特.如果你看过电影,它们是被沙子振动吸引的生物。
参考文献中对此有清晰说明:
沙漠中出现了一条沙虫。它耗尽一切。
Shai-Hulud 通过多次行动造成的损害估计包括 500 个软件包被攻破,数百个组织被攻破,300 GB 数据被盗,以及约 50 万个凭证被窃取给攻击者。
TeamPCP 决定于 5 月 11 日发布其源代码。我不是安全研究人员,但我一直对犯罪分子如何利用复杂系统并绕过其安全系统很感兴趣。于是我分支了仓库,看看使用了哪些入侵技术或漏洞。
我还做了一些笔记,准备以后写成代码审查文章。但我越读代码,越觉得有些失望。
我没找到任何高级漏洞利用系统,而是一堆简单的技巧,用来窃取凭据、混淆字符串,以及向 npm 包注入恶意代码。有时代码不一致,存在一些漏洞,且显得不完整。
那么,这样的代码库是如何变得如此有害的呢?因为它利用了现代发展中的阿喀琉斯之踵。我们对别人的代码的信任,以及我们对依赖的热爱。
工作原理
我分析的代码库是Mini Shai-Hulud。蠕虫共有三个版本,且功能数量似乎在不同版本之间递增。
该项目使用很好用于构建过程,README 包含使用说明。
把这些数据放进CI管道。沙虫会在你的基础设施中爬行,获取所有能接触到的供应商的凭证,然后通过加密渠道泄露。如果它找到了 npm 令牌或 OIDC 访问,就会对包进行后门并发布。下游消费者负责感染。蠕虫在生长。
前检验与感染
一旦蠕虫开始运行,首先会进行一些检查,如果它没有在CI环境中运行,它就会变成守护进程,并破坏OpenSearch如果被感染的系统能够访问该仓库,则使用OIDC攻击。
蠕虫使用两种不同的方法来毒害包裹。OIDC攻击涉及注入一个新的可选依赖,@opensearch/setup,钉在另一个包中的特定提交,opensearch-project/opensearch-js,推测已经被攻破。
另一种方法是添加一个preinstall包含恶意安装文件的脚本,该文件会下载Bun并运行蠕虫。
凭证采集
由于代码能够访问主机系统,它只需读取配置文件并从进程和应用中获取令牌。
简而言之,它窃取了开发者几乎能访问的所有内容:AWS 凭证和密钥、SSH 密钥、云配置文件、加密货币钱包、网页聊天数据、VPN 配置、Kubernetes 凭证、HashiCorp Vault 密钥、GitHub 令牌、Actions 密钥、Claude 设置,.npmrc,.netrc、Bash、Zsh 和 Python shell 历史,以及 MySQL、PostgreSQL 和 Redis 凭证。
数据外流
恶意软件收集凭证后,需要将其发送给攻击者。数据首先通过嵌入载荷中的公钥进行压缩和加密。
恶意软件随后尝试联系错字域名git-tanstack.com.如果失败,它会通过签名提交消息搜索 GitHub 中其他被攻破的仓库,并从其中一个仓库获取一个备用域名。
如果连这个都失败了,它就会创建多个GitHub仓库,名称由随机的形容词和名词组成,这些名称来自以下沙丘.被盗数据随后通过GitHub Actions工作流程上传到这些仓库。
在GitHub上快速搜索显示,有成千上万个存储库包含加密的JSON数据。这些仓库中有相当一部分是在《Mini Shai-Hulud》源代码发布后几天内创建的,让我怀疑是否有人在新的战役中使用过它。
嵌入式有效载荷
负载包含几个脚本,在执行恶意软件前先下载并安装Bun。其中两个文件是VS Code和Claude的配置文件,设计为注入到仓库中,每当用户在编辑器或编码代理中打开项目时,蠕虫就会入侵机器并自我复制。
还有一个GitHub Actions工作流程,用于收集仓库秘密并将其作为工件上传。然后有两个公钥:一个用于加密数据,另一个用于验证提交签名。
最后,还有一个 Python 脚本可以导出 GitHub Actions 运行器的内存。
有效载荷还包含DEADMAN_SWITCHBash 脚本会安装一个守护进程,在接下来的 24 小时内每分钟检查 GitHub 令牌是否被撤销,如果被撤销,则会清除主目录。
混淆
代码在构建时被分成两层混淆处理。第一种方法使得构建代码中的重要字符串不可读取,并且仅在运行时解码。这防止基于签名的恶意软件检测器被以下字符串触发rm -rf ~,因为它被转化为LG+0RPNiAq6wTcBsei6MwLKLjyZ79e67.第二层则用以下方式混淆整个代码库javascript-obfuscator图书馆。
不完美代码
我在代码库中发现了一些问题。一些预期文件缺失,这可能会阻止恶意软件部分的执行。如果 Bun 已经安装,引导器会退出,但不会执行蠕虫。BASH_LOADER以及PYTHON_LOADER看起来未被使用。备援域验证机制使用不匹配的标记:它搜索thebeautifulmarchoftime但解析thebeautifulsnadsoftime,因此验证为verify_key.pub很可能永远不会成功。
我还发现了一些未使用的TypeScript接口和一些catch以及finally空着的方块。
盗取证件和DEADMAN_SWITCH脚本面向macOS和Linux系统。针对Windows的代码出现在代码库中,但未被使用。不少Node开发者使用macOS,而CI系统通常运行Linux,如果这些是主要目标,可能没必要支持Windows。
README声称恶意软件是vibe编码的,但这让我怀疑代理是否能快速修复这些问题。源代码中包含了跨多个提示词产生的工作迹象:不一致的抽象、未完成的分支、未使用的接口,以及看似从少数来源或先例版本拼凑而成的代码。
作者似乎对安全和构建流水线相当了解,但项目目前仍处于原型阶段。
这个代码库的重要教训是,利用供应链不需要特别复杂或复杂。
这是怎么发生的?
多年来我们一直忽视的,就是每次我们跑步npm install,我们允许他人编写的代码访问我们的机器和网络。听起来像噩梦,但事实就是这样。
每次你运行 linter,无论是直接运行还是通过编辑器,被攻破的代码都可能窃取你的凭证,访问你的服务器和加密货币钱包,将数据发送到远程服务器,并将你的仓库新版本推送到带有毒害依赖的 GitHub,像蠕虫一样蔓延。
依赖关系不安全,编辑器扩展也不例外[^1]。
Node,作为大多数JavaScript项目背后的运行时,其设计中存在安全漏洞,正如其创始人Ryan Dahl所说,他自己也承认了.我们习惯于通过依赖大量依赖和信任网络来更快地编写网页应用,期望维护者和开源社区能做好工作。
非常大型的公司就是利用这些技术建立起来的。
什......