GIT-SHELL 沙盒绕过(CVE-2017-8386)导致任意文件读取、可能的任意命令执行漏洞。
测试环境
为了不和docker母机的ssh端口冲突,将容器的ssh端口设置成3322。本目录下我生成了一个id_rsa
,这是ssh的私钥,连接的时候请指定之。
在连接以前,需要先设置私钥的权限为0600:chmod 0600 id_rsa
,否则连接可能失败。
正常连接其ssh服务ssh -p 3322 -i id_rsa git@127.0.0.1
,会被git-shell给拦截,返回错误fatal: unrecognized command ''
,并且连接被关闭。
使用--help技巧,连接目标并进入帮助页面:
ssh -p 3322 -i id_rsa -t git@127.0.0.1 "git-upload-archive '--help'"
按shift
+e,读取任意文件:
回到帮助页面,输入!id
执行命令:
(为什么是www-data用户?因为git用户和www-data用户编号都是33,所以其实他们是一个用户)
原理
基于ssh协议的git拉取流程
git-shell是git服务中重要的组成部分,众所周知,git服务支持ssh、git、https三种协议来传递项目,其中ssh是最安全,也最方便的一种方式。
我们随便打开Github上一个项目,找到Clone with SSH
里列出的地址:git@github.com:phith0n/vulhub.git,其实这个url就是告诉git,ssh用户名是git,地址是github.com(默认端口是22),该项目位于phith0n/vulhub.git
这个目录下;然后git就通过ssh协议连接上github.com,并将对应目录下的项目拉取下来。
所以,基于ssh协议的git clone等操作,本质上就是通过ssh协议连接上git服务器,并将指定目录拉取下来的过程。
那么,既然这个过程是个ssh交互的过程,那么我直接执行ssh git@github.com
是不是就可以登录github服务器了呢?显然是不行的,你可以试试:
说"不行"其实也有偏差,实际上我确实是连接上了其ssh服务,并验证身份通过了,但他给了我一段提示信息"Hi phith0n! You've successfully authenticated, but GitHub does not provide shell access.",就把我的连接关了。
所以,正常来说,基于ssh的git拉取过程对于git服务器是安全的。
关于如何搭建一个git服务器,可以参考这篇文章
如何禁止git用户执行系统shell
那么,github这类git服务商是怎么实现上述"安全"通信的流程的呢?
让用户可以通过ssh认证身份,但又不给用户shell,这个过程有两种方法实现:
-
创建系统用户git的时候将其shell设置成git-shell
-
在authorized_keys文件每个ssh-key的前面设置command,覆盖或劫持重写原本的命令
第一种方法比较直观,就是创建用户的时候不给其正常的bash或sh的shell,而是给它一个git-shell。git-shell是一个沙盒环境,在git-shell下,只允许执行沙盒内包含的命令。
第二种方法不仅在git服务器上使用,很多Linux发行版也会用到。比如aws,默认安装后是不允许root登录的,实现方法就是在/root/.ssh/authorized_keys中设置command="echo 'Please login as the user \"ec2-user\" rather than the user \"root\".';echo;sleep 10"
。这句话相当于覆盖了原本执行的shell,变成了echo一段文字。
当然,第二种方法内也可以用git-shell,比如在添加git用户的时候赋予其正常的/bin/bash
,但在authorized_keys中设置command="git-shell -c \"$SSH_ORIGINAL_COMMAND\""
,实际上还是使用了git-shell。
git-shell 沙盒绕过漏洞(CVE-2017-8386)
git-shell是一个可以限制用户执行命令的shell,如果我们在git用户家目录下创建一个新目录,叫git-shell-commands
,然后将你允许用户执行的命令放在这个目录下,这就创建好了一个沙盒。在git-shell中,只能执行/home/git/git-shell-commands
目录下的命令。
如果系统是没有git-shell-commands
目录,那么git-shell默认只允许执行如下三个命令:
-
git-receive-pack <argument>
-
git-upload-pack <argument>
-
git-upload-archive <argument>
这就是白名单。
但CVE-2017-8386的作者发现,执行git-upload-archive --help
(或git-receive-pack --help
),将会进入一个交互式的man页面,man又调用了less命令,最后是一个可以上下翻页的帮助文档。
本来这也没什么,但是,less命令有一个特性,就是其支持一些交互式的方法。比如在less页面中,按shift
+e可以打开Examine功能,通过这个功能可以读取任意文件;输入!id
就可以执行id这个命令。
可以随便找台linux计算机试一下,执行less /etc/passwd
来到less的页面,然后在英文输入法下输入!id
,就可以执行id命令:
所以,利用这个特性,我们就可以绕过git-shell的沙盒读取任意文件,或执行任意命令了!
我们可以先试试,在Linux下直接执行git-receive-pack --help
,再输入!id
,看到的效果和上图是类似的。
通过ssh进行利用
那么,如何远程利用这个漏洞?
我们前面试了,直接ssh git@gitserver
只能拿到git-shell(或返回一段提醒文字),我们就利用上一节里提到的沙盒绕过漏洞执行命令:
ssh -p 3322 -i id_rsa -t git@127.0.0.1 "git-upload-archive '--help'"
进入帮助页面,然后按shift+e或!id
即可。
一些限制
我前文说了,一般配置git用户,不让ssh拥有shell,有两种方法:一是创建用户的时候设置其shell为/usr/bin/git-shell
,二是在authorized_keys中覆盖command。
如果目标服务器使用了第一种方法,我们即使成功执行了git-upload-archive '--help'
进入帮助页面,也不能执行命令。因为!id
还是在git-shell下执行,git-shell中没有id命令,所以依旧执行不成功。
但读取文件是一定可以的,因为读取文件不是通过命令读取的,所以不受git-shell沙盒的影响。
如果目标服务器是用第二种方法配置的git-shell,比如我这里这个测试环境,我是在/etc/passwd
文件设置git用户的shell是bash,而在authorized_keys中覆盖command,执行git-shell。
这种情况下,如果我进入了帮助页面,输入!id
是可以成功执行id命令的,因为此时id是在bash下执行的,而不是在git-shell下执行的,所以没有沙盒限制。
这个漏洞至少能做到任意文件读取,有可能可以执行任意命令。