查看原文
其他

Repo Jacking:依赖关系仓库劫持漏洞,影响谷歌GitHub等7万多个开源项目的供应链

Indiana Moreau 代码卫士 2022-04-06
 聚焦源代码安全,网罗国内外最新资讯!
编译:奇安信代码卫士团队



三个场景可导致 GitHub 仓库遭劫持。直接组合使用这三个场景可导致恶意代码注入。千万别这么做。

背景


最近的一个客户项目使我们开始调查依赖关系仓库遭劫持的普遍程度。这是一个老旧漏洞,如果仓库的所有人修改了用户名,则可导致任何人劫持该仓库。该漏洞类似于子域名接管,不难利用,且可导致远程代码注入漏洞。分析完开源项目中的这个问题并递归搜索了其依赖关系的图表后,我们发现了7万个受影响的开源项目,其中包括多家大公司(如谷歌、GitHub、Facebook 等)的流行项目和框架。为缓解该漏洞,需要确保你的项目并不依赖于直接的 GitHub URL,或者使用依赖关系锁定文件和版本固定。


谁受影响?


编译依赖于动态链接的GitHub 仓库代码的所有项目均受影响。项目受影响的条件有二:

1、    你的代码需要直接引用一个 GitHub 仓库(通常是一个依赖关系)

2、    之后,该仓库的所有人需要修改/删除自己的用户名。

当链接仓库的所有人更改了其用户名,那么其他人就可以立即重新注册该仓库。意思是,任何项目,只要直接链接回原始的仓库 URL,那么就易受通过依赖关系劫持造成的远程代码注入影响。恶意攻击者能够注册旧的 GitHub 用户名、重建仓库并通过它将恶意代码注入任意依赖于它的项目。


我该担心吗?


即使你的项目含有 GitHub 上目前并不易受攻击的依赖关系,但如果该依赖关系的其中一个所有人更改了用户名,则该项目及其它所有依赖于老旧链接的项目均易受仓库劫持漏洞的影响。当仓库更改了位置时,你会接收到某种警告信息,如 “404 – 未找到仓库“ 的出错信息,但实际上并没有这种提示。此外,GitHub 的另外一个功能更加剧了该漏洞的危险性:仓库重定向 (Repository Redirects)。

加剧漏洞严重性的仓库重定向“功能

当 GitHub 用户更改了仓库的名称或其用户名时,GitHub 会建立从旧 URL 到新 URL 的重定向;这种重定向适用于 HTTP 和 Git 请求。每当用户更改了其用户名、迁移仓库或更名仓库时,该重定向就会创建。问题在于,如果原始的仓库(在本案例中为 “twitter/bootstrap”)被重建时,重定向会崩溃并将导向新建的仓库。

示例场景

1、  链接https://github.com/twitter/bootstrap 指向仓库 “twitter/bootstrap”,但实际上会将你重定向到 “twbs/bootstrap” 仓库。

2、  如果推特更改了其 GitHub 用户名,则任何人可重新注册该用户名,重建一个名为 “bootstrap” 的仓库,任何新的https://github.com/twitter/bootstrap 请求将会到达新建的仓库。

3、  任何依赖于https://github.com/twitter/bootstrap 的项目将开始从这个新建的仓库中加载代码。

重定向的功能很方便,因为它意味着当你更名自己的账户时,你的链接并不会立即崩溃。但它也意味着你的项目在不知不觉中会变得易受仓库劫持攻击的影响。从你的角度而言,什么都没有改变:你的代码仍然向往常一样进行编译,而所有一切都照旧。然而,你的项目实际上开始易受远程代码劫持漏洞攻击,而你对此一无所知。


三种劫持场景


更具体而言,从技术角度来看,仓库可被劫持的方法有三种:

1、  GitHub 用户更名了自己的账户。这是仓库变得可劫持的最常见的方法,因为用户更名账户的操作并不少见,而当他们更名时,仓库重定向让一切照旧。

2、  GitHub 用户将仓库迁移到另外一名用户或组织机构,之后删除自己的账户。当用户迁移仓库时,重定向就被建立,而删除账户后使得任何人都可劫持该重定向。

