S2-066漏洞分析與復現(CVE-2023-50164)

Foreword

自struts2官方紕漏S2-066漏洞已經有一段時間,期間斷斷續續地寫,直到最近才完成。羞愧地回顧一下官方通告:

image.png

2023.12.9發佈,編號CVE-2023-50164,主要影響版本是 2.5.0-2.5.32 以及 6.0.0-6.3.0,描述中提到了文件上傳漏洞和目錄穿越漏洞。開始以爲這是個組合漏洞,其實不是,這是一個漏洞,看了幾篇大佬的文章,有的把它稱爲“文件上傳目錄穿越漏洞”,也有道理。

Prepare

準備工作就是搭建項目,用Tomcat跑,調試好斷點,回顧下struts2的結構。篇幅有限,這裏只貼一張struts2自身的配置文件:

image.png

struts2有衆多的Filter和Intercepter,它的配置邏輯是,除文件中定義的class、package以外,其餘全部攔截。對於S2-066,處理一個請求要經過的幾個關鍵類包括Dispatcher、Interceptor、HttpParameters以及UploadAction。使用下面的poc:

cda10716c5804ad293daf6ae5c7ed9a.png

Dispatcher

請求首先會進入著名的Dispatcher。multi參數對應的就是body數據,包含upload、fileName、contentType三個變量,無誤:

image.png

request中還有一個參數,uploadFileName=../../z127.txt,這個是污染參數,文件上傳的目的地,也是利用這個漏洞的目標。

image.png

走到這裏Dispatcher只是簡單處理一下請求然後交給Interceptor,無異常。

【----幫助網安學習,以下所有學習資料免費領!加vx:dctintin,備註 “博客園” 獲取!】

 ① 網安學習成長路徑思維導圖
 ② 60+網安經典常用工具包
 ③ 100+SRC漏洞分析報告
 ④ 150+網安攻防實戰技術電子書
 ⑤ 最權威CISSP 認證考試指南+題庫
 ⑥ 超1800頁CTF實戰技巧手冊
 ⑦ 最新網安大廠面試題合集(含答案)
 ⑧ APP客戶端安全檢測指南(安卓+IOS)

FileUploadInterceptor

攔截器先是把request包裝了一下,類型是MultiPartRequestWrapper。

image.png

這裏與Dispatcher一樣,請求參數還是multi和request兩部分,也無異常。

image.png

並且遍歷只有一次 ,因爲真正的body只有一個,就是那個multi。

image.png

在遍歷過程中struts2還出現了硬編碼現象,要求文件名參數必須以FileName結尾,且拼接完成的文件名前綴就是body中的{upload}名稱,這就給exp帶來了一定限制:

image.png

此外,注意這裏的279行:

// get the name of the file from the input tag
String[] fileName = multiWrapper.getFileNames(inputName);

使用的是MultiPartRequest接口的方法,而這個接口在S2-066中是由JakartaMultiPartRequest實現。使用下面這個poc進行目錄穿越並斷點檢測一下:

image.png

發現目錄穿越失敗,文件沒有放在指定目錄下。分析源碼:

image.png

參數覆蓋原本想用../../z126.txt,方法的輸入參數確實也是這樣接收的,但在這個方法中struts2會對文件名進行截斷,最終輸出的文件名會變爲 z126.txt,文件也就不會出現目錄穿越的現象。因此目錄穿越不是發生在這裏,讓struts2自己背這個鍋多少有點冤。body中的數據組裝完畢是下面這樣,size等於3,依舊無誤:

image.png

HttpParameters

來到HttpParameters查看接收的參數,還是upload、contentType、fileName三個:

image.png

但是參數接收完後就不正常了,除了原本的UploadFileName(注意首字母是大寫),還多了一個uploadFileName(注意首字母是小寫),size也變成了4。這就是Struts2官方所解釋的大小寫敏感,即對大寫的Upload和小寫的upload分別做處理。從這裏開始,S2-066才露出真正面目:

image.png

HttpParameters實現了Map接口,所以本質上它還是一個map,這也是組裝參數最常用的方式。但不管是HashMap還是TreeMap,自己不會出現覆蓋的問題。用一個小實驗證明:

image.png

走到這裏,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:

image.png

而setUploadFileName第一遍是z106.txt:

image.png

第二遍是../../z127.txt:

image-20240319143952102

實例化完成後,uploadFileName屬性已被覆蓋:

image.png

查看物理路徑,上傳成功:

image.png

POCs

參數不是filename結尾,失敗:

5e69d76ba4a0c6e60e5fd410a53f9a1.png

參數不符合FileName大小寫要求,失敗:

674bb93cd91ae101fbb3cf77c13629c.png

大寫覆蓋小寫失敗:

ab7ee0ad28107ef1a8569beca2091a2.png

大寫覆蓋大寫失敗:

31b60ab46f1b93332c0cd5ecc3ce11f.png

小寫覆蓋小寫失敗:

9a5feb70097b8fd64c922676ab5cc17.png

小寫覆蓋大寫成功,文章開頭所用。另外覆蓋也可以放在body中:

61f40e5da8a7488a8156c1e8897df3f.png

驗證:

8da6d33b7bf1dc08e644433d86e0dde.png

利用條件多少有點苛刻,但殺傷力不輸struts2過去那一堆,CVSS3.0評分9.8,CRITICAL。

capture_20240114164504492.bmp

更多網安技能的在線實操練習,請點擊這裏>>

  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章