引言
在软件开发的世界里,我们经常理所当然地认为我们日常依赖的工具和平台是安全和可靠的。我们假设我们下载的包和我们使用的注册表是安全和值得信赖的。然而,在Lupin & Holmes,我们最近发现了一个缓存投毒攻击在npm注册表上,这是JavaScript最大的包注册表之一,可能暴露了我们的软件供应链的脆弱性以及潜在的广泛破坏。
npm注册表是JavaScript生态系统的关键组成部分,作为超过210万个包的中央仓库,全世界有超过1700万开发者依赖它。它已经成为一个不可或缺的资源,使他们能够轻松地在项目中共享、重用和管理依赖。每天有数百万次下载,npm注册表是无数应用程序和网站的支柱。
在本文中,我们将讨论npm上缓存投毒攻击的细节,并探讨其对更广泛软件生态系统的潜在影响。通过公开披露这一漏洞,我们旨在展示软件供应链中的安全性和可用性的重要性。
缓存投毒攻击:利用漏洞
这个故事实际上非常有趣。当我们为Depi开发一个研究子模块,旨在测试Artifactories上的缓存投毒时,我们惊讶地发现世界上最著名的注册表是脆弱的:npmjs.com。
作为Depi开发的一部分,我们经常在研究模式下测试几个子模块。从本质上讲,我们探索可能破坏我们客户软件供应链的理论攻击向量,并开发一个模块以更大规模地测试和验证。一旦结果经过分类,我们就专注于所有通用和奇怪的结果,直到我们有一个值得在Depi中实现的攻击向量。任何可能影响我们客户的完整性、保密性以及可用性的事情都值得测试。
我们的理论很简单:如果我们客户使用的Artifactories可能容易受到缓存投毒拒绝服务(CPDoS)条件的影响会怎样?
CPDoS是一种网络攻击技术,由PortSwigger的这项研究描述。它涉及利用网络缓存系统中的漏洞向用户传递恶意内容。攻击通过操纵网络缓存存储和服务内容的方式工作,有效地用有害数据污染缓存。当用户请求受影响的资源时,提供的是被污染的内容,而不是合法内容,可能导致服务拒绝或其他恶意结果。这种技术利用了缓存机制及其与各种网络协议和头的交互中的微妙缺陷。
考虑到这一点,我们认为如果攻击者能够污染一个页面,将.tar.gz
文件的内容重定向到恶意的文件或者完全拒绝该包,这将是很有趣的。我们开发了一个执行此操作的模块,实现在Depi中,我们在第一次运行时就匹配到了:
registry.npmjs.org是脆弱的。
显然,我们认为这是一个误报,漏洞实际上并没有在第一次运行时触发,然而我们后来设法确认我们确实在npmjs注册表上得到了完整的CPDoS!
攻击依赖于一系列不同的头,发现这些头会触发后端系统的错误。通过发送一个包含这些头的特殊构造请求,攻击者可以操纵注册表的缓存系统为一个目标包存储一个“未找到”响应。
“
注意:我们没有提供会触发这个问题的确切的头的序列,因为在写这篇文章时它仍然可以被利用
以下是一个恶意请求的例子,我们设置了一个缓存破坏参数以避免对真实用户进行DoSing:
GET /safe-regex/-/safe-regex-1.1.0.tgz?lupin_E7A812DE-E09A-4906-A9E3-530E54AAEB41=cpdos_test HTTP/1.1
Host: registry.npmjs.org
User-Agent: lupin_test_cpdos
lupin: E7A812DE-E09A-4906-A9E3-530E54
通过随后的请求,不包含头部和相同的缓存键,攻击者随后可以检索缓存的“未找到”响应,有效地使包对其他用户不可访问。
GET /safe-regex/-/safe-regex-1.1.0.tgz?lupin_E7A812DE-E09A-4906-A9E3-530E54AAEB41=cpdos_test HTTP/1.1
Host: registry.npmjs.org
User-Agent: lupin_test_cpdos
第二个请求将导致以下响应:
HTTP/1.1 404 Not Found
Date: Tue, 21 May 2024 08:40:06 GMT
Content-Type: application/json
Content-Length: 21
Connection: keep-alive
CF-Ray: 8873427f1e301222-MRS
Access-Control-Allow-Origin: *
Vary: Accept-Encoding
Server: cloudflare
{
"error": "Not found"
}
我们发现缓存的响应是暂时的(几分钟),需要攻击者不时地持续发送请求来维持CPDoS。我们还观察到注册表使用了多个后端服务器,需要重复攻击以在不同的服务器上投毒缓存。
虽然这次攻击是直接从Burp Suite测试的,我们已经创建了一个虚拟包来测试我们是否能够从npm install命令中投毒。我们对npm cli进行了代理,以查看发生了什么,然后从当前系统中清除了缓存。在循环运行攻击几秒钟后,我们设法确认我们能够在包上传后在生产环境中对包进行CPDoS:
红色:在运行攻击之前
绿色:在运行攻击时
这次缓存投毒攻击的影响是巨大的。攻击者可以针对流行的包,例如每周下载量超过3000万的”express”,有效地使它们对开发者不可用。这可能导致软件开发流程中广泛的中断,导致构建失败和应用程序中断。
我们还使用不同的IP和客户端对攻击进行了彻底的测试,确认投毒不仅影响了攻击者,也影响了其他尝试访问目标包的用户。这突出了如果漏洞被恶意利用,可能会产生广泛影响。
通过成功利用这个漏洞,攻击者可能会导致npm注册表的服务拒绝,使其对用户不可用,破坏全世界无数组织的软件开发流程。如果针对广泛使用的包,攻击可能会特别具有破坏性,因为它可能会在软件供应链中引起连锁反应。
然而,我们还发现,被投毒的后端服务器存在不一致性,如果缓存已经被注册,攻击者无法使用PURGE命令重新投毒。我们还发现,在研究这种行为时,攻击者可能在流行的包的新版本注册之前开始投毒,以便在版本存在或包的缓存更新时投毒安装。
连锁反应:对软件供应链的影响
对npm注册表的缓存投毒攻击有着深远的影响,这些影响超出了单个包的即时可用性。当像npm注册表这样的关键组件被破坏时,它可能对整个软件供应链产生多米诺骨牌效应。
考虑这样一个场景,一个广泛使用的包,如express被攻击者针对。它在其最新版本上每周有超过1200万次下载,这个包是无数Web应用程序的基本构建块。
如果由于缓存投毒攻击而使包变得不可用,它可能会对所有依赖它的项目和服务产生连锁反应。
连锁反应可以在多个组织中感受到。
Github对这种漏洞的响应
作为npm的所有者,Github在收到有关这个漏洞的Bug Bounty报告后进行了调查。在评估了发现后,Github确定这个问题没有构成重大的安全风险,并将报告作为信息性的关闭,而没有解决这个问题。
Github承认了缓存投毒攻击的复杂性和有限的可靠性。他们还指出,攻击依赖于使用一个有问题的头,这已经是他们团队已知的。此外,Github强调,执行攻击需要DDoS或体积攻击(我们将讨论),这属于滥用范畴,不在他们的Bug Bounty计划范围内。尽管根据他们的声明,报告不符合全额奖励的条件,但Github认可了我们的努力,并提供了500美元的小额奖励作为感谢的象征。
现在我们对他们的以下声明感到困扰:
“
为了进一步执行你在最新跟进评论中描述的攻击,需要DDoS或体积攻击,这是滥用问题。我们严肃对待滥用和垃圾邮件,并有一个专门的团队追踪垃圾用户。还请注意,关于体积DoS攻击的提交不在我们悬赏计划的范围内。
但是正如我们在报告和本文中所示,我们仅用一台机器就成功破坏了一个生产包。攻击的可靠性有两个问题:
-
我们无法预测哪个后端会受到影响 -
我们必须每几分钟发送一次请求以维持投毒
根据我们的测试,四分之一的请求被投毒,这已经是一个大问题。我们只是提到如果攻击者发送更多的请求,攻击可以更可靠。但是为此所需的资源不会接近DDoS。
在撰写本文时,这个漏洞仍然可以在npmjs注册表上被利用。然而,我们将文章的第一稿发给了Github的安全团队,以获得对技术部分的总体反馈。在收到草稿后,Github团队向我们发送了以下评论:
“
再次感谢您与我们分享您打算发表的博客文章的草稿,并提交此报告,为我们提供了加强DoS保护的机会。正如我们在这个问题的历史中讨论的那样,再现性一直很难,并且需要DDoS或体积攻击才能成功利用。为了继续提高npm和我们产品的安全性,我们计划在下周一发布一个修复程序,以解决这个问题,尽管它很复杂。再次感谢您对我们Bug Bounty计划的贡献,并期待未来的合作。
有必要声明,我们对Github安全团队没有任何不满。我们实际上见过他们,他们是很棒的人,非常有趣。话虽如此,我们仍然不同意对这种情况的总体评估。我们坚信,处于软件供应链中心的公司需要更认真地对待这些类型的CPDoS。声称所描述的攻击是体积性的,并属于滥用类别,在我们谦虚的意见中,这有点牵强。
我们相信,在未来,对软件供应链上的这种可用性攻击将更加受到重视。越来越多的研究人员和漏洞猎人正在揭示CPDoS问题及其对我们生态系统的影响。
我们强烈希望安全社区所做的所有这些工作能成为软件供应链生态系统的真正警钟。
结论
Lupin & Holmes的安全研究团队发现的npm注册表缓存投毒攻击,让我们深思软件供应链的脆弱性问题。
这类漏洞可能带来的影响不容小觑。一个被破坏的注册表可能会产生严重后果,影响开发者、组织和最终用户。一个包变得不可用的连锁反应可能会干扰开发流程、导致应用程序停机,并造成经济损失。
然而,这个漏洞也展现了成长和改进的机会。它突显了像GitHub和npm这样的组织需要持续评估和加强他们的安全实践的必要性。
此外,缓存投毒攻击强调了软件供应链内协作和共同责任的重要性。开发者、注册表提供者和更广泛的社区必须共同努力,确保我们所依赖的包的安全性、完整性和可用性。
时间线
-
2023年3月3日,UTC时间22:14 Lupin报告了漏洞 -
2023年3月6日,UTC时间17:11 Github确认了报告 -
2023年3月9日,UTC时间19:48 Github关闭了这个问题,认为是内部重复 -
2023年5月4日,UTC时间21:42 Github重新开启了报告 -
2023年6月6日,UTC时间18:49 Github对报告进行了分类 -
2023年8月30日,UTC时间22:24 Github以信息性关闭了报告并支付了500美元 -
2024年5月15日,UTC时间09:44 Lupin开始了协调披露流程 -
2024年5月16日,UTC时间21:22 Github同意披露这个问题 -
2024年5月24日,UTC时间14:21 发送了第一稿给Github -
2024年6月1日,UTC时间02:15 Github确认将修复这个问题
原文始发于微信公众号(3072):单一漏洞如何摧毁JavaScript生态系统