简易高效的供应链攻击—依赖混淆
2022-8-26 11:13:31 Author: www.freebuf.com(查看原文) 阅读量:9 收藏

漏洞报告时间为2020年7月17日 由alexbirsan提交,赏金为3万美元。本篇文章记录的仅为提交给Paypal的漏洞报告,但另有针对多家企业的报告。

漏洞报告原始地址:RCE via npm misconfig -- installing internal libraries from the public registry

依赖混淆(Dependency Confusion)一种简易而又高效的供应链攻击方式,影响多家大型科技公司,并获取远超10万美元的漏洞赏金。

漏洞概况

为了简约并快速的让读者能够对这样一份报告有大体上的理解,所以我决定将漏洞报告分析概况提到文章前头来。这样也方便读者决定是否要继续阅读完整报告,也尽量能让一些非专业读者能够对此篇文章所介绍的内容有所了解,而不至于太过枯燥乏味。

在配置项目的包依赖时,常常会混用外部公共包和内部自定义包,我们称此为dependency confusion(依赖混淆)问题。而由于包依赖程序的内部机制,就会导致错误地引入外部的恶意包,这也就为一次成功的供应链攻击(supply chain attacks)提供了机会。攻击者通过将配置文件中与内部包名称相同的恶意包上传到公共包管理库当中,使得当项目构建加载运行时错误引用这一恶意包,从而使得RCE攻击成为可能。

以python的包管理工具pip为例,当使用包含这一参数--extra-index-urlpip install library命令来指定所要使用的包时,其内部机制为:

  • 检测library是否存在于指定(内部)包索引中

  • 检测library是否位于公共包索引(PyPI)中

  • 安装所找到的版本,如果在两个位置都找到了library,那默认就会安装更高版本的那个

因此上传“高版本”的包到公共源当中,即可实现RCE攻击,且这一攻击的成功率非常之高。

当然,不单单是python的pip,管理Node包的npm,Ruby的RubyGems等也存在同样的问题。发掘这一漏洞的关键除了这些包管理工具的内部机制外,如何发现更多的暴露出来的内部包配置脚本同样也是值得探究的地方。

研究员alexbirsan利用自动化脚本搜集并利用这一dependency confusion(依赖混淆)问题,成功“入侵”了包括苹果(Apple)、Yelp、特斯拉(Tesla)和Shopify等大型公司,且每项漏洞报告都获得了不菲的奖金($30000/每个 甚至更多),足以证明这一漏洞极高的威胁性。

漏洞挖掘详情

在我开始学习编程的时候,就一直被我们对这样一个简单命令的信任程度所吸引

pip install package_name

一些编程语言比如Python,提供了一种简单的、或多或少正式的官方工具用来管理项目的依赖项。 这些工具通常与公共包管理库绑定在一起,任何人都可以免费上传代码包供其他人使用。你可能已经听说过了很多类似的工具——例如npm用于npm注册,Python通过pip来使用PyPI,Ruby的gem使用RubyGems。

当我们在下载和使用来自这些源的软件包时,实际上就是信任了它的发布者在自己的机器上运行代码, 那么这种盲目信任会被恶意攻击者所利用吗?

当然了!!没有一个包托管服务能够保证它的用户上传的所有代码都是没有恶意软件的。过去的一个研究就展现了一种利用流行包typo版本的攻击——typposquatting,令人难以置信地可以有效地访问世界各地随机的一台计算机设备。其他众所周知的供应链攻击路径包括使用各种方法破坏现有的包,或者使用不再存在的依赖项的名称上传恶意代码。

漏洞发掘灵感

在2020年的夏天Justin Gardner分享了在Github上找到的一段有趣的Node.js代码。

这段代码被Palpay内部所使用,位于package.json文件当中,似乎混合地包含了公共依赖项和私有依赖项——公共包来自于npm源,非公共包名很可能托管于Paypal内部当中,这些名字在npm源中并不存在。

