这几年来,信息安全研究一直是我的业余爱好,虽然有很多人专职做漏洞众测以获得奖励,但对我个人来说,我只对一些感兴趣的项目投入不多的时间去深入研究。今年,我想看看自己是否是全职漏洞赏金猎人的料,所以就从6月份开始每天抽出几个小时的时间去测试GitHub的安全漏洞。

我对GitHub的主要测试方法为,下载试用版的GitHub Enterprise,然后用我写的脚本把它反混淆(deobfuscate),然后观察GitHub的 Rails 代码查看是否有一些奇怪的行为或漏洞。从安全开发的角度来说,GitHub的的代码架构做得非常好,虽然我能偶而发现一两个由应用逻辑处理导致的小bug,但最终都不会导致大的安全问题,而且整个代码的运行权限较低,根本无从下手。看来GitHub做的滴水不漏,天衣无缝。但尽管如此,我还是想方设法绞尽脑汁地发现了GitHub的一些有趣漏洞,其中就包括它的一个OAuth授权验证绕过漏洞。

GitHub的OAuth授权验证机制

在6月份的时候,我开始测试GitHub的OAuth授权验证机制代码,简单来说,这里的GitHub OAuth授权验证流程如下:

1、某第三方应用 (这里暂且叫“Foo App”) 想要访问GitHub用户的数据,它会向GitHub用户发送包含大量查询信息的链接:https://github.com/login/oauth/authorize;

2、之后,GitHub用户端会显示以下授权页面:

3、如果GitHub用户选择允许第三方应用访问,他需要点击“Authorize” 按钮,接着,就会跳转匹配到Foo App的查询字符串,这些字符串代码后续将会访问到GitHub用户的相关数据;(当然,GitHub用户也可以选择拒绝Foo App的访问)

在检查该流程时,我首重查看了“Authorize”按钮的具体实现行为,之后我发现该“Authorize”按钮其中是一个独立的HTML格式,它会发送一个包含CSRF token在内的隐藏表单字段的POST请求。当该POST请求被发送后,此时其CSRF token是被验证过的,也就是代表GitHub用户想要授权给第三方APP访问权限。这种猜测基本是合理的。

有意思的是,“Authorize”按钮对应的终端URL链接也是/login/oauth/authorize,它和授权验证页面是一样的URL,GitHub会根据HTTP请求方法的响应来确定如何执行下一步操作(GET请求会返回授权页面的信息,而POST请求会得到相应的授权)。

这种行为切换实际上发生在Github的内部代码中,路由router会把GET 和 POST 请求转发到同一个控制器controller上,如下:

# In the routermatch "/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 controllerif request.get?  # serve authorization page HTMLelse  # grant permissions to append

所以,最后路由router会接受GET 或 POST 请求,而控制器controller会检查哪种请求被发送了,从而执行后续动作。乍一看,这不算是什么安全问题,但是,深入探究发现,路由router机制存在隐患。

Rails 路由能够识别 URL 地址,并把它们分派给控制器动作或 Rack 应用进行处理。它还能生成路径和 URL 地址,从而避免在视图中硬编码字符串。

HTTP HEAD请求时Rails路由在说谎

HEAD方法跟GET方法相同,只不过服务器响应时不会返回消息体。一个HEAD请求的响应中,HTTP头中包含的元信息应该和一个GET请求的响应消息相同。这种方法可以用来获取请求中隐含的元信息,而不用传输消息实体本身。也经常用来测试超链接的有效性、可用性和最近的修改。

自HTTP协议被创建以来,HTTP的HEAD方法就一直存在了,但是人们对它的使用较少。当服务器收到HEAD请求时,只会向客户端发送回响应头,而不发送响应体,这有一些特殊用途。例如,在决定是否要开始下载文件之前,客户端可以发送HEAD请求来检查大文件的大小(通过内容长度响应头来确定)。

显然,编写网络应用程序的人通常不想花时间来实现HEAD请求的行为。可以理解的是,获得一个有效的产品比符合超文本传输协议规范的特定部分更为重要。但总的来说,如果HEAD请求能够得到正确处理,这是件好事,前提是应用程序开发人员不必手动处理它们。所以Rails以及其它的一些网络框架采用了一个聪明的技巧:它试图将HEAD请求路由到与GET请求相同的地方,然后运行控制器代码,以此省略掉消息响应体。

这看上去很好,但却是一个漏洞百出的抽象概念,如果此时控制器发出request.get?的请求,对于这样的请求,因为现在控制器是HEAD请求,而不是GET请求,所以将会返回false。

滥用HEAD请求

如果我们向https://github.com/login/oauth/authorize?发送一个授权验证的HEAD请求,将会发生什么情况?前面我们说过,Rails路由会把它当成GET请求来处理,所以它会被发送到控制器中。但当HEAD请求到达控制器后,控制器会意识到这不是一个GET请求,所以控制器会检查它是否是一个经过授权验证的POST请求,之后, GitHub会找到请求中指定OAuth授权流程的APP,并给予相应的访问授权。

这里的利用点是,GitHub的CSRF防护机制要求所有授权验证POST请求必须包含一个 CSRF token,但是HEAD请求由于不会造成过多影响,所以通常不需要CSRF token。但在此,我们可以无需告知目标用户的方法,通过跨站方式向用户发送一个给予任意OAuth权限的HEAD请求,以此实现我们的授权绕过目的。

最终效果是,如果目标Github用户访问了由攻击者构造的页面,攻击者可以执行对目标Github用户隐私数据的读取或更改,可以点击此PoC页面进行体会(由于漏洞已经被修复,最终执行结果不再有效)

