魯先志
摘 要:shell軟件的bash的“破殼”漏洞從2014年被披露至今對全球上百萬臺服務(wù)器造成了非常嚴(yán)重的影響。文章首先分析了該漏洞的原理,并對該漏洞的可利用性并進(jìn)行了驗證,最后提出了修補該漏洞的方法。
關(guān)鍵詞:破殼漏洞;Shell;Bash
破殼漏洞對應(yīng)的CVE編號為CVE-2014-6271, 該漏洞是由法國的研究者最先發(fā)現(xiàn)的,此漏洞的影響范圍包括大多數(shù)應(yīng)用Bash的Unix、Linux、Mac OS X,而針對這些操作系統(tǒng)管理下的數(shù)據(jù)均存在高危威脅。“破殼”是Bash(GNU Bourne Again Shell) 中出現(xiàn)的允許攻擊者通過環(huán)境變量執(zhí)行任意命令的漏洞,該漏洞可使攻擊者在受影響的系統(tǒng)上執(zhí)行任意代碼,影響到與Bash交互的多種應(yīng)用系統(tǒng),包括Apache、OpenSSH、DHCP等。
1 漏洞原理
Shell是一個交互性命令解釋器,shell獨立于操作系統(tǒng),這種設(shè)計讓用戶可以靈活選擇適合自己的Shell。Shell可以在命令行鍵入命令,經(jīng)過shell解釋后傳送給操作系統(tǒng)(內(nèi)核)執(zhí)行。
目前的Bash使用的環(huán)境變量是通過函數(shù)名稱來調(diào)用的,導(dǎo)致漏洞出問題是以“(){”開頭定義的環(huán)境變量在命令ENV中解析成函數(shù)后,Bash執(zhí)行并未退出,而是繼續(xù)解析并執(zhí)行shell命令。而其核心的原因在于在輸入的過濾中沒有嚴(yán)格限制邊界,也沒有做出合法化的參數(shù)判斷。
在Bash解釋命令行指令時,可以通過輸入一些代碼來檢測該系統(tǒng)中是否存在出破殼漏洞:
env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
如果系統(tǒng)存出該漏洞,會出現(xiàn)下圖所示的執(zhí)行結(jié)果:
圖1 具有破殼漏洞的系統(tǒng)
上面的語句中env為一個系統(tǒng)命令,該命令讓系統(tǒng)創(chuàng)建一個環(huán)境變量x='() { :;}; echo vulnerable'并且?guī)е@個環(huán)境變量的值執(zhí)行bash-c “echo this is a test”。第一行輸出的“vulnerable”暴露了漏洞的存在,因為函數(shù)定義() { :;};之后的echo vulnerable指令本不該被執(zhí)行卻被執(zhí)行。具體原因是由于bash在處理含有函數(shù)定義諸如”() { :;};”的環(huán)境變量賦值的代碼上存在設(shè)計缺陷,錯誤地將函數(shù)定義后面的字符串作為命令執(zhí)行。實事上真正的漏洞利用與env命令無關(guān),只要設(shè)法讓系統(tǒng)接受一個含有”[函數(shù)定義]+[任意命令]”的環(huán)境變量賦值則可觸發(fā)”[任意命令]”部分所表示的代碼執(zhí)行。
2 利用破殼漏洞繞過通過授權(quán)秘鑰的OpenSSH驗證
通常情況下用戶通過SSH遠(yuǎn)程登陸系統(tǒng)是需要使用用戶名與密碼登陸,但還有一種方式是配置授權(quán)登陸密鑰(RSA算法非對稱加密),使得登陸時無需輸入用戶名與密碼,相對于用戶密碼的驗證方式,使用公鑰驗證登錄是更佳的安全方法。
SSH實現(xiàn)無密碼訪問的應(yīng)用非常廣泛的,比如在linux主機高可用的集群節(jié)點上配置SSH 實現(xiàn)節(jié)點間用戶的無密碼訪問,由于主機高可用程序需要在各節(jié)點間進(jìn)行信息傳遞,所以必須實現(xiàn)所有節(jié)點兩兩之間能無密碼訪問。節(jié)點間的無密碼訪問是通過配置ssh 公鑰認(rèn)證來實現(xiàn)的。
在很多情況,內(nèi)網(wǎng)里的SSH密鑰認(rèn)證登陸只是為了完成程序自動化登陸操作的任務(wù),比如實現(xiàn)主機高可用節(jié)點間的無密碼訪問,“SSH shelltest@serverip命令” 就可以完成任務(wù)的情況,所以為了安全起見,管理員通常會限制SSH密鑰認(rèn)證登陸后的操作權(quán)限,一般常見的限制方式是限制命令執(zhí)行,將需要執(zhí)行的命令加入白名單,限制后的SSH無法登陸shell。
通過輸入下面的命令可用成果繞過系統(tǒng)白名單執(zhí)行任意命令。
SSH username@serverip ‘() { :;}; cat /etc/passwd