作者: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,這個過程有兩種方法實現:
- 創建系統用戶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。
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下執行的,所以沒有沙盒限制。
總的來說,這個漏洞至少能做到任意文件讀取,有可能可以執行任意命令。
本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/309/