通过损害官方Cask存储库,在家中的远程执行代码

2021-04-26 10:32:02

本文也发布以日语:https://blog.rootak.me/post/homebrew-security-security-security/(如果您可以阅读日语,我不擅长英语,所以日语不擅长英语建议阅读文章。)

Homebrew项目正在Hackerone上运行“漏洞披露程序”,允许黑客执行漏洞评估。本文介绍了由Homebrew项目员工的许可执行的漏洞评估,并不意图建议您执行未经授权的漏洞评估。如果您在家中找到了任何漏洞,请将其报告给homebrew项目的漏洞披露程序。

在Homebrew / homebrew-cask存储库中,可以通过混淆由自动化项目开发的自动拉出请求审查脚本中使用的库来合并恶意拉拔请求。通过滥用它,攻击者可以执行任意Ruby代码用户'使用啤酒的机器。

一个下午,我在下次约会之前有少有时间1,所以我决定寻找一个关于Hackerone的一个有趣的程序。我想在我使用的软件/服务中找到漏洞,我在我的电脑上看,酿造的命令抓住了我的眼睛。然后,我记得我看到了一个名为hackerone的程序,所以我决定找到它的脆弱性。

要选择目标,我查看了漏洞泄露程序的策略页面。我注意到主页布鲁克/自主 - *存储库在范围内。由于我不擅长阅读复杂的Ruby代码,我决定找到一个漏洞Homebrew / homebrew- *。

因此,我开始在范围内的存储库上检查这两个漏洞类型。要检查第一个漏洞,我克隆了由Homebrew成员创建的所有存储库,并扫描了一个类似于令牌的字符串。但是,由于Github有一个要扫描的功能对于泄漏的令牌,这几天这种漏洞并不常见。正如预期的那样,我找不到任何有效的令牌。2

Homebrew项目使用GitHub操作来运行CI脚本。3所以我看了。每个存储库的Github / Workflows /目录。

在审核一些存储库后,我对HomeBrew / Homebrew-Cask的Review.yml和automerge.yml非常感兴趣。它看起来像Review.yml检查用户提交的拉拉请求的内容,如果拉请求足够简单(例如,颠簸版),它将批准这些拉请求。之后,Automerge.yml自动合并已批准的拉拔请求。

Review.yml 4使用的ruby脚本将拉出请求内容提取为diff文件,并使用git_diff gem解析它。然后,只有在满足以下所有条件时,它只批准拉出请求:

我仔细审查了上面的条件,但我找不到任何缺陷。所以我得出结论,在这些条件下无法注射任意代码。之后,我正在检查其他脚本一段时间,但由于某种原因,我无法忘记这个脚本。所以我决定挖掘这个脚本并开始查看解析差异文件的库。

虽然我正在研究Git_diff存储库,但我发现了一个问题,报告了错误解析了更改的线路计数。在看到这个问题后,我开始想知道我是否可以以某种方式混淆git_diff并伪装拉扯请求以满足上述条件。

对于每行,检查^ diff --git(?:a /(\ s +))?(?:b /(\ s +))?匹配,如果是,则替换当前正在处理的文件信息与与正则表达式匹配的文件。

如果第2步没有匹配,请检查它是否匹配以下正则表达式之一,并且如果它匹配,则根据内容替换源/目的地的文件路径信息。

如果第3步没有匹配,请将其视为对文件内容的更改,如果它以+从+开头而将其视为加法,如果它开始删除 - 否则将其视为原始文件内容而不修改。

这些过程似乎乍一看是可以的,但是可以在步骤3中多次改变源/目的地文件路径信息。

diff --git a / source文件路径b /目标文件pathindex父提交散列散列.. current commit hash filemode - a / source文件路径+++ b /目标文件路径@@ line信息@@更改的详细信息(例如:`+ Asdf`,`-zxcv`)

这意味着如果添加的线匹配++"?b /(.*),它将被视为文件路径信息,而不是对文件内容的变化。并且通过检查上面所需的条件,我注意到更改的文件路径所需的条件仅为\ acasks / [^ /] +。rb \ z。如上所述,可以多次更改文件路径信息,因此可以通过进行以下改变来绕过上述条件,并且拉出请求将被视为具有0线的无害拉出请求。 6.

作为Hackerone等BUG赏金平台要求报告中的POC /演示,我决定展示这种漏洞。

由于修改在未经许可的情况下修改正在使用的桶并不是一个好主意,因为我试图在家中找到一个测试桶中的Cask存储库。但是,我找不到它。所以我联系了在Hackerone上运营漏洞披露程序的自主研发员工。

之后,我收到了我不能为此添加测试桶,但你可以尝试对现有桶进行无害的修改?来自员工。因此,我选择了一个随机的桶,决定做出无害的变化。

由于我看到了一个在github上无意中发布了一个API令牌的拉索请求,因此我决定更改iterm2.rb,此拉请求正在尝试更新。

在添加修改之前,我注意到++ B / Casks / iterm2.rb如果未定义这些变量,则会抛出错误。所以我刻上了Homebrew / homebrew-cask,并将以下2行添加到Casks / Iterm2.rb。 7.

