Foreword
自struts2官方紕漏S2-066漏洞已經有一段時間,期間斷斷續續地寫,直到最近才完成。羞愧地回顧一下官方通告:
2023.12.9發佈,編號CVE-2023-50164,主要影響版本是 2.5.0-2.5.32 以及 6.0.0-6.3.0,描述中提到了文件上傳漏洞和目錄穿越漏洞。開始以爲這是個組合漏洞,其實不是,這是一個漏洞,看了幾篇大佬的文章,有的把它稱爲“文件上傳目錄穿越漏洞”,也有道理。
Prepare
準備工作就是搭建項目,用Tomcat跑,調試好斷點,回顧下struts2的結構。篇幅有限,這裏只貼一張struts2自身的配置文件:
struts2有衆多的Filter和Intercepter,它的配置邏輯是,除文件中定義的class、package以外,其餘全部攔截。對於S2-066,處理一個請求要經過的幾個關鍵類包括Dispatcher、Interceptor、HttpParameters以及UploadAction。使用下面的poc:
Dispatcher
請求首先會進入著名的Dispatcher。multi參數對應的就是body數據,包含upload、fileName、contentType三個變量,無誤:
request中還有一個參數,uploadFileName=../../z127.txt,這個是污染參數,文件上傳的目的地,也是利用這個漏洞的目標。
走到這裏Dispatcher只是簡單處理一下請求然後交給Interceptor,無異常。
【----幫助網安學習,以下所有學習資料免費領!加vx:dctintin,備註 “博客園” 獲取!】
① 網安學習成長路徑思維導圖
② 60+網安經典常用工具包
③ 100+SRC漏洞分析報告
④ 150+網安攻防實戰技術電子書
⑤ 最權威CISSP 認證考試指南+題庫
⑥ 超1800頁CTF實戰技巧手冊
⑦ 最新網安大廠面試題合集(含答案)
⑧ APP客戶端安全檢測指南(安卓+IOS)
FileUploadInterceptor
攔截器先是把request包裝了一下,類型是MultiPartRequestWrapper。
這裏與Dispatcher一樣,請求參數還是multi和request兩部分,也無異常。
並且遍歷只有一次 ,因爲真正的body只有一個,就是那個multi。
在遍歷過程中struts2還出現了硬編碼現象,要求文件名參數必須以FileName結尾,且拼接完成的文件名前綴就是body中的{upload}名稱,這就給exp帶來了一定限制:
此外,注意這裏的279行:
// get the name of the file from the input tag
String[] fileName = multiWrapper.getFileNames(inputName);
使用的是MultiPartRequest接口的方法,而這個接口在S2-066中是由JakartaMultiPartRequest實現。使用下面這個poc進行目錄穿越並斷點檢測一下:
發現目錄穿越失敗,文件沒有放在指定目錄下。分析源碼:
參數覆蓋原本想用../../z126.txt,方法的輸入參數確實也是這樣接收的,但在這個方法中struts2會對文件名進行截斷,最終輸出的文件名會變爲 z126.txt,文件也就不會出現目錄穿越的現象。因此目錄穿越不是發生在這裏,讓struts2自己背這個鍋多少有點冤。body中的數據組裝完畢是下面這樣,size等於3,依舊無誤:
HttpParameters
來到HttpParameters查看接收的參數,還是upload、contentType、fileName三個:
但是參數接收完後就不正常了,除了原本的UploadFileName(注意首字母是大寫),還多了一個uploadFileName(注意首字母是小寫),size也變成了4。這就是Struts2官方所解釋的大小寫敏感,即對大寫的Upload和小寫的upload分別做處理。從這裏開始,S2-066才露出真正面目:
HttpParameters實現了Map接口,所以本質上它還是一個map,這也是組裝參數最常用的方式。但不管是HashMap還是TreeMap,自己不會出現覆蓋的問題。用一個小實驗證明:
走到這裏,HttpParameters對參數的處理開始出現異常,但依然沒有發生覆蓋。
UploadAction
終於到Action了。引用一段struts2官方的描述:
An attacker can manipulate file upload params to enable paths traversal and under some circumstances this can lead to uploading a malicious file which can be used to perform Remote Code Execution.
通過操控上傳參數,黑客能夠出發目錄穿越漏洞,這樣一來,在某些情況下可以上傳惡意文件,從而進行RCE。換種說法,S2-066是框架自身、軟件工程師、Java反射機制共同作用的結果。走到這裏,爲了簡化代碼,UploadAction即是Action又是Entity。而在Entity的實例化過程中,必然是通過setXX屬性來賦值。所以就有了setUploadFileName(注意首字母大寫)和setuploadFileName(注意首字母小寫)的需求 。而在Entity的setter與getter中,這兩種需求都會被當做一種,即setUploadFileName,因此覆蓋也就發生了。正常情況下實例化方法只走一遍,如contentType:
而setUploadFileName第一遍是z106.txt:
第二遍是../../z127.txt:
實例化完成後,uploadFileName屬性已被覆蓋:
查看物理路徑,上傳成功:
POCs
參數不是filename結尾,失敗:
參數不符合FileName大小寫要求,失敗:
大寫覆蓋小寫失敗:
大寫覆蓋大寫失敗:
小寫覆蓋小寫失敗:
小寫覆蓋大寫成功,文章開頭所用。另外覆蓋也可以放在body中:
驗證:
利用條件多少有點苛刻,但殺傷力不輸struts2過去那一堆,CVSS3.0評分9.8,CRITICAL。
更多網安技能的在線實操練習,請點擊這裏>>