http://p4.qhimg.com/t01f07e42485fb74a1f.png



git-shell在git远程会话之上引入了ssh隧道,是一种受限的shell。其背后的基本思想就是,在ssh会话中限制能够执行的命令,使其仅仅能执行git需要的相应命令。git需要执行的命令如下 :

1
2
3
4
5
6
git-receive-pack
    Receives repository updates from the client.
git-upload-pack
    Pushes repository updates to the client.
git-upload-archive
    Pushes a repository archive to the client.

除了上面这几个自带命令,管理员也可以通过shell脚本文件或者其他可执行文件来提供自定义命令。由于这些自定义的都是完全自定义的,因此此处主要讨论自带的命令。

如果你熟悉git,那你可能知道大部分服务器都会将git协议封装在SSH、HTTP/S[3]协议中。这是因为,git协议是基于简单文本的协议[4],在数据传输时并不提供任何认证或者保护机制。通常的做法是利用SSH协议实现repository写权限的控制,因为SSH协议本身提供多种认证机制、可靠的加密、低的协议额外开销。

使用SSH的缺点是,期初SSH是为了远程用户提供Shell访问。而通常情况下,git用户是不具备shell访问能力的。为了限制连接,使其仅仅能够访问repository,我们需要将原始shell(典型的就是bash shell,或者类似的)替换为更受限的shell。大型主机厂商通常都自己实现上面git命令的功能。但是也能使用git开发者提供的shell(该shell限制为仅仅允许与调用执行白名单中的命令)。

搭建过程很简单。比较建议在服务器上服务器上创建一个特定用户,并 使用git-shell命令作为

该用户的login shell[5]。另一种方式是,使用SSH force命令,是你能够对每一个客户端进行限制(依赖于登录过程中使用的key),后面还会介绍其他 方式。

如果在本地repository中设置好了可远程访问的repository,git push命令本质上会执行下面的命令:

1
2
3
4
ssh git@remoteserver “git-receive-pack ‘/myrepository.git'”
 008957d650a081a34bcbacdcdb5a94bddb506adfe8e0 refs/heads/develop report-status delete-refs side-band-64k quiet ofs-delta agent=git/2.1.4
 003fbe8910f121957e3326c4fdd328ab9aabd05abdb5 refs/heads/master
 00000000

如果两个repository具有同样的提交,如果执行的命令不在白名单中(不是上面列举的自带命令,也不在home目录下的git-shell-commands目录下),那么会报错提示命令无法识别。由于不是交互式shell,典型的命令注入攻击此处并不适用。相反,命令行仅仅以空格分隔开(引号包含的是整体),并被execve执行。

上面的情况,有让我更多的考虑赋值协议处理的二进制文件本身。git本身提供help命令,能针对特定命令打开帮助页面(man page),如init命令:

1
2
3
4
5
6
$ git help init
GIT-INIT(1)                    Git Manual                     GIT-INIT(1)
  
NAME
 git-init - Create an empty Git repository or reinitialize an existing one
[...]

其他的一些命令也可以通过-help参数来显示该命令对应的帮助页面,如下所示:

1
2
3
4
5
6
$ git init --help
GIT-INIT(1)                    Git Manual                     GIT-INIT(1)
  
NAME
git-init - Create an empty Git repository or reinitialize an existing one
[...]

同样,这也适用于git-receive-pack、git-upload-archive命令。在服务器上运行git-receive-pack -help命令,如下所示:

1
2
3
4
5
6
$ ssh git@remoteserver "git-receive-pack '--help'"
GIT-RECEIVE-PACK(1)            Git Manual             GIT-RECEIVE-PACK(1)
  
NAME
 git-receive-pack - Receive what is pushed into the repository
[...]

但是怎样才能绕过能够执行命令的限制呢?在大多数系统上,如果使用man命令打开帮助页面,man specification被解析、渲染,并以ANSI输出,通过管道传递给pager(通常是less命令)。这样,我们就可以滚动与搜索帮助页面,而与terminal终端的大力与容量无关。

除了作为一个简单的pager,less命令还具有额外的交互性特性。它允许你打开其他的文件并读取,输出当前输出到log文件,在当前shell下执行系统命令。要想能够利用这些特性,需要在交互式模式下运行less命令。在pty可用情况下,交互式模式可用。通常SSH连接到服务器,pty就启用了,但直接运行命令是pty不可用。幸运的是,我们可以强制ssh 客户端分配一个pty(只要服务器端没有禁用它,通常服务端也不会禁用它)。运行实例如下:

1
2
3
4
5
6
$ ssh -t git@remoteserver "git-receive-pack '--help'"
GIT-RECEIVE-PACK(1)            Git Manual             GIT-RECEIVE-PACK(1)
  
NAME
 git-receive-pack - Receive what is pushed into the repository
 Manual page git-receive-pack(1) line 1 (press h for help or q to quit)

现在我们可以使用less命令的交互特性。上面建议的建立方式有一个限制,那就是由于shell执行任然是在当前git-shell环境下,之前git-shell对ssh中能执行的命令限制同样适用于此时能执行的命令。不管怎样,我们限制可以读文件、列举目录(利用tab补全),并将当前显示结果输出到文件(如果能够控制文件部分内容,则作用更大)

http://p6.qhimg.com/t0176d54f0975c1d663.gif

如你所料,还有另一种适用git-shell的方式,虽然不是很常见。该方法适用于限制特定用户能访问repository,或者不允许改变git用户的shell的情况。

此时,我们将login shell提供给用户,并在.ssh/authorized_keys文件中指定git-shell命令来限定用户。限定用户的代码如下:

1
command="git-shell -c \"$SSH_ORIGINAL_COMMAND\"" ssh-rsa AAAAB3NzaC1yc2EA[...]

除了能执行less命令,上面的配置其他行为与配置为log shell的相同。

http://p3.qhimg.com/t01f670a9423ec898a6.gif

另外,你也可以给force命令提供额外参数来限制ssh的特性。最常见的标记就是no-pty[6],这能防止客户端请求一个pty,这样就不能在交互式模式下运行less命令。


时间线


2017-04-25 Reported to the git-security mailing list

2017-05-01 Assigned CVE-2017-8386

2017-05-10 Release of the fixed versions v2.4.12, v2.5.6, v2.6.7, v2.7.5, v2.8.5, v2.9.4, v2.10.3, v2.11.2, v2.12.3 and v2.13.0


参考


[1] https://about.gitlab.com/2017/04/05/gitlab-9-dot-0-dot-4-security-release/ 

[2] https://about.gitlab.com/2017/05/08/gitlab-9-dot-1-dot-3-security-release/ 

[3] https://git-scm.com/book/no-nb/v1/Git-on-the-Server-The-Protocols 

[4] https://github.com/git/git/blob/master/Documentation/technical/pack-protocol.txt 

[5] https://git-scm.com/book/en/v2/Git-on-the-Server-Setting-Up-the-Server 

[6] http://man.openbsd.org/sshd#command=”command” 



本文由 安全客 翻译,作者running_wen

原文链接:https://insinuator.net/2017/05/git-shell-bypass-by-abusing-less-cve-2017-8386/