前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >赏金$10000的GitHub漏洞

赏金$10000的GitHub漏洞

作者头像
程序猿DD
发布2020-11-09 10:56:00
6470
发布2020-11-09 10:56:00
举报
文章被收录于专栏:程序猿DD程序猿DD

本文来源: https://www.anquanke.com/post/id/220963

本文是翻译文章,文章原作者William Bowling,文章来源:devcraft.io 原文地址:https://devcraft.io/2020/10/19/github-gist-account-takeover.html

0x01 前言

安全研究员William Bowling在研究GitHub用于生成url的每种方法过程中,找到了可用于创建所需令牌的方法url_for,并实现了Gist账户接管,最终获得$10000赏金。

0x02 漏洞发现

url_for方法经常被用来生成指向其他控制器的链接。虽然无法找到任何地方可以作为旁路使用,但也发现了一些点,调用url_for与用户一个可控的哈希。这时候,哈希中的任何额外的参数都会被附加到url中作为一个查询字符串。通过查看档,发现有相当多的选项是可以控制的:

1 .:only_path – 如果为true,返回相对的URL。默认为false

2 .:protocol – 要连接的协议,默认为http

3 .:host – 指定链接的目标主机。如果:only_path为false,则必须显式或通过default_url_options提供该选项

4 .:subdomain – 指定链接的子域,使用tld_length将子域与主机分割开来。如果为false,则删除链接主机部分的所有子域

5 .:domain – 指定链接的域,使用tld_length将域从主机中分割出来

6 .:tld_length – TLD id 组成的标签数,只有在提供 :subdomain 或 :domain 时才使用。默认值为ActionDispatch::Http::URL.tld_length,而默认值为1

7 .:port – 可选择指定连接的端口

8 .:anchor – 附加在路径上的锚名称

9 .:params – 要附加到路径上的查询参数

10 .:trailing_slash – 如果为true,则在路径后面添加一个斜线,如”/archive/2009/“

11 .:script_name – 指定相对于域根的应用程序路径。如果提供了,则预置应用程序路径

我以前在其他应用程序中看到过一些比较常见的选项,比如:protocol, :host 选项被列入黑名单/删除,或者:only_path 被设置为 true 以防止被使用(即使是 brakeman 建议这样做是安全的),但以前从未见过 :script_name param。它被path_for方法使用,如果它存在,将被用在路径的开头:

代码语言:javascript
复制
def path_for(options)
    path = options[:script_name].to_s.chomp("/")
    path << options[:path] if options.key?(:path)

    add_trailing_slash(path) if options[:trailing_slash]
    add_params(path, options[:params]) if options.key?(:params)
    add_anchor(path, options[:anchor]) if options.key?(:anchor)

    path
end

GitHub上有几个地方使用了下面类似的代码创建链接:

代码语言:javascript
复制
<a class="link" href="<%= url_for(request.query_parameters.merge(only_path: true)) %>">
    Click me
</a>

这就意味着,如果使用字符串?script_name=javascript:alert(1)//最终会生成以下html:

代码语言:javascript
复制
<a class="link" href="javascript:alert(1)//user/repo/...">
    Click me
</a>

然而,这只是一个低严重性的反射型XSS,需要点击,也被CSP所阻止,但这仍然可以看做一个有趣的bug。

关注公众号:后端面试那些事儿,每天学一点,一起进大厂!

随后,我发现另一个地方使用url_for与可控参数,这次是作为重定向的一部分。这段代码在应用程序控制器中,做了如下操作(方法/参数名称已被更改):

代码语言:javascript
复制
 before_action :check_source

  def check_source
    source = params["source"]
    return redirect_to(check_source_redirect_url) if source == "message"
  end

  def check_source_redirect_url
    query = Addressable::URI.parse(request.env["REQUEST_URI"]).query_values || {}
    filtered_params = query.except("source", "token").merge(only_path: true)
    url_for(filtered_params)
  end

由于使用only_path: true,通常只允许使用现有主机的URL,只保留查询参数。但如果使用script_name就会得到一些有趣的结果,script_name不需要以斜杠开头,当与redirect_to一起使用时,可以被附加到host中:

代码语言:javascript
复制
curl -i 'http://local.dev?source=message&script_name=ggg'
HTTP/1.1 302 Found
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Download-Options: noopen
X-Permitted-Cross-Domain-Policies: none
Referrer-Policy: strict-origin-when-cross-origin
Location: http://local.devggg/welcome/index
Content-Type: text/html; charset=utf-8
Cache-Control: no-cache
X-Request-Id: 7c8eedfa-f552-4d5a-bbcd-295f4e7fd9c0
X-Runtime: 0.002744
Transfer-Encoding: chunked

<html><body>You are being <a href="http://local.devggg/welcome/index">redirected</a>.</body></html>

由于域名的结尾是可控的,如果用.attacker.domain作为script_name,就会重定向到他们的域名。

关注公众号:程序猿DD,与一线架构师共成长!

0x03 漏洞利用

第二天,我和corb3nik聊起开放重定向的影响,他提到 OAuth tokens 是很挖掘的目标。回头再看这个重定向bug,我发现它其实很厉害,因为它在应用控制器中很早就被影响,这意味着将影响几乎所有的路径(所有的控制器都会扩展应用控制器)。

GitHub自带一些内置的OAuth应用,其中一个就是针对Gist的。GitHub Gist与GitHub是同一个rails应用,只是在不同的主机名后面,拥有有不同的路径。当登录Gist时,通过正常的OAuth流程是一大堆重定向,看起来像这样:

1 .https://github.com/login/oauth/authorize?client_id=7e0a3cd836d3e544dbd9&redirect_uri=https://gist.github.com/auth/github/callback

2 .https://gist.github.com/auth/github/callback?browser_session_id=XXX&code=YYY

3 .https://gist.github.com/auth/github

4 .https://github.com/login/oauth/authorize?client_id=7e0a3cd836d3e544dbd9&redirect_uri=https%3A%2F%2Fgist.github.com%2Fauth%2Fgithub%2Fcallback&response_type=code&state=ZZZ

5 .https://gist.github.com/auth/github/callback?browser_session_id=XXX&code=YYY&state=ZZZ

6 .https://gist.github.com/

为了成功登录Gist,攻击者只需要browser_session_idcode,因为client_id是公开的,state param可以由攻击者生成,因为它只是为了防止CSRF。

初始重定向redirect_uri携带有codebrowser_session_id ,所以我试着在其中添加 script_name=.wbowling.info。结果成功了,我被重定向到我自己的域名,并添加了所需的参数。

在一个新建的浏览器隐私页面,我去https://gist.github.com/auth/github/callback,抓取一个有效的状态参数,然后使用这份browser_session_idcodestate参数,成功登录了账户。

由于GitHub和Gist使用不同的会话令牌,虽然它不允许访问github.com,但允许完全访问Gist。

最终我因为这个发现,获得了$10000的赏金。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-11-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序猿DD 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 0x01 前言
  • 0x02 漏洞发现
  • 0x03 漏洞利用
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档