3、  用户删除自己的账户。这是影响最小的方法,因为原始用户删除自己的账户后,任何引用它的项目在尝试提取仓库时,将开始收到出错信息。

注:在场景一和二中,攻击者会在用户删除账户和项目尝试提取仓库的间隔内重新注册已被删除的用户名。这一场景此前已讲过,在此不再赘述(https://donatstudios.com/GithubsTotalSecurityFacepalm)。


GitHub 的回复


我们在发布本文之前联系了 GitHub,它表示这是一个已知问题但目前并没有计划更改重定向或用户名复用的方式。它提供了一些针对热门仓库的缓解措施。这些仓库如果在一周内的新 clone 超过100个被删除,那么禁止重新注册仓库名称。它确实提供了某种程度的防护措施但并非万无一失,因为很多规模更小的仓库并不满足这个标准,但仍然是热门项目的依赖关系。因此,想使用这些仓库,开发人员必须直接将链接到 GitHub。

根因不在于 GitHub 对重定向和用户名复用的允许程度,而在于开发人员从不安全的位置 pull 代码。GitHub 无法控制开发人员将其服务用于非预期目的的行为。很多包管理器都在解决远程代码依赖关系的问题,而开发人员有责任确保从安全位置加载代码。


分析


另一个问题是,“这个问题的影响范围有多广?“。遍历所有的开源项目、编译其依赖关系、找出所有可遭劫持的仓库、以及构建易受攻击仓库看的依赖关系图表并非易事。因此,我们使用了如下方法:

第一步:数据收集


大规模分析开源软件最难的步骤之一是,最开始的数据收集。找到所有开源项目保持更新的、准确且易搜索指标,难。我们主要使用了两个数据集,如下:

1、    GitHub Activity 数据

这是 GitHub 本身提供的数据,规模庞大,包括超过280万个仓库及其所有文件和内容;整个数据集的内容大小超过 3TB。不过它托管在 Google Cloud Platform (GCP) 上的一个公开 BigQuery 数据集中,这意味着我们可以在 GCP 本身内部使用 BigQuery 在整个数据集中运行 SQL 命令,而无需下载整个超过3TB大小的文件。

为了真正地执行分析,我们生成了一个正则表达式,可以抓取到任意的 GitHub URL 或其它常见的 GitHub 仓库链接格式如 github:username/reponame。通过该正则表达式,我们可以提取到每个文件(包含 GitHub 链接的引用)的仓库、文件名称和文件内容。这就使我们将搜索空间从 3TB+ 缩小到更易于管理的 4GB 大小。这个过滤后的数据集包括400万个唯一的 GitHub 链接和超过7万个不同的 GitHub 用户。

2、    Libraries.io

Libraries.io 是一个开源项目,旨在将多个不同包管理器中的所有依赖关系累计到图表类的数据集中。这样做很好,因为它不仅为我们省去了匹配依赖的繁重工作,而且整个数据集可免费下载。如不压缩,该数据集的大小虽然超过了100GB,但是可以直接被加载到数据库中,使得处理起来更容易。

这两个数据集起着重要作用,因为它们各有所长。“GitHub Activitiy 数据“数据集可使我们找到仓库中所引用的所有可能的 GitHub 链接,即使链接可能使用在不容易看到的地方如包管理器清单。最有意思的发现并非直接的代码依赖关系。而是,我们经常发现 GitHub URL 直接被用在 bash 脚本中克隆在构建时从 GitHub 中 pull 仓库的仓库或者 docker 镜像中。


另外一个常见的发现是,和 Git 子模块一样可遭劫持的仓库,这是常规依赖关系分析可能错过的地方。相反,libraries.io 数据集是一个已清洗、过滤并格式化的数据集,使我们能够构建一个依赖关系图表并轻松访问该漏洞的延伸程度。总之,这些数据让我们能够更全面地查看该漏洞对开源项目所产生的整体影响。


第二步:数据清洗


收集了这些数据后,我们需要清理并规范化。由于我们需要说明每个包管理器的不同格式,因此工作量巨大。另外,我们想删除实际上并不被用于依赖关系的任何链接。这些链接很多都被用于注释中,如类似于:“//来自github.com/username/reponame 或文档文本文件中的代码”。由于我们主要考虑的是代码注入的可能性,因此我们删除了不会被代码直接使用的部分。这样就剩下超过200万个唯一的 GitHub 链接,它们都是文件以有意义的方式做出的引用。

第三步:可劫持的用户名


拥有更清洁、直接依赖于 GitHub 链接的项目列表后,我们需要找出目前未被注册的用户。此时,我们已经挑选出65万个 GitHub 用户名。通过 GitHub API,虽然我们可以查看是否存在某个用户名,但每个小时的限制请求次数是5000次,也就是说检查完所有的用户名需要超过5天的事件。通过一点点聪明的逻辑以及 GitHub GraphQL API,我们扫描完所有65万个用户只花了2个小时多一点。

那么,结果是什么?我们发现7%(大约5万个)的用户名是未被注册的。实话讲,我们没有想到比例竟然有这么高。我们原本以为不到1%的用户名是可遭劫持的。显然,对用户名感到厌倦的人群远比想象得要庞大。


第四步:易受攻击的项目


拥有所有可被劫持的用户名后,问题就剩下逆向搜索数据集中依赖于由其中一个用户名所拥有仓库的项目。通过进一步过滤和删除误报后,我们发现共有超过1.8万个项目直接易受仓库劫持漏洞的影响。这些项目的 GitHub star 数共计超过50万个,并且包括其中一些最大的开源组织机构的几乎每一种语言。

数字本身就足以令人担忧了,但现代代码库并非生活在单个仓库中的庞然大物。它们依赖于很多其它项目发挥功能。对于可维护性和可复用性而言这样做很好,但它意味着某个热门依赖关系中的要给漏洞就可对依赖关系链中的很多项目产生巨大影响。实际上,依赖于这1.8万个直接易受攻击项目之一的任何项目本身也是易受攻击的。


第五步到∞:依赖关系分析


拥有直接易受攻击的项目后,我们结合之前的数据集进行了依赖关系图污点搜索,结果找到了依赖于供应链中易受攻击仓库的每个项目。在此分析中,我们包含了普通的依赖关系和不太容易发现的依赖关系如开发依赖关系或者不在主软件包清单文件中的依赖关系。如果其中一个辅助依赖关系易受仓库嗅探的影响,那么它对整个依赖关系链的影响可能不会那么快,因为只有当开发人员发布新版本时才会发生这种情况。考虑到这一点,我们开始了污点分析。

由于易受攻击项目列表很可能会膨胀到无法掌控的地步,因此我们一次只分析了图表的一个深度层(depth layer)。在每层切换时,我们手动遍历了结果并删除了明显的误报情况,以便最大程度地减少错误传播,并确保结果不会被错误充斥。

在分析了5个深度层后我们不得不停止。

直到第5次之前,数据按预期增长,并且每轮搜索都会花费一定的时间,但我们达到第6层深度时,数据开始不受控制地增长。查看第5层的结果,原因就清晰了;我们已经触及多个庞大的框架,这些框架是基础性的而且被数千个其它项目所依赖。

这已经足以让我们了解该漏洞所产生的影响了。总体而言,Security Innovation 公司发现了超过7万个受影响的项目,GitHub star 数量超过150万个;这个数字要比前8 GitHub 仓库所得的 star 总数还要多。虽然难以准确衡量,但我们预计这些项目每天的下载量至少是200万。

受影响的项目包含来自庞大组织机构(如谷歌、GitHub、Facebook、Kubernetes、NodeJS、亚马逊等)的仓库。从个人用户项目到由数十万个组织机构使用的热门 Web 框架均受影响。还有一个发现很耐人耐人寻味:你不知道它影响的软件类型数量有多么庞大:易受攻击的路由器固件、游戏、加密钱包、移动应用和很多其它唯一的项目等等不一而足。


缓解措施


了解该漏洞的影响力和影响范围后,有必要了解应该通过哪些缓解措施保护项目供应链的安全。


不要直接链接到 GitHub 仓库


这是最直接的措施:GitHub 仓库从来就不是也从未声称自己是软件包管理器的替代者。无法保证 GitHub 的链接是静态的,它们不应被用作直接的代码依赖关系。使用专有的软件包管理器有很多优势,从可使用性和安全角度来看皆如此,而且应该总是胜于直接链接到仓库。然而,需要注意的是,如果其中一个依赖关系本身直接链接到GitHub URL,那么你仍然可能易受仓库劫持攻击,即使你检查了传递性依赖关系中的直接链接也是如此,其中一个依赖关系可能仍然存在 GitHub 仓库的隐藏依赖关系。我们在 build 脚本中经常看到这种情况,它直接从开发人员的仓库或测试代码内部提取代码。如果它易受隐藏仓库劫持的影响,那么当下次该依赖关系更新后,它可能会含有进入你应用中的恶意代码。


版本固定和锁定文件


另一种缓解方法是通过版本固定和锁定文件。版本固定是指当某个具体版本包含在依赖关系中时,确保只有该版本被下载。在 GitHub 链接依赖关系上下文中,它通常是一个 SHA1 git commit 哈希(用于指令软件管理器工具仅下载某个 git 仓库的特定 commit)。这样做的原因是,即使该仓库被劫持,恶意攻击者也将无法在不修改 commit 哈希的情况下修改该代码。你也可以将依赖关系版本固定到一个特定的分支或标记,但没有办法阻止恶意用户更新该标记或分支,因此它未对仓库劫持提供任何保护措施。

锁定文件是软件包管理器工具制作的文件,包含版本固定依赖关系列表,确保下次当有人试图构建该项目时,他们会下载该锁定文件中指定的同样的软件包和版本。锁定文件有时候包括所下载软件包的完整性哈希,以进一步确保其真实性。

版本固定和锁定文件实现虽然仅针对软件包管理器,但多数大型的软件包管理器也支持这些功能。话虽如此,但它们远非无懈可击。事实上,我们在开展这项研究时,设法绕过了多数主要软件包管理器的版本固定和锁定文件。我们后续将深入分析这些问题。


Vendoring


Vendoring 是指提前将所有的依赖关系下载到仓库中的行为。这样做的好处在于,仓库完全自包含需要运行仓库的代码,同时它有助于防护仓库劫持攻击。由于所有的依赖关系均已下载,因此它就像锁定文件那样同时包含依赖关系的内容。即使其中一个依赖关系遭劫持,你已经下载了所需代码。不过还需警告的是,如果下次当你更新依赖关系时,其中一个依赖关系已遭劫持,那么你可能仍然易受攻击。很多开发人员仅在软件包管理器提醒更新时才更新,而不会查看具体修改的地方。在这些案例中,vendoring 提供的防护力度很小,因为只有当你密切关注依赖关系更新时,它才会发挥作用。


结论


希望本文能帮助大家理解依赖关系仓库劫持所带来的影响,并促使项目所有人更好地保护自己的依赖关系供应链。COTS(商用现成品或技术)、第三方软件和开源将继续发展和扩散,而随之而来的攻击活动也将增多。尽管使用第三方依赖关系会更快地获取功能并节省开发时间,但像对待自己的代码那样,或者说要花费更多的精力对其进行检查仍然至关重要。





推荐阅读
Ripple 20:严重漏洞影响全球数十亿IoT设备,复杂软件供应链使修复难上加难
GitHub 上数十个 NetBeans 开源项目被卷入供应链攻击
FBI 连续第三次发布关于国家黑客利用 Kwampirs 发动全球供应链攻击的警告
Linux 基金会发布《开源软件供应链安全报告》
刚刚GitHub 收购 npm,旨在提升开源软件供应链安全




原文链接
https://blog.securityinnovation.com/repo-jacking-exploiting-the-dependency-supply-chain


题图:Pixabay License


本文由奇安信代码卫士编译,不代表奇安信观点。转载请注明“转自奇安信代码卫士 https://codesafe.qianxin.com”。


奇安信代码卫士 (codesafe)

国内首个专注于软件开发安全的

产品线。

    觉得不错,就点个 “在看” 吧~

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存