简介

GitHub企业版(GHE)的代码默认是混淆的,但是有脚本可以把他们恢复为常规ruby文件.

影响版本:GitHub Enterprise < 2.21.4

修复该漏洞的版本: GitHub Enterprise 2.21.4 released fixing the issue

git基本命令

git revert: 撤销某个单一的commit. 本文中的"撤销"就是gitrevert

历史漏洞

参考 https://enterprise.github.com/releases/2.17.6/notes

GitHub Enterprise 2.17.6 August 13, 2019

漏洞原理:使用以一个-字符开头的"分支名称"(branch names),向git命令中注入选项,允许攻击者截断服务器上的文件。

我认为这个漏洞是一个很好的开始,我看看GitHub企业版(GHE)是否存在类似的漏洞。

发现新漏洞

我开始搜索git进程被调用的所有位置,然后追溯参数,查看它们是否是用户可控的,以及是否已正确清理(sanitised)。

  • 发现情况是这样的:
    • 大多数地方要么将用户控制的数据放在--命令后面,以使它永远不会被解析为选项
    • 要么进行检查以确保它是有效的sha1或commit hash值,并且不以-开头

过了一会儿,我找到了reverse_diff方法,该方法进行了2次"提交"(commits),最终git diff-tree与它们一起运行,并且唯一的检查是对于存储库(sha,branch,tag等)都存在有效的git引用(git references)。追溯可知,此函数由revert_range在之前的2个wiki"提交"(commits)之间进行"撤销"(reverting)时使用的方法调用。

因此,发送POST请求到user/repo/wiki/Home/_revert/57f931f8839c99500c17a148c6aae0ee69ded004/1967827bcd890246b746a5387340356d0ac7710a
会将值(实际参数)57f931f8839c99500c17a148c6aae0ee69ded0041967827bcd890246b746a5387340356d0ac7710a传入reverse_diff,调用该函数。

完美,我checked out了一个repo(仓库),并通过命令git push origin master:--helppushed出一个新的分支 名为–help,之后尝试发送POST请求到user/repo/wiki/Home/_revert/HEAD/--help。但是没有成功,返回的提示信息是422 Unprocessable Entity
为什么会这样?查看服务器日志后发现,是因为 CSRF 令牌无效。事实证明,rails现在具有基于表单的CSRF token,这些token是根据要POST的路径生成的。
没有检查查询参数,但是在本例中,路由设置为只允许"提交"(commits)的路径参数。

"撤销"(revert)的形式以及有效token是由"wiki比较模板"(wiki compare template)生成的,但遗憾的是,它的验证更加严格,且要求commit具有有效的sha hashes。这意味着我们无法为–help分支提供有效的表单(form)和token,仅能为具有有效的sha hashes的commit提供:有效的表单(form)和token。

深挖rails中的valid_authenticity_token?方法(你没看错这个方法最后面是个问号),可以发现,绕过每个表单(form)CSRF的另一种方法是使用全局token,因为存在这样一个"代码路径"(code path),可以在转换时使现有表单向后兼容。
as there is a code path to make existing forms backwards compatible while transitioning.

def valid_authenticity_token?(session, encoded_masked_token) # :doc:
    if encoded_masked_token.nil? || encoded_masked_token.empty? || !encoded_masked_token.is_a?(String)
        return false
    end

    begin
        masked_token = Base64.strict_decode64(encoded_masked_token)
    rescue ArgumentError # encoded_masked_token is invalid Base64
        return false
    end

    # See if it's actually a masked token or not. In order to
    # deploy this code, we should be able to handle any unmasked
点击收藏 | 0 关注 | 1
  • 动动手指,沙发就是你的了!
登录 后跟帖