自从我开始学习如何编程,我一直对执行如下一条简单命令的信任程度所吸引。
pip install package_name
某些编程语言,如Python,附带一种简单,接近官方的方法用于为项目安装依赖项。这些安装程序通常与公开代码存储库绑定,在哪里任何人都可以自由上传代码包供他人使用。
你可能已经听说过这些工具-比如Node有npm
和npm注册表,Python的pip
使用PyPI(Python包索引),和Ruby的gem可以在RubyGems找到。
当下载和使用来自任何资源的包,你基本是信任它的发行者在你的机器上运行代码的。那么这种盲目的信任会被恶意行为者利用吗?
答案是: 当然可以
任何程序包托管服务都无法保证其用户上传的所有代码都是无害的。过去的研究表明,typosquatting(利用流行软件包名称的错字版本进行攻击)能够非常有效地获取来自全世界各地的随机PC的访问权限。
其他众所周知的依赖项链条攻击路径,包括使用各种方法去破坏现存的软件包,或以不再存在的依赖项名称上传恶意代码。
在2020年夏季,Justin Gardner(@Rhynorater)尝试与我入侵PayPal时,分享了在Github上发现有趣的Node.js源码。
该代码旨在供内部PayPal使用,在它的的package.json
文件中,出现了包含公共依赖和私有依赖混合的情况-公共的软件包来自npm,而非公共的软件包名称,很有可能由PayPal内部托管。这些名称当时在公共npm注册表并不存在。
由于此处不清楚从何处导入包的逻辑,因此产生了几个问题:
事不宜迟,我开始制定计划来回答这些问题。
这个想法是将我自己的“恶意” Node程序包以无人使用的名称上传到npm注册表中,这将从安装它们的计算机"打电话回家"。如果最终将任何软件包安装在PayPal拥有的服务器上(或其他任何地方),就此而言,其中的代码会立即通知我。
在这一点上,我觉得很重要的一点是,必须明确指出,在此研究过程中所针对的每个组织都已允许通过公共漏洞赏金计划或通过私人协议来对其安全性进行测试。 未经授权,请勿尝试这种测试。
值得庆幸的是,npm允许在安装软件包时自动执行任意代码,这使我可以轻松创建一个Node软件包,该软件包通过其preinstall
脚本收集有关所安装的每台计算机的一些基本信息。
为了在基于数据识别组织的能力与避免收集太多敏感信息之间取得平衡,我决定只记录用户名,主机名和每个唯一安装的当前路径。与外部IP一起使用的数据就足够了,可以帮助安全团队根据我的报告确定可能受到攻击的系统,同时避免将我的测试误认为是实际的攻击。
现在剩下一件事了—我该如何得到这些返回的数据?
众所周知,大多数可能的目标都将位于受到良好保护的企业网络内部,我认识到DNS窃取是解决的好方法,值得尝试。
有了攻击的基本计划,现在是时候发现更多可能的目标了。
第一个策略是寻找替代生态系统进行攻击。因此,我将代码移植到了Python和Ruby上,以便能够分别将相似的软件包上传到PyPI(Python软件包索引)和RubyGems。
但是,该测试最重要的部分可以说是找到尽可能多的相关依赖项的名称。
在搜索了一些目标公司的私有软件包名称的整整几天后,发现可以在GitHub以及主要软件包托管服务(偶然发布的内部软件包内部)内部的主要软件包托管服务中找到许多其他名称--甚至在各种互联网论坛上的帖子。
但是,到目前为止,找到私有程序包名称的最佳位置竟然是…在javascript文件中。
显然,package.json
包含javascript项目依赖项名称的内部文件在构建过程中会嵌入到公共脚本文件中,从而暴露内部程序包名称,这是很常见的。同样,这些文件中泄漏的内部路径或require()
调用也可能包含依赖项名称。苹果,Yelp和特斯拉只是以这种方式公开内部名称的公司的一些例子。
在2020年下半年,由于@streaak的帮助和他出色的侦察技能,我们能够自动扫描属于目标公司的数百万个域,并提取数百个尚未npm注册表声明的javascript程序包名称。
然后,我将代码上传到所有找到的名称下的包托管服务中,并等待回调。
成功率简直是惊人的。
从开发人员在自己的计算机上犯下的一次性错误,到内部配置不当或基于云的构建服务器,再到系统易受攻击的开发管道,结论很明显:抢占正当的内部软件包名称几乎是一种肯定的方法去进入一些最大的科技公司的网络,然后可以远程执行代码,并且可能允许攻击者在构建过程中添加后门。
迄今为止,这类型的漏洞,我已经开始称其为<依赖混淆>,且在超过35个组织的所有三种测试的编程语言中检测到该类型问题。绝大多数受影响的公司属于1000多名员工类别,这很可能反映了大型组织内部使用内部私有库的普遍性。
由于更容易找到javascript依赖项名称,几乎所有已记录的回调中有75%来自npm软件包-但这并不一定意味着Python和Ruby不太容易受到攻击。实际上,尽管在我的搜索过程中只能识别属于八个组织的内部Ruby gem名称,但事实证明,其中有四家公司很容易通过RubyGems造成依赖混淆。
加拿大电子商务巨头Shopify是这样的公司之一,其构建系统在我上载后仅几个小时就自动安装了一个名为shopify-cloud
的Ruby gem ,然后尝试在其中运行代码。Shopify团队在一天之内准备好修复程序,并为发现问题提供了30,000美元的漏洞赏金。
另外30,000美元的奖励来自于苹果,我于2020年8月上传到npm的Node包中的代码在其网络内的多台计算机上执行。受影响的项目似乎与Apple的身份验证系统(外部称为Apple ID)有关。
当我提出这个错误可能使威胁者向Apple ID注入后门的想法时,Apple并不认为这种影响水平可以准确说明问题,而是说:
在运营服务中实现后门需要更复杂的事件序列,这是一个带有附加含义的非常特定的术语。
但是,Apple确实承认使用此npm软件包技术可以在Apple服务器上执行远程代码。根据软件包安装的流程,该问题在我报告后的两周内得到了解决,但仅在发布此帖子之前不到一天就授予了赏金漏洞。
在针对其他公司的其他几次成功攻击中,可以看到在内部服务器和个人开发人员的PC上都安装了相同主题的npm软件包,其中一些安装通常是在软件包上传后数小时甚至几分钟进行的。
哦,这一切开始于PayPal的名字吗?这些也奏效了,又产生了3万美元的赏金。实际上,大多数已授予的Bug赏金都设置为每个程序的策略所允许的最大数量,有时甚至更高,这说明了依赖混淆bug的严重性通常很高。
其他受影响的公司包括Netflix,Yelp和Uber。
尽管发现了大量的依赖混淆,但一个细节在某个程度上依然是不清晰的:为什么会这样? 导致此类的漏洞真正原因是什么?
大多数受影响的组织都不愿透露有关其根本原因和缓解策略的更多技术细节,但是在我的研究过程中以及与安全团队的沟通中确实出现了一些有趣的细节。
例如,Python依赖关系混乱的罪魁祸首似乎是错误地使用了“设计不安全”命令行参数--extra-index-url
。带上此参数使用pip install library
指定您自己的包索引时,您可能会发现它可以按预期工作,但是pip
背后的实际操作是这样的:
library
指定(内部)包索引上是否存在library
存在因此,library 9000.0.0
在上面的示例中,上传名为PyPI的程序包将导致依赖关系被劫持。
尽管这种行为已经广为人知,但简单地在GitHub上搜索--extra-index-url
就足以找到一些属于大型组织的易受攻击的脚本-包括一个影响Microsoft .NET Core组件的bug。不幸的是,该漏洞可能已允许向.NET Core添加后门程序,但该漏洞在.NET Bug赏金计划中未发现。
Ruby的gem install --source
工作方式也与此类似,但是我无法确定其用法是否是我发现所有该类漏洞的根本原因。
当然,更改--extra-index-url
为--index-url
是快速而直接的解决方法,但是事实证明,依赖混淆的其他一些变体很难缓解。
JFrog Artifactory是一款广泛用于托管各种类型内部软件包的软件,它提供了将内部和公共库混合到同一“虚拟”存储库中的可能性,从而大大简化了依赖性管理。但是,多个客户表示Artifactory使用上述完全相同的易受攻击算法来决定遭遇相同名称时,是使用内部还是外部程序包。在撰写本文时,无法更改此默认行为。
据报道,JFrog意识到了这个问题,但一直对待可能的解决方案视为“功能请求”,而没有看到ETA,在此期间,其一些客户则诉诸于将系统策略更改应用于依赖项管理,以减轻依赖项中的依赖项混乱。
Microsoft还提供了类似的名为Azure Artifacts的程序包托管服务。根据我的一份报告,对该服务进行了一些小的改进,以确保它可以为依赖项混淆漏洞提供可靠的解决方法。有趣的是,没有通过测试Azure Artifacts去发现此问题,而是通过成功攻击Microsoft自己的基于云的Office 365来发现此问题,该报告得到了在Azure可能获得的最高奖励40,000美元。
有关根本原因和预防建议的更多详细信息,您可以查阅Microsoft的白皮书“使用专用软件包供稿时缓解风险的3种方法”。
尽管许多大型科技公司已经意识到这种漏洞,并已在其基础架构中对其进行了修复,或者正在努力实施缓解措施,但我仍然感到可以继续有很多发现的感觉。
具体来说,我相信找到泄漏内部程序包名称的新方法将揭示更多易受攻击的系统,而寻找其他的编程语言和目标存储库将暴露依赖混淆Bug的其他攻击面。
话虽这么说,无论您的经验水平如何,我都竭诚鼓励您花一些时间在脑海中尝试一下该想法-无论它是否与依赖项管理安全性相关。
本文为翻译文章,原文链接:https://medium.com/@alex.birsan/dependency-confusion-4a5d60fec610