我向Github上报了该漏洞后,它们在三小时内就积极进行了修复,最终我也收获了Github官方$25000的奖励!是我做Github漏洞测试以来的最大一笔奖金。

漏洞上报及处理进程

2019-06-19  通过HackerOne向GitHub上报漏洞

2019-06-19  GitHub安全团队确认漏洞

2019-06-20  漏洞修复,GitHub确认补丁已成功释放

2019-06-26  GitHub推出修复版本的 Enterprise 2.17.3, 2.16.12、2.15.17 和 2.14.24

2019-06-26  GitHub奖励我$25000

*参考来源:teddykatz,clouds 编译整理,转载请注明来自 FreeBuf.COM

精彩推荐

oauth最后的确认按钮_绕过GitHub的OAuth授权验证机制($25000)相关推荐

  1. oauth最后的确认按钮_spring-oauth集成cas单点登录,登陆完成进入授权页面后,按回退按钮进入404页面的问题...

    背景: 1.项目中使用耶鲁的cas做单点登录. 2.使用spring-oauth包实现oauth2服务 3.使用spring-cas做spring-security及cas的集成 现象: 开发报了个b ...

  2. bootstrap 单选按钮点击change事件 只触发一次_微信支付新增“确认”按钮,付错钱将成为历史?...

    阅读本文之前,麻烦您先点击上面蓝色字体"蓝色字体",再点"关注",这样您就可以继续"免费"收到文章了,每天都有分享,完全是"免费订 ...

  3. github项目怎么运行_利用 GitHub 从零开始搭建一个博客

    "NightTeam",一个值得加星标的公众号. 趁着周末,搭建了一下 NightTeam 的官方博客和官方主页,耗时数个小时,两个站点终于完工了. 由于 NightTeam 的域 ...

  4. python创建按钮_掌握Python之Tkinter按钮组件的创建及使用

    不学python功能按钮肯定是不完整的啊,尤其是在使用python过程中,大量需要使用的tkinter,要怎么利用这个模块去创建个功能键呢?一起来看下吧~ 使用tkinter.Tk() 生成主窗口(r ...

  5. 修改vant 弹窗Dialog组件调用是确认按钮与取消按钮的文字

    文章目录 修改vant 弹窗Dialog组件调用是确认按钮与取消按钮的文字 效果图 · 示例: 重要代码如下(部分): 代码使用 · 注意事项: 官方文档参数定义 · 注意事项: 文章阅读: 修改va ...

  6. 如何调换antd中Modal对话框确认按钮和取消按钮两个按钮的位置

    今天有个工作是把所有的确认按钮放在取消按钮的左边,类似于下图这样的,公司用的时antd组件 但是antd组件的按钮时确认键放在右边的 可以采用下面的方式,将按钮调换过来: 对的,就是在modal里面的 ...

  7. android 支付选择按钮,微信支付新增“确认”按钮,更安全还是更麻烦?

    近日,安卓版微信悄悄更新了版本,在最新的V7.0.5版本中,微信支付的付款界面和步骤发生了变化. 据移动支付网了解,此次微信支付更新之后,个人转账过程中,会弹出微信自带的安全键盘,而且输入金额时会有相 ...

  8. 小程序中的confirm-type设置键盘的确认按钮

    详情: confirm-type是很多小程序组件中的一种设置,用于改变输入键盘右下角的确认按钮.比如说,正常情况下,键盘上的默认提示可能是完成,但是你可以通过confirm-type将其设置为发送,搜 ...

  9. elementUI二次确认按钮

    开发中需要用到二次确认按钮,防止误触等操作. 原代码为: el-button @click="changeBtn()">修改</el-button> (修改函数已 ...

最新文章

  1. java 反序列化利用工具 marshalsec 使用简介
  2. 向Python女神推荐这些年我追过的经典书籍
  3. php mysql简单留言本_php+mysql写的简单留言本实例代码
  4. linux运行星际争霸1
  5. 微软块级备份引擎服务器,文件级与块级备份区别
  6. 指令系统——数据存放、指令寻址(详解)
  7. 《软件项目管理(第二版)》第 9 章——项目监督与控制 重点部分总结
  8. 图片处理和验证码识别
  9. 关于T_SQL中声明变量类型的基础知识。
  10. (连载0.2)加强版Python提取上市公司年报报告中财务报表
  11. 无法使用tftp下载Linux内核到开发板,总是显示TTTTTTTTT的原因
  12. Hex Fiend很强大
  13. poj2391 Ombrophobic Bovines 拆点连边要注意
  14. uniapp实现app跳转app
  15. unity 打开外部虚拟键盘 exe文件
  16. Python报错不要慌,这三个关键词帮你解决问题!
  17. js var多等式变量的定义
  18. docker 命令大全
  19. 门禁|梯控管理系统CPU卡读写器发卡器HX-WR03密码设置操作说明
  20. TongWeb及应用系统安全加固

热门文章

  1. Android项目中出现的Plugin with id ‘kotlin-android‘ not found解决方法
  2. 在Django中,“子弹”是什么?
  3. 马蜂窝事件背后暴露出的数据风险
  4. github建站之路
  5. swift4.0 确定手势滑动方向
  6. 简单时间复杂度大O记法
  7. 常纪文:智慧城市有助于实现低碳绿色发展
  8. Mybatis3.3.x技术内幕(十三):Mybatis之RowBounds分页原理
  9. C语言实现简易通讯录
  10. glVertexPointer