原文:
https://medium.com/@alex.birsan/dependency-confusion-4a5d60fec610\
自从我开始学习如何编码以来,我一直对我们放在这样一个简单命令中的信任程度着迷:
pip install package_name
某些编程语言(例如Python)带有一种简单的或多或少官方的方法来为项目安装依赖项。
这些安装程序通常与公共代码存储库绑定,在那里任何人都可以自由上载代码包供他人使用。
您可能已经听说过这些工具Node具有npm和npm注册表,Python的pip使用PyPI(Python包索引),Ruby的gems可以在RubyGems上找到。
从这些来源中的任何一个下载和使用软件包时,您实际上是在相信其发布者在您的计算机上运行代码。 那么这种盲目的信任会被恶意行为者利用吗?

当然可以。
任何程序包托管服务都无法保证其用户上传的所有代码均不含恶意代码。 过去的研究表明,域名抢注(利用流行包名称的错字版本进行的攻击)在访问全球随机PC方面非常有效。
其他众所周知的依赖项链攻击路径包括使用各种方法来破坏现有软件包,或者在不存在的依赖项目上传恶意代码。

想法
在2020年夏季我和贾斯汀·加德纳(@Rhynorater)尝试入侵PayPal时,贾斯汀·加德纳分享了在GitHub上找到的有趣的Node.js源代码。
该代码旨在供内部PayPal使用,并且在其package.json文件中似乎即包含公共(来自npm的公共程序包)和也包含私有依赖项(很可能由PayPal内部托管)。 私有依赖当时在公共npm注册表中不存在。

由于逻辑不清楚从何处加载软件依赖,所以引起了一些问题:
⚪如果以这些名称将恶意代码上传到npm会发生什么? PayPal的一些内部项目是否有可能开始默认为新的公共软件包而不是私有软件包?
⚪开发人员甚至自动化系统会开始在库中运行代码吗?
⚪如果这行得通,我们可以从中获得赏金吗?
⚪这种攻击还会对其他公司起作用吗?
事不宜迟,我开始制定计划来回答这些问题。
我的想法是将我自己的“恶意” Node程序包以所有不存在的依赖上传到npm注册表中,这将从安装它们的每台计算机上“打电话回家”。 如果最终将任何软件包安装在PayPal拥有的服务器上(或其他任何原因),则其中的代码会立即通知我。
在这一点上,我觉得很重要的一点是,必须明确指出,在此研究过程中所针对的每个组织都已允许通过公共漏洞赏金计划或通过私人协议来对其安全性进行测试。未经授权,请勿尝试这种测试。
Always DNS
幸运的是,npm允许在安装软件包时自动执行任意代码,这使我可以轻松创建一个Node软件包,该软件包通过其预安装脚本收集有关所安装的每台计算机的一些基本信息。
为了在基于数据识别组织的能力与避免收集太多敏感信息之间取得平衡,我决定只记录用户名,主机名和每个唯一安装的当前路径。 与外部IP一起使用的数据就足够了,可以帮助安全团队根据我的报告确定可能受到攻击的系统,同时避免将我的测试误认为是实际的攻击。现在剩下的一件事-如何将这些数据传给我?知道大多数可能的目标都将位于受良好保护的公司网络内部,我认为DNS渗出是解决之道。

通过DNS协议将信息发送到我的服务器对于测试本身能否正常工作是非常必要的,因为它确保了在出站时不太可能被阻止或检测到流量。
数据经过十六进制编码,并用作DNS查询的一部分,该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美元的漏洞赏金。
在我于2020年8月上传到npm的Node包中的代码在其网络内的多台计算机上执行之后,苹果又获得了30,000美元的奖励。 受影响的项目似乎与Apple的身份验证系统(外部称为Apple ID)有关。
当我提出这个错误可能使威胁者向Apple ID注入后门的想法时,Apple并不认为这种影响水平可以准确地表示问题所在,而是说:在运行服务中实现后门需要更复杂的事件序列,是非常特殊的项目并需要其他条件。
但是,Apple确实确认使用此npm软件包技术可以在Apple服务器上执行远程代码。 根据软件包安装的流程,该问题在我报告后的两周内得到了解决,但仅在发布此帖子之前不到一天就授予了赏金漏洞。

