研究人员最近发现了依赖存储库劫持的情况非常普遍,这是一个隐藏的漏洞,允许任何人在用户更改用户名的情况下劫持存储库。这个漏洞类似于子域接管,利用起来很容易,并且会导致远程代码注入。在分析了这个漏洞的开源项目并总结了搜索它们的依赖关系图后,研究人员发现有超过70000个开源项目受到影响,这包括来自谷歌、GitHub、Facebook等公司的流行项目和框架。为了缓解这个漏洞,请确保你的项目不依赖于GitHub的直接URL或使用依赖关系锁定文件和版本固定。
什么是Repo Jacking?
依赖存储库劫持(又名“Repo Jacking”)是供应链上一个鲜为人知的漏洞,在概念上类似于子域名接管,影响超过7万个开源项目,影响从web框架到加密货币的所有操作。这个漏洞利用起来很不容易,会导致远程代码注入,并影响来自谷歌、GitHub、Facebook、Kubernetes、NodeJS、Amazon等公司的重大项目。研究人员在最近的一次活动中首次发现这个漏洞后,就想知道这个漏洞有多普遍,于是就对所有开源项目进行了递归分析,结果发现它非常普遍。
哪些对象易受Repo Jacking攻击?
每个编译依赖于GitHub存储库动态链接代码的项目都可能受到攻击,不过攻击要成功,需要满足以下两个条件:
- 你的代码需要直接引用GitHub存储库(通常作为依赖关系)。
- 存储库的所有者需要更改/删除他们的用户名。
当链接的存储库所有者更改其用户名时,任何人都可以立即重新注册该用户名。这意味着,任何链接回原始存储库URL的项目现在都很容易受到依赖劫持的远程代码注入的攻击。恶意攻击者可以注册旧的GitHub用户名,重新创建存储库,并使用它向依赖它的任何项目提供恶意代码。
即使依赖于GitHub存储库的项目现在还不容易受到攻击,但如果其中一个依赖关系的所有者更改了他们的用户名,那么该项目和其他依赖于该旧链接的项目就会受到repo jacking的攻击。当存储库更改位置时,可能会出现某种警告,比如“404 -未找到存储库”之类的漏洞,但实际上没有。此外,Github的一项小功能(存储库重定向)使此漏洞明显更加危险。
“存储库重定向”使攻击更加严重
当GitHub用户更改存储库的名称或用户名时,GitHub设置了一个从旧URL到新URL的重定向,这种重定向同时适用于HTTP和Git请求。当用户更改其用户名、传输存储库或重命名存储库时,就会创建此重定向。这里的漏洞是,如果重新创建原始存储库(在本例中为“twitter/bootstrap”),重定向将中断,并将你发送到新创建的存储库。
示例场景
链接https://github.com/twitter/bootstrap指向资源库“twitter/bootstrap”,但实际上会将你重定向到“twbs/bootstrap”资源库。
如果Twitter更改了他们的GitHub用户名,那么任何人都可以重新注册它,重新创建一个名为“bootstrap”的资源库,任何对https://github.com/twitter/bootstrap的新请求都将进入新创建的资源库。
任何依赖于https://github.com/twitter/bootstrap的项目现在都将开始从这个新存储库加载代码。
重定向是一个方便的功能,因为它意味着当你重命名你的帐户时链接不会立即中断。但这也意味着你的项目可能在不知不觉中变得容易受到Repo Jacking的攻击。从你的角度来看,什么都没有改变,你的代码编译仍然是一样的,一切都按照它应该的方式工作。但是,你的项目现在很容易受到远程代码注入的攻击,而且你并不知道。
三种劫持场景
更具体地说,从技术上讲,有三种不同的方式可以使存储库变得可以被劫持:
- GitHub用户重命名其帐户。这是存储库可劫持的最常见方式,因为用户重命名其帐户并不罕见,并且在用户重命名帐户后,由于存储库重定向,一切都会按预期进行。
- Github用户将其存储库转移到另一个用户或组织,然后删除其帐户。用户转移存储库时,将建立重定向,并通过删除其用户来打开它,使其被任何人劫持。
- 用户删除其帐户。这是三者中影响最小的,因为从原始用户删除帐户的那一刻起,任何引用该帐户的项目在尝试获取存储库时都会开始出现漏洞。
注意:在用户删除帐户和项目尝试获取存储库之间,有几次攻击者重新注册已删除的用户名,详情请点此。
GitHub的回应
在发布本文之前,研究人员已与GitHub联系,他们表示虽然这是一个已知漏洞,但是他们目前尚无任何计划来更改重定向或用户名重用的方式。他们只是通过禁止重新注册导致删除一周之内具有100个以上新复制的存储库名称来为某些受欢迎的存储库提供了一些缓解此问题的方法,如下所述。这确实提供了一定程度的保护,但不是万无一失的解决方案,因为许多较小的存储库不符合此标准,但仍然可以为流行项目所依赖。
这里的根本漏洞不是GitHub允许重定向和用户名重用,而是开发人员从不安全的位置提取代码。GitHub无法监督那些出于意外目的使用其服务的开发人员。有许多可用的包管理器(事实上,GitHub本身就有一个)用于解决远程代码依赖漏洞,开发人员有责任确保他们从安全位置加载代码。
漏洞影响范围
漏洞影响范围有多大,事实证明,筛选所有开放源码项目,编译它们的依赖关系,找到所有可被劫持的存储库,并构建易受攻击的存储库的依赖关系图并不容易。
步骤1:数据收集
对开源软件进行大规模分析时,最困难的部分之一是初始数据收集。为所有开源项目找到一个最新的、准确的、容易搜索的索引是很困难的。研究人员主要使用两个数据集进行分析:
(1) GitHub活动数据
这是由Github自己提供的,是一个巨大的数据集,包括超过280万个存储库,以及它们的所有文件和内容,整个数据集的内容超过3TB。方便的是,它被托管为谷歌云平台(GCP)上的一个公共BigQuery数据集,这意味着研究人员可以使用BigQuery从GCP本身内部在整个数据集上运行SQL命令,而不需要下载整个3TB文件。
为了实际执行搜索,研究人员生成了一个正则表达式,用于捕获任何Github URL或其他常见的Github依赖链接格式,如Github:username/reponame。使用这个正则表达式,研究人员能够为包含对GitHub链接的引用的每个文件提取存储库、文件名和文件内容。这将研究人员的搜索空间从3TB缩小到更易于管理的4GB。经过过滤的数据集包括400万个独特的GitHub链接和超过70万个不同的GitHub用户。
(2) libraries.io
libraries.io是一个开源项目,旨在将来自多个不同打包程序管理器的所有依赖聚合成一个类似图表的数据集。这是令人惊奇的,因为它不仅为研究人员完成了连接什么依赖什么的所有繁重工作,而且它还提供了整个数据集可供免费下载。未压缩时,该数据集超过100GB,但可以直接加载到数据库中,以便于处理。
研究人员使用这两个数据集是很重要的,因为每个数据集擅长不同的事情。“Github活动数据”数据集允许研究人员找到存储库中引用的每一个可能的Github链接,即使它没有被用在明显的地方,比如包管理器清单中。一些最有趣的发现并不一定是直接的代码依赖,研究人员经常发现,在bash脚本中直接使用Github url来复制存储库或docker映像,这些映像将在构建时从Github提取存储库。
示例安装脚本;任何人都可以注册GitHub的链接
另一个常见的发现是可劫持的存储库作为Git子模块,这是标准依赖分析可能会忽略的。
另一方面,“libraries.io”数据集是一个已经清理、过滤和格式化的数据集,它使我们能够构建依赖图并轻松评估此漏洞的广泛性。通过这些数据集,我们可以更全面地了解此漏洞对开源项目的总体影响。
步骤2:清理
收集了所有这些数据后,研究人员需要对其进行清理和规范化,这是一项任务量很大的工作,因为研究人员需要考虑每个程序包管理器的不同格式。此外,研究人员希望删除所有实际上没有作为依赖关系使用的链接。这些链接中有很多是在注释中使用的,例如//code inspired from github.com/username/reponame,或者在文档文本文件中。由于研究人员主要关心代码注入的可能性,所以研究人员删除了代码不会直接使用的任何内容。这就给研究人员留下了超过200万个独特的GitHub链接,这些链接被文件以有意义的方式引用。
步骤3:可劫持的用户名
现在研究人员有了一个直接依赖于GitHub链接的清晰项目列表,研究人员需要找到当前未注册的用户。到目前为止,研究人员有大约650k个Github用户名需要整理。使用GitHub API,研究人员可以检查用户名是否存在,但研究人员的速度限制在每小时5000个请求,这意味着检查所有用户名要花费5天以上的时间。通过一些巧妙的逻辑和GitHub GraphQL API,研究人员能够将扫描所有650k用户的时间缩短到2小时多一点。
那么,结果如何呢?研究人员发现,研究人员收集的用户名中有7%(约50k)是未注册的。老实说,研究人员没想到这个数字会这么高。研究人员认为只有不到1%的用户名是可以被劫持的。显然,人们对自己的用户名感到厌倦的程度远远超过预期。
步骤4:易受攻击的项目
一旦研究人员有了所有可能被劫持的用户名,漏洞就只是对研究人员的数据集进行反向搜索,每个项目都依赖于一个用户名所拥有的存储库。经过进一步的过滤和清理误报后,研究人员发现总共有18000个项目直接容易受到库劫持的攻击。这些项目在GitHub上总共有超过50万颗星星,并且包括了来自一些最大的开源组织的几乎每种语言的项目。
仅这个数字就令人恐惧,但是现代代码库并不是运行在单个存储库中的庞大整体。相反,它们在功能上依赖于许多其他项目。这对于可维护性和可重用性来说是很好的,但这意味着单个流行依赖关系中的漏洞会极大地影响依赖关系链上的许多项目。实际上,任何依赖于18000个直接易受攻击项目的项目本身也是易受攻击的。
步骤5:依赖性分析
现在研究人员就有了一个直接易受攻击的项目列表,将其与以前的数据集一起用于执行依赖关系图污点搜索,并找到每个依赖其供应链中易受攻击的仓库的项目。在此分析中,研究人员包括了普通的依赖关系和不太明显的依赖关系,比如开发依赖关系或不在主包清单文件中的依赖关系。如果这些辅助依赖关系中的一个容易受到repo sniping的影响,则影响可能需要更长的时间才能在依赖关系链上传播,因为这种影响可能仅在开发人员发布新版本时才会发生。考虑到这一点,研究人员开始了攻击分析。
由于易受攻击项目的数量可能会呈指数级增长,研究人员会慢慢进行遍历。在每次传递过程中,研究人员都手动检查结果,并删除任何明显的误报,以最小化漏洞传播,并确保研究人员的结果不会被误报所掩盖。
经过5次遍历后,研究人员不得不停下来。因为在第5轮之前,数据的增长都是可以预测的,且每一轮搜索都花费了合理的时间,但当研究人员进行第6轮遍历时,数据开始不可控制地增长。看看第五轮的结果,原因就清楚了,研究人员已经建立了多个大型的基础框架,并被成千上万的其他项目所依赖。这足以让研究人员理解这一漏洞的影响。截至目前,研究人员已经发现了超过7万个受影响的项目,其中GitHub明星项目总数超过150万个,这比GitHub前8大资料库加起来还要多。虽然这很难精确衡量,但研究人员估计这些项目的总下载量至少有200万。
受影响的项目包括来自大型组织(例如Google,GitHub,Facebook,Kubernetes,NodeJS,Amazon等)的存储库。从小型个人用户项目到成千上万个组织使用的流行Web框架,一切都受到影响。有趣的是,它会影响很多不同类型的软件。研究人员发现了易受攻击的路由器固件、游戏、加密钱包、移动应用程序和许多其他独特的项目。
缓解措施
- 不要直接链接到GitHub存储库。
- 版本固定和锁定文件。
本文翻译自:https://blog.securityinnovation.com/repo-jacking-exploiting-the-dependency-supply-chain