Bitbucket服务器参数注入漏洞(CVE-2019-15000)

Posted by caiqiqi on 2019-11-03

原文:
https://mp.weixin.qq.com/s/3J-lA0CQylrq2ZY3ZEESiQ

首先来看一下哪些参数可控哪些不可控,以及各个参数在整个命令中的位置:

/usr/bin/git diff -C --color=never -U10000 --dst-prefix=dst:// --src-prefix=src:// <可控sinceId> <可控untilId> -- <可控待diff文件名>

由于漏洞描述中说由于参数注入可以 造成命令执行,于是开始花了大量时间找类似于git ls-remote命令的--upload-pack参数;git grep命令的--open-files-in-pager参数进行漏洞注入的方式。但是看了很久git diff命令一直没找到合适的参数。看到的唯一带执行命令的参数是--ext-diff

Allow an external diff helper to be executed. If you set an external diff driver with gitattributes(5), you need to use this option with git-log(1) and friends.

然而尝试之后发现需要预先在.gitconfig文件或者git全局配置中指定好外部diff命令的路径,于是这个漏洞就搁置了。
最近看到这篇文章中的分析,才恍然大悟。这里把我对这篇文章中利用方式的理解记录一下。

利用步骤如下:
第一步,这里使用--output=--,通过在sinceId处注入--output选项,指定diff结果导出到--文件中,在工作目录下生成一个空的--文件(后续用到);

第二步,无论 -- /etc/passwd前面有0个、1个或者2个commit hash都会由于不可控参数--的存在,而导致--后面的文件被当作文件路径被解析,而且这个文件不能在工作区(working tree)之外。否则会提示:

fatal: /etc/passwd: '/etc/passwd' is outside repository

而读取失败。

这里先生成一个--文件,然后拼接出-- -- /etc/passwd的参数列表。这里由于新插入的前面的--的存在,将原本后面的--参数当作一个文件看待;然后再通过注入--no-index参数,拼接出

git diff --no-index -- -- /etc/passwd

的命令(这个命令的含义是对两个文件--/etc/passwd进行diff操作),利用其可以读取工作区(working tree)之外文件的特性,成功读取出工作区外的任意文件。

两个步骤模拟如下:

附录

git diff命令:

–output选项

–output=
Output to a specific file instead of stdout.

–no-index选项

You can omit the –no-index option when running the command in a working tree controlled by Git and at least one of the paths points outside the working tree, or when running the command outside a working tree controlled by Git.

官方热补丁

官方发布的hotfix的修复方式是拦截以--开头的commitId然后响应400。

参考