由于并没有清晰的逻辑指明哪个包应该来自于哪里,所以出现了一些问题:

  • 如果相同名字的恶意软件包被上传到了npm的公共源当中,Paypal内部的一些项目是否会使用这些公共包而不再使用内部包

  • 开发人员,或者甚至是自动化系统是否会开始运行这些包当中的代码

  • 如果这些成功实现了,我们能拿到漏洞赏金吗

  • 这种攻击对其他公司也有效吗

话不多说,我便开始着手制定一个计划来回答这些问题。我的想法是将自己的恶意Node包上传到npm公共源当中,恶意包中的代码能够让安装了的计算机设备返回一些信息。如果任何一个包最终被安装到了Paypal内部的服务器当中,或者其他任何地方,这些代码都能够立刻通知我。

在此我需要澄清一下,在这项研究中每一个被针对的组织都已经允许进行安全测试的,无论是通过公开的漏洞赏金项目,还是通过私人协议,请不要在未经授权的情况下尝试这种测试。

DNS yyds

值得庆幸的是,npm允许在包安装时自动执行任意代码,这让我可以轻松地创建一个Node包,并通过它的preinstall脚本收集其所安装的设备的一些基本信息。为了在通过数据能够识别所属组织和避免收集太多敏感信息之间取得平衡,我决定只记录用户名、主机名和当前路径再加上外部ip这些信息,这些数据足以帮助安全团队根据我的报告识别可能易受攻击的系统,同时避免我的测试被误认为是实际的攻击。

现在还有一件事——我该怎么把这些数据回传给我。我知道大多数目标可能都处于良好的公司网络内部保护当中,所以我认为利用DNS是一种有效的方法(将信息以DNS协议数据的形式携带)。

通过DNS协议将信息发送回我的服务器对于测试工作本身不是必需的,但这确实有利于确保这些流量在返回时不易被检测到或被阻塞发出。 数据使用十六进制编码,并作为DNS查询的一部分发往我所自定义的权威服务器,服务器被配置为记录每个收到的查询,这实质上就保存并下载了每台设备的记录。

拓展攻击面

有了基本的攻击计划,是时候发现更多的目标了。第一种策略是寻找相同的生态系统,所以我将这些代码移植到Python和Ruby中,以便能够将类似的包分别上传到PyPI (Python Package Index)和RubyGems当中。但是理论上来说,这个测试最重要的部分应该是寻找到尽可能多的相关依赖项名称(内部包名称)。对一些目标公司的内部包名称进行了几天的搜索后发现,在GitHub以及主要的包托管服务上都可以找到这些内容,包括甚至在各种互联网论坛的帖子中也可以找到这些暴露的内部包名。

然而,到目前为止,找到内部包名称的最佳位置是在——javascript文件中。显然,这对于内部包来说是十分常见的。package.json文件包含了javascript项目依赖项的名称,在构建的过程中嵌入了公共脚本文件以此就会导致内部包名称的泄露。 类似地,这些文件中泄露的内部路径或require()调用也可能会包含依赖项的名称。 Apple、Yelp和Tesla(特斯拉)等公司也只是这些案例当中的一部分在2020年下半年,感谢streaak的帮助以及他卓越的侦察能力,使得我们能够自动化扫描数百万的属于目标公司的域名,并提取了数百个额外的javascript包名称,这些内部包还没有出现在npm的公共源列表当中。然后我将所有这些找到的内部包名为我所编写的代码命名,并将这些代码上传到包托管源当中,并等待信息返回。

结果

成功率高的惊人!从开发人员在其机器上的一次失误,到错误配置的内部或基于云的构建服务器,再到系统上易受攻击的开发管道,有一件事是明确的:利用有效的内部包名进行攻击几乎是一种肯定会成功的方法,可以进入一些最大的科技公司网络进行远程代码执行操作,并可以让攻击者在构建期间添加后门。

这种类型的漏洞我称之为依赖混淆(dependency confusion),到目前为止,在超过35个组织中检测到,跨越所有三种测试的编程语言。 绝大多数受影响的公司员工数量都超过1000人,这反应了错误配置内部包在大型公司中具有极高的流行率。

