作者:phith0n@長亭科技

原文地址:GIT-SHELL 沙盒繞過(CVE-2017-8386)

GIT-SHELL 沙盒繞過(CVE-2017-8386)導致任意文件讀取、可能的任意命令執行漏洞。

參考鏈接:

  • https://insinuator.net/2017/05/git-shell-bypass-by-abusing-less-cve-2017-8386/

  • http://docs.ioin.in/writeup/evi1cg.me/_archives_CVE_2017_8386_html/index.html

一. 測試環境

編譯及運行測試環境(地址):

docker-compose build
docker-compose up -d

為了不和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,所以其實他們是一個用戶)

二. 原理

1. 基于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服務器,可以參考這篇文章

2. 如何禁止git用戶執行系統shell

那么,github這類git服務商是怎么實現上述“安全”通信的流程的呢?

讓用戶可以通過ssh認證身份,但又不給用戶shell,這個過程有兩種方法實現:

  1. 創建系統用戶git的時候將其shell設置成git-shell
  2. 在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。

3. 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,看到的效果和上圖是類似的。

evi1cg大佬的博客中有動圖,看的更直觀。

4. 通過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即可。

5. 一些限制

我前文說了,一般配置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下執行的,所以沒有沙盒限制。

總的來說,這個漏洞至少能做到任意文件讀取,有可能可以執行任意命令。


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/309/