【赏金猎人】绕过 GitHub 的 OAuth 流程漏洞利用

admin 2023年8月5日12:38:23评论16 views字数 2813阅读9分22秒阅读模式

点击上方蓝字“Ots安全”一起玩耍

在过去的几年里,安全研究一直是我在业余时间做的事情。我知道有些人靠漏洞赏金计划谋生,但我个人只是在有需要的时候在这里和那里度过几个小时。


也就是说,我一直想弄清楚如果我选择全职工作,我是否能够靠漏洞赏金谋生。所以我在今年夏天尝试这样做了几个月,每天花几个小时在 GitHub 中寻找安全漏洞。


我的主要工作流程是下载GitHub Enterprise的试用版,使用此脚本的修改版本对其进行反混淆,然后盯着 GitHub 的 Rails 代码一段时间,尝试发现任何奇怪或可利用的东西。总的来说,从安全的角度来看,GitHub 的代码似乎是非常好的架构。我偶尔会发现由某些应用程序逻辑中未处理的情况引起的错误,只是意识到该错误并没有造成安全问题,因为(例如)代码无论如何都在以降低的权限运行查询。几乎每个应用程序都有漏洞,但安全工程的一大挑战是在不知道漏洞的情况下使漏洞无法利用,GitHub 似乎在这方面做得很好。


即便如此,我还是在夏天找到了一些有趣的问题,包括完整的 OAuth 授权绕过。


GitHub 的 OAuth 流程

六月的某个时候,我在查看实现 GitHub 的OAuth 流程的代码。简而言之,OAuth 流程应该是这样工作的:

  1. 某些第三方应用程序(“Foo App”)想要访问用户的 GitHub 数据。它将用户发送到https://github.com/login/oauth/authorize查询字符串中的一堆信息。

  2. GitHub 向用户显示授权页面,如下所示。

    【赏金猎人】绕过 GitHub 的 OAuth 流程漏洞利用

  3. 如果用户选择授予对应用程序的访问权限,他们会单击页面上的“授权”按钮,并使用查询字符串中的授权代码重定向到 Foo 应用程序。然后可以使用此代码访问请求的数据。(用户也可以拒绝将他们的数据提供给应用程序。)


在查看此内容时,我查看了“授权”按钮的实现方式。事实证明,按钮实际上是一个自包含的 HTML 表单,它发送带有一些隐藏表单字段的 POST 请求,包括 CSRF 令牌。当该 POST 请求被发送(并且 CSRF 令牌被验证)时,用户被认为已授予应用程序的权限。目前看来还算合理。


有趣的是,“授权”按钮的端点 URL 是/login/oauth/authorize,恰好与授权页面本身的 URL 相同。GitHub 根据 HTTP 请求方法(GET请求返回 HTML 授权页面,POST请求授予应用程序权限)确定要发送的响应。


这种行为切换实际上发生在应用程序代码中。路由器将两者GET和POST请求转发到同一个控制器

# In the router
match "/login/oauth/authorize", # For every request with this path... :to => "[the controller]", # ...send it to the controller... :via => [:get, :post] # ... as long as it's a GET or a POST request.
# In the controller
if request.get? # serve authorization page HTMLelse # grant permissions to append

所以路由器接受一个GET或一个POST请求,控制器检查发送了哪种类型的请求并做出相应的动作。乍一看,这似乎不是问题——也不会是问题,除非路由器没有说实话。


HTTP HEAD 请求,以及为什么 Rails 路由器有时会撒谎

让我们来谈谈 HTTP 方法。


自 HTTP 最初创建以来,HTTPHEAD方法一直存在,但它并没有得到很多使用。当服务器收到一个 HEAD 请求时,预期的语义是,“假装这是一个 GET 请求,但只发回没有响应正文的响应头”。这有一些利基用途。例如,客户端可以在决定是否要开始下载文件之前发送HEAD请求以检查大文件的大小(通过Content-Length响应头)。


自然地,编写 Web 应用程序的人通常不想花时间为 HEAD 请求实现行为。可以理解,获得一个有效的产品比遵守 HTTP 规范的小众部分更重要。但总的来说,如果 HEAD 请求能够被正确处理就好了,前提是应用程序开发人员不必手动处理它们。因此,滑轨(与其他一些Web框架一起)实现了一个聪明的黑客:它试图路线HEAD,因为它会请求路由到同一个地方GET的请求然后它运行控制器代码,只是省略响应主体。

参考:

(https://github.com/rails/rails/blob/bc5d9567be44e6241a049c01605ad6cfefe42e10/actionpack/lib/action_dispatch/journey/router.rb#L133-L147)。



这很好,但这是一个有漏洞的抽象。如果控制器调用request.get?这样的请求,它将返回 false,因为它仍然是一个HEAD请求,而不是一个GET请求。


滥用 HEAD 请求

如果我们向 发送经过身份验证的HEAD请求会发生什么https://github.com/login/oauth/authorize?我们已经得出结论,路由器会将其视为GET请求,因此它将被发送到控制器。但是一旦它在那里,控制器就会意识到它不是一个GET请求,因此该请求将由控制器处理,就好像它是一个经过身份验证的POST请求一样。因此,GitHub 将找到请求中指定的 OAuth 应用程序,并授予它访问经过身份验证的用户数据的权限。


为什么这很有用?好吧,GitHub 的 CSRF 保护要求所有经过身份验证的POST请求都包含 CSRF 令牌。但是HEAD请求不需要 CSRF 令牌,因为它们不应该有副作用。因此,我们可以发送一个跨站点认证HEAD请求,该请求将授予任意 OAuth 权限,而根本不向用户显示确认页面。


因此,如果用户访问了攻击者的网站,攻击者就可以任意读取或修改用户 GitHub 帐户中的私人数据。这是一个概念验证(它不再有效,因为该问题已被修补)。


我向 GitHub 的 bug 赏金计划报告了这个问题,他们在大约三个小时内将修复程序发送到生产环境。我还获得了 25000 美元的赏金(!),这在当时是 GitHub 计划中最高的赏金。


时间线

  • 2019-06-19 23:28:56 UTC问题在 HackerOne 上报告给 GitHub

  • 2019-06-19 23:36:50 UTC问题由 GitHub 安全团队确认

  • 2019-06-20 02:44:29 UTC问题已在 github.com 上打补丁,GitHub 在 HackerOne 上回复以仔细检查补丁是否完全解决了问题

  • 2019-06-26 16:19:20 UTC GitHub Enterprise 2.17.3、2.16.12、2.15.17 和 2.14.24 随补丁一起发布(参见GitHub 的公告)。

  • 2019-06-26 22:30:45 UTC GitHub 奖金 25000 美元

【赏金猎人】绕过 GitHub 的 OAuth 流程漏洞利用

原文始发于微信公众号(Ots安全):【赏金猎人】绕过 GitHub 的 OAuth 流程漏洞利用

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年8月5日12:38:23
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   【赏金猎人】绕过 GitHub 的 OAuth 流程漏洞利用http://cn-sec.com/archives/1105544.html

发表评论

匿名网友 填写信息