由于javascript依赖名称更容易找到,所以几乎75%的日志回调都来自于npm包,但这并不一定意味着Python和Ruby更不容易受到攻击。 事实上,在搜索过程当中,尽管只能识别出属于8个组织的内部Ruby gem名称,但其中4个公司很容易通过RubyGems产生的依赖混淆而进行攻击。

加拿大的电子商务巨头Shopify就是这样一家公司,它的构建系统在我上传Ruby gem几个小时后就自动安装了名为shopify-cloud的Ruby gem并试图运行其中的代码。 Shopify 的团队在一天之内就准备好了修复补丁,并为找到这个问题而奖励了$30000的漏洞赏金。

另外一份$30000的漏洞赏金来自于Apple,在我上传至npm公共源的Node包中的代码被其网络内的多台机器执行之后(2020年8月)。 受影响的项目似乎与Apple的认证系统有关,外部称为Apple ID。对了,还有促使我开始这一次漏洞挖掘的Papay也同样给予了我$30000的漏洞赏金,事实上这些奖金金额都是在每个漏洞收集政策所允许的最大金额上设置的,有时候甚至更高,这表明了依赖混淆这一漏洞的严重危害性。其他一些受影响的公司包括Netflix、Yelp和Uber。

另一个导致bug的特性

尽管有大量关于dependency confusion的发现,但有一个细节在某种程度上仍然是不清楚的:为什么会发生这种情况? 这类漏洞产生背后的主要根源是什么?可以理解的是,大多数受影响的组织不愿意进一步分享关于其根本原因和缓解策略的技术细节,但在我与安全团队的交流以及自己的研究当中,确实出现了一些有趣的细节。

例如,导致Python依赖关系混乱的罪魁祸首似乎是错误地使用了一个设计不安全的命令行参数--extra-index-url。 当使用包含这一参数的pip install library命令时来指定索要使用的包索引时,表面上看它可能按照预期工作,但是pip命令在幕后实际做的事情是这样的:

  • 检测library是否存在于指定(内部)包索引中

  • 检测library是否位于公共包索引(PyPI)中

  • 安装所找到的版本,如果在两个位置都找到了library,那默认就会安装版本更高的那个

因此,在上面的例子中,如果将名为library 9000.0.0的包上传到PyPI就会导致依赖被劫持尽管这种机制已经广为人知,在Github上简单地使用--extra-index-url就足以找到一些属于大型组织的脆弱性脚本——包括一个可以影响微软.NET Core组件的漏洞,这一漏洞允许在.NET Core当中添加后门,不过其并不在.Net的漏洞收集范围当中。Ruby的gem install --source也以相似的机制进行工作,但我还无法确认它的使用是否是造成这些问题的根本原因。当然将--extra-index-url更改为--index-url是一个快速且直接的修复方式,但事实证明其他一些依赖混淆变体更难以缓解。

JFrog Artifactory是一款广泛用于托管所有类型的内部包的软件,它提供了将内部和公共库混合到同一个“虚拟”库中的可能,极大地简化了依赖管理。 然而许多用户表示,Artifactory使用完全相同的易受攻击的算法来决定使用哪个具有相同名称的内部包和外部包来提供服务。 在撰写本文时,还没有办法更改这种默认行为。据报道,JFrog已经意识到这个问题,但一直将其可能的修复作为一个“feature request” ,并没有具体的完成时间。不过它的一些用户已经在依赖管理中应用系统策略进行更改,以减轻依赖混淆的影响。

微软还提供了一个类似的包托管服务,名为Azure Artifacts。 根据我的一份报告,对该服务进行了一些小的改进,以确保它可以为依赖混淆漏洞提供可靠的解决方案。 有趣的是,这个问题不是通过测试Azure工件本身发现的,而是通过成功攻击微软自己的基于云的Office 365发现的,该报告创造了Azure可能的最高奖励$40000。有关根本原因和预防建议的更深入信息,可以查看Microsoft的白皮书《3 Ways to Mitigate Risk When Using Private Package Feeds


文章来源: https://www.freebuf.com/articles/web/342957.html
如有侵权请联系:admin#unsafe.sh