成功獲取WinRAR 19年曆史程式碼執行漏洞
在本文中,我們講述瞭如何使用WinAFL模糊測試工具找到WinRAR中的邏輯錯誤,並利用它來完全控制失陷主機的故事。該漏洞僅通過提取精心構造的存檔檔案即可成功利用,使超過5億使用者的主機面臨風險。這個漏洞存在已達19年之久!並迫使WinRAR完全放棄對易受攻擊格式的支援。
背景
幾個月前,我們的團隊構建了一個多處理器模糊測試實驗室,並開始使用 WinAFL 模糊器對Windows環境下的二進位制檔案進行模糊測試。在收穫了 Adobe 的模糊測試研究成果 後,我們決定擴充套件我們的模糊測試工作,針對WinRAR進行模糊測試。
模糊測試過程產生的一個Crash指引我們發現了一個WinRAR使用的2006年編譯的,沒有保護機制(如ASLR,DEP等)的過時的動態連結庫。
我們將焦點和模糊測試的主要目標轉向這個“容易上手”的dll,找到了一個記憶體損壞錯誤,併成功引發遠端程式碼執行。
然而,模糊器產生了一個具有“怪異”行為的測試用例。在研究了這種行為之後,我們發現了一個邏輯錯誤:絕對路徑遍歷漏洞。從這一點開始,利用這個漏洞完成遠端程式碼執行變得非常簡單。
也許還值得一提的是,這類漏洞在Bug Bounty計劃中,有巨大的獎金份額。
什麼是WinRAR?
WinRAR是Windows的件歸檔應用程式,可以建立和檢視RAR或ZIP檔案格式的歸檔,並解壓縮大量歸檔檔案格式。
據 WinRAR網站 稱,全球超過5億WinRAR使用者,這就使其成為當今世界上最受歡迎的壓縮工具。
這就是GUI的樣子:
模糊過程背景
這些是開始模糊WinRAR所採取的步驟:
- 在WinRAR主函式內部構造harness,使我們能夠模糊任何存檔型別而無需為每種格式構造相應的harness。這是通過給WinRAR可執行檔案打補丁來完成的。
- 去除使用者互動的對話方塊和GUI等元素,這也可以通過修補WinRAR可執行檔案來完成。
即使在WinRAR的CLI模式下,也會彈出一些訊息框。 - 使用奧盧大學2005年左右進行的一項有趣研究釋出的 巨型語料庫 。
- 在WinRAR命令列模式下使用WinAFL對程式進行模糊處理。通過這樣強制WINRAR解析“已損壞的存檔”並設定預設密碼(“-p”表示密碼,“ – kb”表示保留損壞的解壓縮檔案)。這些引數和選項可以在WinRAR幫助手冊中找到。
在短時間的模糊測試之後,我們發現了幾個存檔格式的崩潰,例如RAR,LZH和ACE,這些存檔格式會導致記憶體損壞,例如Out-of-Bounds Write。但是,利用這些漏洞並非易事,因為原語提供了對覆蓋緩衝區的有限控制。
然而,解析ACE格式時的崩潰引起了我們的注意。我們發現WinRAR使用名為unacev2.dll的DLL來解析ACE歸檔檔案。快速瀏覽一下這個dll就會發現它是2006年沒有保護機制的舊版dll。事實證明,漏洞利用的時候真的不需要繞過保護。
構建一個特定的Harness
由於這個dll看起來容易利用,所以我們專注它的模糊測試過程。
另外,就WinRAR而言,只要歸檔檔案具有.rar副檔名,它就會根據檔案的Magic位元組處理它,在我們的示例中,是ACE格式。
為了提高模糊器效能,並僅增加相關dll的程式碼覆蓋,我們為unacev2.dll建立了一個特定的Harness。
為此,我們需要了解如何使用unacev2.dll。逆向呼叫unacev2.dll進行ACE歸檔提取的程式碼後,我們發現應按以下順序呼叫兩個匯出函式進行歸檔檔案的提取:
- 名為ACEInitDll的初始化函式,具有以下簽名:
INT __stdcall ACEInitDll(unknown_struct_1 * struct_1);
•struct_1:指向未知結構的指標 - 名為ACEExtract的提取函式,具有以下簽名:
INT __stdcall ACEExtract(LPSTR ArchiveName,unknown_struct_2 * struct_2);
•ArchiveName:指向要提取的ace檔案的路徑的字串指標
•struct_2:指向未知結構的指標
這兩個函式都需要傳遞我們不知道的結構。我們有兩種方法可以嘗試理解未知的結構:逆向,除錯WinRAR,或嘗試查詢使用這些結構的開源專案。
第一種選擇更耗時,因此我們選擇嘗試第二種選擇。我們在github.com上找到了ACEInitDll這個匯出函式,並找到了一個名為 FarManager 的專案,該專案使用此dll幷包含未知結構的詳細標頭檔案。
注意:此專案的建立者也是WinRAR的建立者。
將標頭檔案載入到IDA後,更容易理解兩個函式(ACEInitDll和ACEExtract)之前的“未知結構”,因為IDA為每個結構成員顯示了正確的名稱和型別。
從我們在FarManager專案中找到的標題中,我們提出了以下簽名:
INT __stdcall ACEInitDll(pACEInitDllStruc DllData);
INT __stdcall ACEExtract(LPSTR ArchiveName,pACEExtractStruc Extract);
為了模仿WinRAR使用unacev2.dll的方式,我們分配了與WinRAR相同的結構成員。
我們開始模糊這個Harness,但我們沒有發現新的崩潰,並且覆蓋範圍沒有在模糊測試的前幾個小時內擴充套件。我們試圖瞭解這種限制的原因。
我們首先查詢有關ACE歸檔格式的資訊。
瞭解ACE格式
我們沒有找到該格式的RFC,但我們確實在網際網路上找到了重要資訊。
1.建立ACE存檔受專利保護。 唯一允許建立ACE存檔的軟體是 WinACE 。 該專案的最後一個版本是在2007年11月編譯的。該公司的網站自2017年8月以來一直處於關閉狀態。但是,提取ACE存檔不受專利保護。
這個 維基百科 中提到了一個名為 acefile 的純Python專案。 它最有用的功能是:
它可以提取ACE檔案。 它包含有關ACE檔案格式的簡要說明。 它有一個非常有用的功能,列印檔案格式標題和解釋。
要理解ACE檔案格式,讓我們建立一個簡單的.txt檔案(名為“simple_file.txt”),並使用WinACE對其進行壓縮。 然後,我們將使用acefile檢查ACE檔案的標頭。
simple_file.txt如下:
這些是我們在WinACE中選擇建立示例的選項:
此選項在所選的提取目錄下建立子目錄 users\nadavgr\Documents,並將simple_file.txt提取到該相對路徑。
使用headers標誌從acefile專案執行acefile.py會顯示有關存檔標頭的資訊:
結果如下:
請注意:
將上圖中檔名欄位中的每個“\\”視為單個斜槓“\”,這只是python轉義。 為清楚起見,相同的欄位在ace 檔案中的十六進位制轉儲和輸出中用相同的顏色標記。
重要領域摘要:
·hdr_crc(標記為粉紅色):
兩個CRC欄位存在於2個標頭中。如果CRC與資料不匹配,則中斷提取。這就是為什麼fuzzer沒有找到更多路徑(擴充套件其覆蓋範圍)的原因。為了“解決”這個問題,我們修補了unacev2.dll中的所有CRC 校驗。 注 – CRC是常規CRC的修改實現-32。
·檔名(以綠色標記):
檔名包含檔案的相對路徑。在提取過程中(包括檔案)建立相對路徑中指定的所有目錄。檔名的大小由十六進位制轉儲中的黑色框標記的2個位元組(小端)定義。
·廣告(標有黃色)
如果使用未註冊版本的WinACE建立存檔,則在建立ACE存檔期間,WinACE會自動新增廣告欄位。
·檔案內容:
“origsize” - 內容的大小。內容本身位於定義檔案的標題之後(“hdr_type”欄位== 1)。 “hdr_size” – 頭部大小。由十六進位制轉儲中的灰色框標記。 在第二個頭部的偏移70(0x46)處,我們可以找到我們的檔案內容:“Hello From Check Point!”
因為filename欄位包含檔案的相對路徑,所以我們對該欄位進行了一些手動修改嘗試,以檢視它是否容易受到“路徑遍歷”的影響。
例如,我們將簡單的路徑遍歷小工具“ \..\ ”新增到檔名欄位和更復雜的“路徑遍歷”技巧,但沒有成功。
在修補所有結構檢查(例如CRC驗證)之後,我們再次再次運行了模糊器。 在短時間的模糊測試之後,我們進入了主要的模糊測試目錄,發現了一些奇怪的東西。 但還是首先描述一下我們的模糊器以便於交代一些背景資訊。
模糊器
為了提高模糊器效能並防止I\O瓶頸,我們在一個使用ImDisk工具包的RAM碟符下執行模糊器。
Ram磁碟對映到驅動器R:\,資料夾樹如下所示:
檢測路徑遍歷錯誤
啟動模糊器後不久,我們在驅動器R的根目錄中找到了一個名為sourbe的新資料夾,位於一個令人驚訝的位置:
Harness被指示將測試歸檔檔案提取到“output_folders”下的子目錄。 例如,R:\ACE_FUZZER\output_folders\Slave_2 。 那麼為什麼我們在父目錄中建立了一個新資料夾呢?
在sourbe資料夾中,我們找到了一個名為REDVERSION_的檔案,其中包含以下內容:
觸發漏洞的測試用例十六進位制dump檔案如下:
請注意:
·我們對此測試用例進行了一些小的更改(例如調整CRC)以使其可以通過acefile進行解析。 ·為方便起見,欄位在十六進位制轉儲中以相同的顏色標記acefile的輸出。
這是我們在檢視十六進位制轉儲和acefile輸出時注意到的前三件事:
- 模糊器將“廣告”欄位的一部分複製到其他欄位:
·壓縮檔案的內容為“SIO”,在十六進位制轉儲中以橙色框標記。它是廣告字串“ UNREGISTERED VER SIO N ”的一部分。
·檔名欄位包含字串“RED VERSION ”,它是廣告字串“ UNREGISTE RED VERSION * ”的一部分。
- 檔名欄位中的路徑在提取過程中用作“絕對路徑”,而不是目標資料夾的相對路徑(反斜槓是驅動器的根目錄)。
- 提取檔名是“REDVERSION_¶”。似乎檔名欄位中的星號已轉換為下劃線,並且 \x14\ (0x14)值在提取檔名中表示為“¶”。檔名欄位的其他內容被忽略,因為在 \x14\ (0x14)值之後有一個空字元終止字串。
為了找到harness忽略目標資料夾的約束並在提取過程中使用檔名欄位作為絕對路徑的原因,我們根據我們的假設進行了以下嘗試。
我們的第一個假設是檔名欄位的第一個字元(’\’)觸發漏洞。不幸的是,經過快速檢查後我們發現事實並非如此。經過額外檢查後,我們得出了以下結論:
- 第一個字元應該是’/‘或‘\’。
- ‘*’應至少包含在檔名中一次;位置無關緊要。
觸發錯誤的檔名欄位示例: some folder\some_file\* .exe將被解壓縮到C: some_folder\some_file .exe,星號將轉換為下劃線(_)。
鑑於對harness的fuzzing已經成功觸發漏洞,現在是時候在WinRAR上測試我們精心設計的存檔(例如,利用檔案)檔案了。
在WinRAR上嘗試利用
乍一看,漏洞在WinRAR上按預期工作,因為sourbe目錄是在驅動器C:\的根目錄中建立的。但是,當我們進入“sourbe”資料夾(C:\sourbe)時,我們注意到檔案未建立。
這些行為引發了兩個問題:
·為什麼Harness和WinRAR的行為不同?
·為什麼建立了漏洞利用檔案中指定的目錄,而未建立提取的檔案?
為什麼Harness和WinRAR的行為不同?
我們預計漏洞利用檔案在WinRAR上的行為與在我們的Harness中表現的行為相同,原因如下:
1.dll(unacev2.dll)將檔案提取到目標資料夾,而不是外部可執行檔案(WinRAR或我們的Harness)。 2.當將引數/結構成員傳遞給dll時,我們的Harness完美地模仿WinRAR。
更深入的觀察表明我們在第二點中的假設是錯誤的。我們的執行緒定義了4個回撥指標,我們實現的回撥與WinRAR的回撥不同。讓我們回到我們的Harness實現。
我們在呼叫名為ACEInitDll的匯出函式時提到了這個簽名。
INT __stdcall ACEInitDll(pACEInitDllStruc DllData);
pACEInitDllStruc是指向sACEInitDLLStruc結構的指標。該結構的第一個成員是tACEGlobalDataStruc。此結構有許多成員,包括具有以下簽名的回撥函式的指標:
INT(__stdcall * InfoCallbackProc)(pACEInfoCallbackProcStruc Info);
INT(__stdcall * ErrorCallbackProc)(pACEErrorCallbackProcStruc Error);
INT(__stdcall * RequestCallbackProc)(pACERequestCallbackProcStruc Request);
INT(__stdcall * StateCallbackProc)(pACEStateCallbackProcStruc State);
這些回撥在提取過程中由dll(unacev2.dll)呼叫。
這些回撥函式被用來作為即將發生的操作例如建立檔案,建立目錄,覆蓋檔案等的驗證機制。
外部回撥/驗證器獲取有關即將發生的操作的資訊,例如檔案提取,並將其結果返回給dll。
如果允許該操作,則將 ACE_CALLBACK_RETURN_OK 常量返回給dll。否則,如果回撥函式不允許該操作,則返回以下常量: ACE_CALLBACK_RETURN_CANCEL ,同時終止操作。
有關這些回撥函式的更多資訊,請參閱 FarManager 中的 說明 。
在我們構造的Harness中,除ErrorCallbackProc返回了ACE_CALLBACK_RETURN_CANCEL之外,所有回撥函式返回了ACE_CALLBACK_RETURN_OK。
這就說明,WinRAR對提取的檔名進行了驗證(在它們被提取和建立之後),並且由於WinRAR回撥中的那些驗證結果,終止了檔案建立。這意味著在建立檔案後,WinRAR會刪除它。
WinRAR驗證器/回撥
這是阻止檔案建立的WinRAR回撥驗證器虛擬碼的一部分:
“SourceFileName”表示將提取的檔案的相對路徑。
該功能執行以下檢查:
- 第一個字元不等於“\”或“/”。
- 檔名不以以下字串“..\ ”或“../”開頭,它們是“路徑遍歷”的小工具。
-
字串中不存在以下“路徑遍歷”小工具:
1.“\..\” 2.“\../” 3.“/../” 4.“/ ..\”
unacv2.dll中的提取函式呼叫WinRAR中的StateCallbackProc,並將ACE格式的檔名欄位作為要提取的相對路徑傳遞。
相對路徑是由WinRAR的回撥/驗證機器檢查的。驗證器將ACE_CALLBACK_RETURN_CANCEL返回到dll,(因為檔名欄位以反斜槓“\”開頭)並且檔案建立被終止。
以下字串傳遞給WinRAR回撥的驗證器:
“\sourbe\RED VERSION_”
注意:這是帶有欄位“\sourbe\RED VERSION ¶”的原始檔名。 “unacev2.dll”用下劃線替換“ ”。
為什麼漏洞利用檔案中指定的資料夾被建立,而解壓縮的檔案沒有被建立?
由於dll中存在錯誤(“unacev2.dll”),即使從回撥中返回ACE_CALLBACK_RETURN_CANCEL,也會由dll建立相對路徑(ACE歸檔中的檔名欄位)中指定的資料夾。
原因是unacev2.dll在建立資料夾之前呼叫外部驗證器(回撥),但是在建立資料夾之後它會過早地檢查回撥的返回值。因此,在呼叫WriteFile API之前,它會在將內容寫入提取的檔案之前終止提取操作。
它實際上建立了待提取檔案卻沒有向檔案內寫入內容。它呼叫CreateFile API
然後檢查回撥函式的返回值。如果返回值是ACE_CALLBACK_RETURN_CANCEL,就會會刪除先前通過呼叫CreateFile API建立的檔案。
附註:
我們找到了繞過刪除檔案的方法,但它只允許我們建立空檔案。我們可以通過在檔案的末尾新增“:”來繞過檔案刪除,該檔案被視為備用資料流。如果回撥返回ACE_CALLBACK_RETURN_CANCEL,那麼dll會嘗試刪除檔案的備用資料流而不是檔案本身。 如果相對路徑字串以“”(斜槓)開頭,那麼dll程式碼中還有另一個過濾函式會終止提取操作。這種操作發生在第一個提取階段,呼叫其他過濾器函式之前。 但是,通過將“*”或“?”字元(萬用字元)新增到壓縮檔案的相對路徑(檔名欄位),就可以跳過這個驗證,同時,程式碼流可以繼續並(部分)觸發目錄遍歷漏洞。這就是模糊器生成的漏洞利用檔案觸發了我們harness中的漏洞的原因。由於WinRAR程式碼中的回撥驗證器,它不會觸發WinRAR中的漏洞。
中級調查結果摘要
·我們在unacev2.dll中發現了一個目錄遍歷漏洞。它使我們的Harness能夠將檔案提取到任意路徑,完全忽略目標資料夾,並將提取的檔案相對路徑視為完整路徑。
·這個目錄遍歷漏洞(在前面的部分中總結):
1.第一個字元應該是’/‘或‘\’。
2.’*‘應至少包含在檔名中一次。位置無關緊要。
·WinRAR部分容易受到Path Traversal的攻擊:
從WinRAR回撥(ACE_CALLBACK_RETURN_CANCEL)獲取終止程式碼後,unacev2.dll不會終止操作。由於延遲檢查WinRAR回撥的返回程式碼,因此會建立漏洞利用檔案中指定的目錄。 提取的檔案也是在exploit檔案中指定的完整路徑上建立的(沒有內容),但在從回撥中檢查返回的程式碼(在呼叫WriteFile API之前)之後立即刪除它。 我們找到了繞過刪除檔案的方法,但它允許我們只建立空檔案。
找到根本原因
此時,我們想弄清楚為什麼忽略目標資料夾,並將歸檔檔案的相對路徑(檔名欄位)視為完整路徑。
為了實現這個目標,我們可以使用靜態分析和除錯,但我們決定使用更快的方法。我們使用 DynamoRio 來記錄常規ACE檔案的unacev2.dll中的程式碼覆蓋率以及觸發該錯誤的漏洞利用檔案。然後我們使用 Lighthouse 外掛進行覆蓋率計算,並從另一箇中減去一個覆蓋路徑。
這些是我們得到的結果:
在“Coverage Overview”視窗中,我們可以看到一個獨立的結果。 這意味著在第一次嘗試中僅執行了一個基本塊(在A中標記),在第二次嘗試時未到達(在B中標記)。
Lighthouse外掛用藍色標記了變焦基本塊的背景,如下圖所示。
從程式碼覆蓋率結果中,您可以理解漏洞利用檔案不是通過分支的基本塊(標記為藍色),而是採用相反的基本塊(錯誤條件,用紅色箭頭標記)。
如果程式碼流經過錯誤條件(紅色箭頭),那綠色框內的程式碼就會用“”(空字串)替換目標資料夾,稍後呼叫sprintf函式,該函式將目標資料夾連線到相對路徑提取的檔案。
程式碼流向真假條件,分別用綠色和紅色箭頭標記,
受到對名為GetDevicePathLen的函式的呼叫的影響(在紅框內)。
如果呼叫GetDevicePathLen的結果等於0,則sprintf如下所示:
sprintf(final_file_path,“%s%s”,destination_folder,file_relative_path);
反之,sprintf結果如下
sprintf(final_file_path,“%s%s”,“”,file_relative_path);
最後一個sprintf是觸發目錄遍歷漏洞的錯誤程式碼。
這意味著相對路徑實際上將被視為應寫入/建立的檔案/目錄的完整路徑。
讓我們看一下 GetDevicePathLen 函式,以便更好地理解根本原因:
提取檔案的相對路徑將傳遞給GetDevicePathLen。
它會檢查裝置或驅動器名稱字首是否出現在Path引數中,並返回該字串的長度,如下所示:
·該函式為C:\some_folder\some_file.ext這個路徑返回3
·該函式為\some_folder\some_file.ext這個路徑返回1
·該函式\\LOCALHOST\C $\some_folder\some_file.ext這個路徑返回15
·該函式為\\? \Harddisk0Volume1\some_folder\some_file.ext這個路徑返回21
·該函式為some_folder\some_file.ext這個路徑返回0
如果GetDevicePathLen的返回值大於0,則提取檔案的相對路徑將被視為完整路徑,因為在呼叫sprintf期間目標資料夾被空字串替換,這會觸發目錄遍歷漏洞。
但是,通過省略在呼叫GetDevicePathLen之前不允許的任何序列,有一個“清除”提取檔案的相對路徑的函式。
這是一個清除路徑“CleanPath”的虛擬碼。
該函式省略了簡單的目錄遍歷序列,如“ .. ”(如果它在路徑的開頭找到 “..”序列,它會只省略它)序列,它省略了驅動器號序列,如:“C:\” ,“C:”,並且由於未知原因,“C:\C:”也是如此。
請注意,它不關心第一個字母;以下序列也將被省略:“_:\”, “_:”, “_:\_:”(在這種情況下,下劃線表示任何值)。
整合
要建立導致WinRAR將歸檔檔案解壓縮到任意路徑(目錄遍歷漏洞)的漏洞利用檔案,請解壓縮到startup資料夾(在重新啟動後獲取程式碼執行)而不是目標資料夾。
我們應該繞過兩個過濾函式來觸發bug。
要觸發空字串與壓縮檔案的相對路徑的串聯,而不是目標資料夾:
sprintf(final_file_path,“%s%s”,“”,file_relative_path);
代替:
sprintf(final_file_path,“%s%s”,destination_folder,file_relative_path);
GetDevicePathLen函式的結果應大於0。
它取決於相對路徑的內容(“file_relative_path”)。如果相對路徑如下方式啟動裝置路徑:
選項1:C:\some_folder\some_file.ext 選項2:some_folder\some_file.ext(第一個斜槓代表當前驅動器。)
GetDevicePathLen的返回值將大於0。
但是,unacev2.dll中有一個名為CleanPath的過濾器函式(圖17),它會檢查相對路徑是否以C:開頭,並在呼叫GetDevicePathLen之前將其從相對路徑字串中刪除。
它省略了選項1字串中的“C:”序列,但沒有從選項2字串中省略“”序列。
為了克服這個限制,我們可以在選項1中新增另一個“C:”序列,它將被CleanPath省略(圖17),並按照我們想要的一個“C:”保留字串的相對路徑,如:
選項1':C:\C:\some_folder\some_file.ext => C:\some_folder\some_file.ext
但是,WinRAR程式碼中有一個回撥函式(圖13),它是驗證器/過濾器函式。在提取過程中,unacev2.dll被呼叫到駐留在WinRAR程式碼的回撥函式當中。
回撥函式驗證壓縮檔案的相對路徑。如果找到黑名單序列,則將終止提取操作。
回撥函式進行的一項檢查是以“”(斜槓)開頭的相對路徑。
但它沒有檢查“C:”。因此,我們可以使用選項1’來 利用目錄遍歷漏洞 !
我們還發現了一個 SMB攻擊向量 ,它可以連線到任意IP地址,並在SMB伺服器上的任意路徑中建立檔案和資料夾。
例:
C:\\\10.10.10.10\smb_folder_name\some_folder\some_file.ext => \\10.10.10.10\smb_folder_name\some_folder\some_file.ext
簡單漏洞利用檔案的示例
我們將.ace副檔名更改為.rar副檔名,因為WinRAR會根據檔案內容檢測格式,而不是副檔名。
這是acefile的輸出:
我們通過檔名欄位中精心構造的字串(綠色)觸發漏洞。
無論目標資料夾的路徑是什麼,此存檔都將解壓縮到C:\some_folder\some_file.txt。
構造真正的漏洞利用
我們可以通過從ACE存檔中提取壓縮的可執行檔案到其中一個啟動資料夾來獲得程式碼執行。駐留在Startup資料夾中的任何檔案都將在引導時執行。
製作一個將其壓縮檔案提取到Startup資料夾的ACE存檔似乎很簡單,但事實並非如此。
以下路徑中至少有2個Startup資料夾:
C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp
C:\Users\<使用者名稱>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
第一個Startup資料夾的路徑需要高許可權/高完整性級別(如果啟用了UAC)。但是,WinRAR預設以中等完整性級別執行。
Startup資料夾的第二個路徑要求知道使用者的名稱。
我們可以嘗試通過建立包含數千個精心設計的壓縮檔案的ACE存檔來克服這個問題:所有的檔案都包含Startup資料夾的路徑,但具有不同的 <使用者名稱> 。以此來寄希望於檔案可以在我們的目標中工作。
最強攻擊向量
我們找到了一個向量,它允許我們將檔案提取到Startup資料夾,而無需關心<使用者名稱>。
通過在ACE存檔中使用以下檔名欄位:
C:\C:C:../ AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\some_file.exe
它由CleanPath函式轉換為以下路徑(圖17):
C:../ AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\some_file.exe
因為CleanPath函式刪除了“C:\C:”序列。
此外,此目標資料夾將被忽略,因為GetDevicePathLen函式(圖16)將為最後一個“C:”序列返回2。
讓我們分析最後的路徑:
序列“C:”由Windows翻譯為正在執行的程序的“當前目錄”。在我們的例子中,它是WinRAR的當前路徑。
如果從其資料夾執行WinRAR,則“當前目錄”將是此WinRAR資料夾:C:\Program Files\WinRAR
但是,如果通過雙擊存檔檔案或右鍵單擊存檔檔案中的“extract”來執行WinRAR,則WinRAR的“當前目錄”將成為存檔所在資料夾的路徑。
例如,如果存檔位於使用者的“下載”資料夾中,則WinRAR的“當前目錄”將為:
C:\Users\ <使用者名稱>\ Downloads
如果存檔位於Desktop資料夾中,則“當前目錄”路徑將為:
C:\Users\ <使用者名稱>\ Desktop
要從Desktop或Downloads資料夾到Startup資料夾,我們應該將一個資料夾“../”返回到“使用者資料夾”,並連線到啟動目錄的相對路徑:AppData\Roaming\Microsoft\Windows\Start選單程式啟動按以下順序:“C:../”
所以最終結果為:C:../ AppData\Roaming\Microsoft\Windows\Start\Menu\Programs\Startup\some_file.exe
請記住,有兩個針對路徑遍歷序列的檢查:
- 在CleanPath函式中跳過這樣的序列。
- 在WinRAR的回撥函式中,會終止提取操作。
CleanPath檢查以下路徑遍歷模式:“ .. ”
WinRAR的回撥函式檢查以下模式:
“\..\” “\../” “/../” “/ ..\”
因為第一個斜槓或反斜槓不是我們的序列“C:../”的一部分,所以我們可以繞過路徑遍歷驗證。但是,我們只能回退一個資料夾。我們需要在不知道使用者名稱的情況下將檔案解壓縮到Startup資料夾。
注意:如果我們想要回退多個資料夾,我們應該連線以下序列“/../”。例如,“C:../../”,而“/../”序列將被回撥函式捕獲到,並終止檔案提取。
邊注
在我們的研究結束時,我們發現WinACE在linux環境下建立了一個類似unacev2.dll的應用程式,名字為unace-nonfree(使用Watcom編譯器編譯)。 原始碼可用。
Windows的原始碼(由unacev2.dll構建)也包含在內,但它比unacev2.dll的最新版本舊,並且無法為Windows編譯/構建。 此外,原始碼中缺少某些功能 – 例如,不包括圖17中的檢查。
但是,圖16取自原始碼。
我們還在原始碼中找到了目錄遍歷漏洞。 它看起來像這樣:
CVE編號:
CVE-2018-20250,CVE-2018-20251,CVE-2018-20252,CVE-2018-20253。
WinRAR的回覆
WinRAR決定從他們的軟體包中刪除UNACEV2.dll,而WinRAR不支援版本號為“5.70 beta 1”的ACE格式。
引自WinRAR官方的 描述 :
“Nadav Grossman from Check Point Software Technologies informed us about a security vulnerability in UNACEV2.DLL library.Aforementioned vulnerability makes possible to create files in arbitrary folders inside or outside of destination folder when unpacking ACE archives. WinRAR used this third party library to unpack ACE archives. UNACEV2.DLL had not been updated since 2005 and we do not have access to its source code. So we decided to drop ACE archive format support to protect security of WinRAR users. We are thankful to Check Point Software Technologies for reportingthis issue.“
Check Point的SandBlast Agent Behavioral Guard可以防禦這些威脅。
Check Point的IPS提供針對此威脅的保護:“RARLAB WinRAR ACE格式輸入驗證遠端執行程式碼(CVE-2018-20250)”
非常感謝我的同事Eyal Itkin( @EyalItkin )和Omri Herscovici( @omriher )對本研究的幫助。
本文譯自Check Point研究人員釋出的 Extracting a 19 Year Old Code Execution from WinRAR