在针对其他公司的其他几次成功攻击中,可以看到在内部服务器和个人开发人员的PC上都安装了相同主题的npm软件包,其中一些安装通常是在软件包上载后数小时甚至数分钟进行的。
哦,这一切开始于PayPal的名字吗? 这些也奏效了,又产生了3万美元的赏金。 实际上,大多数已授予的Bug赏金都设置为每个程序的策略所允许的最大数量,有时甚至更高,这证实了依赖混淆bug的严重性通常很高。
其他受影响的公司包括Netflix,Yelp和Uber。
这不是一个Bug,这是一个Feature
尽管有大量的依赖混淆的发现,但一个细节在某种程度上仍然是(现在仍然是)尚不清楚:为什么会这样? 此类漏洞的主要根源是什么?
可以理解,大多数受影响的组织都不愿透露有关其根本原因和缓解策略的更多技术细节,但是在我的研究过程中以及与安全团队的沟通中确实出现了一些有趣的细节。
例如,Python依赖关系混乱的主要原因似乎是错误地使用了“设计不安全”命令行参数--extra-index-url。
当将此参数与pip install库一起使用以指定您自己的软件包索引时,您可能会发现它可以按预期工作,但是pip在幕后实际执行的操作是这样的:
⚪检查指定(内部)包索引上是否存在库
⚪检查库是否在公共包索引(PyPI)上存在
⚪安装找到的任何版本。 如果两个软件包均存在,则默认从具有更高版本号的源进行安装。
因此,在上面的示例中,将名为库9000.0.0的包上载到PyPI将导致劫持依赖项。
尽管这种行为已经众所周知,但是只需在GitHub上搜索--extra-index-url就足以找到一些属于大型组织的易受攻击的脚本-包括一个影响Microsoft .NET Core组件的错误。 不幸的是,该漏洞可能已允许向.NET
Core添加后门程序,但该漏洞在.NET Bug赏金计划中未发现。
Ruby的gem install--source也可以以类似的方式工作,但是我无法确认其使用是否是我发现的根本原因。
当然,将--extra-index-url更改为--index-url是一种快速而直接的解决方法,但是事实证明,依赖混淆的其他一些变体很难缓解。
JFrog Artifactory是一款广泛用于托管各种类型内部软件包的软件,它提供了将内部和公共库混合到同一“虚拟”存储库中的可能性,从而大大简化了依赖性管理。 但是,许多客户表示Artifactory使用上述完全相同的易受攻击算法来决定在使用相同名称的内部软件包还是外部软件包。 在撰写本文时,无法更改此默认行为。

据报道,JFrog意识到了这个问题,但一直在将其可能的解决方案视为“功能请求”,而没有看到ETA,而其一些客户则诉诸于将系统策略更改应用于依赖项管理,以减轻依赖项中的依赖项混乱。与此同时。Microsoft还提供了类似的名为Azure Artifacts的程序包托管服务。 根据我的一份报告,对该服务进行了一些小的改进,以确保它可以为依赖项混淆漏洞提供可靠的解决方法。 有趣的是,不是通过测试Azure Artifacts本身发现了此问题,而是通过成功攻击了微软自己的基于云的Office 365来发现此问题,该报告得出了Azure可能获得的最高4万美元的奖励。有关根本原因和预防建议的更多详细信息,请查阅Microsoft的白皮书“使用专用软件包供稿缓解风险的三种方法”。
未来研究
尽管许多大型科技公司已经意识到这种漏洞,并已在其基础架构中对其进行了修复,或者正在努力实施缓解措施,但我仍然感到还有未发现的点。
具体来说,我相信找到泄漏内部程序包名称的新方法将揭示更多易受攻击的系统,而寻找替代的编程语言和目标存储库将揭示依赖混淆错误的其他攻击面。
话虽这么说,无论您的经验水平如何,我都竭诚鼓励您花一些时间在脑海中尝试一下该想法-无论它是否与依赖项管理安全性相关。
感谢:
⚪@EdOverflow和@prebenve,他们在我之前曾独立研究过类似类型的攻击,但不幸的是尚未发布他们的发现
⚪Justin Gardner(@Rhynorater),分享了激发最初想法的代码,并校对了这篇文章
⚪@streaak,用于帮助找到许多易受攻击的目标,并非常乐于与之合作
⚪Ettic,出色的工具dnsbin的创建者,我曾用它记录DNS回调
⚪Ohm M.,Plate H.,Sykosch A.,Meier
M.(2020)“ Backstabber的刀收藏:开源软件供应链攻击的回顾”。 DIMVA2020。计算机科学讲座,第12223卷。Cham Springer(供应链攻击树插图的来源)
⚪所有运行公共Bug赏金计划的公司,使我们有可能花费时间来追寻像这样的想法。
谢谢!
译者按:
传统的安全漏洞挖掘变得日益艰难,厂商的防御机制也在日益成熟,如何才能高效的挖掘漏洞呢?本文作者通过研究库文件依赖机制,上传恶意库文件,让开发者或程序自己去加载,并利用DNS协议绕过防火墙检测,成功渗透各大公司并获取回连数据,并获得高额奖励。那么在我们浏览目标网站的时候,目标网站有没有引用一些不存在的文件,我们是否可以去冒名顶替呢?
本文迁移自知识星球“火线Zone”