++" b /#{puts'要报告它 - ryotak(https://hackeorne.com/ryotak )' ;;b = 1; casks = 1; iterm2 = {}; iterm2.define_singleton_method(:rb)do 1结束}" ++ b / casks / iterm2.rb

通过定义B,Casks,Iterm2,Iterm2.rb在第一行中,第二行不会抛出错误。因此,它可以作为有效的Ruby脚本执行。此外,通过添加这些更改,Github将返回以下差异:

diff --git a / casks / iterm2.rb b / casks / iterm2.rbindex 3c376126bb1cf9..ba6f4299c1824e 100644 --- a / cask / iterm2.rb +++ b / casks / iterm2.rb @@ -8,6 +8,8 @@ sha256" e7403dcc5b08956a1483b5defea3b75fb81c3de4345da6000e3ad4a6188b47df"结束+++" b /#{puts'要报告它 - ryotak(https:/hackeorne.com/ryotak )' ;;b = 1; casks = 1; iterm2 = { }; iterm2.define_singleton_method(:rb)do 1结束}" +++ b / casks / iterm2.rb url" https://iterm2.com/downloads/stable/iterm2-# {版本。 dots_to_underscores} .zip"名称" iterm2" DESC"终端仿真器作为Apple'终端应用程序&#34的替代品。

如上所述,Git_diff将匹配+++&#34的行为文件路径信息而不是添加的线条,因此将被视为改变0行的拉请求。

即使在等待一段时间之后,也不合并拉出请求,当我检查CI执行日志时,我注意到拉拉请求的所需状态检查104191不成功。在输出中。通过调查失败的检查,我确认使用BREW样式的工作流程失败,这意味着rubocop拒绝了更改。

rubocop允许源代码通过添加#rubocop来禁用其功能:禁用所有在行的末尾。可以通过添加评论来修复第一行,但第二行无法修复。由于第二行必须在捕获组的捕获组的+++&#34中返回Casks / Iterm2.rb;?b /(.*),无法通过添加评论来修复。

在某些尝试之后,事实证明,可以在不改变以下更改时忽略ROBOCOP而不会更改最后一行:

++" b /#{puts'要报告它 - ryotak(https://hackerone.com/ryotak )' ;;b = 1; casks = 1; iterm2 = {}; iterm2.define_singleton_method(:rb)做1结束; }" #rubocop:禁用所有++" b /"如果#rubocop:禁用所有++ b / casks / iterm2.rb

通过在第二行中添加,让下一行作为IF表达式评估,可以修复操作员/在void上下文中使用。警告。

由于对拉请求的所有检查成功运行,因此BrewtestBot合并了我的拉请求。

随着PLUT请求成功合并,我执行了BREW安装ITERM2 - 扫描并确认要报告它 - 雷托克(HTTPS://Hackerone.com/ryotak)被打印出来。然后在报告中发送图像作为PoC。

之后,在等待对我发送的报告的回复时,我收到了以下回复Twitter。我无法理解它几秒钟,但不知何故啤酒清理打印要报告它 - 雷托克(https://hackerone.com/ryotak)。

当我匆忙尝试在我的机器中时,我可以确认报告它 - 即使在执行啤酒清理时,也会显示ryotak(https://hackerone.com/ryotak)。

我没有注意到它,因为我此时匆忙,但由于稍后调查,我发现如果有人执行了Brew Source等,则执行修改后的桶。它旨在在执行某些命令时评估所有桶,因此即使未安装目标桶,也会执行修改后的代码。

由于我所做的唯一更改是打印其他日志,并且维护者立即恢复了更改,这没有太大的影响。但是,我很惊讶,因为我没想到这种情况发生。

在本文中,我描述了在家官方水龙头中存在的漏洞。如果由恶意演员滥用这种漏洞,则可以用来损害在恢复之前运行啤酒的机器。因此,我强烈觉得需要对集中式生态系统进行安全审计。我想对PYPI / NPM注册表&amp执行安全审核; MLDR等,但由于它们不允许明确的漏洞评估,我不能这样做。

如果您对本文有任何意见/疑问,请在Twitter上发送消息(@Rootkak)。

具体而言,它与日光匹配等待时间大致相同,在改进之前等待时间。 ↩︎

此外,Homebrew有一个与GitHub API令牌的泄漏有关的事件,因此似乎成员的认识足够高。 ↩︎

对不起,过去的三篇文章均与GitHub操作有关。 (但GitHub动作是一个非常好的攻击表面。)↩︎

我省略了我发现的漏洞不重要的条件,但有许多其他条件。如有许多其他条件。请检查https://github.com/homebrew/actions/blob/bac0cf0eef64950c5fa7b60134da80f5f52d87ab/.github/workows/review-cask -pr.yml↩︎ 它有意的是,第二行不是字符串文字,因为Git_diff中的另一个错误,关闭字符串文字时不会忽略双引号。 ↩︎ 此时,我认为只有在Brew Installial中指定的情况下只会执行每个Cask文件。在维护者处于联系的情况下,我认为如果它立即被恢复,则不会立即恢复,用户将无法执行修改后的代码。 ↩︎