CVE-2022-27925 Zimbra Collaboration 存在路徑穿越漏洞最終導(dǎo)致RCE
前段時間 Zimbra 官方通報了一個 RCE 漏洞 CVE-2022-27925 ,也有小伙伴在漏洞空間站談到了這個漏洞,上周末在家有時間完成了漏洞的分析與復(fù)現(xiàn)。漏洞原理并不復(fù)雜,但在搭建環(huán)境的過程中遇到了一些坑,下面將分析過程分享給大家。

從描述來看,這是一個 ZIP 壓縮包解析導(dǎo)致路徑穿越類型的漏洞。
由于直接安裝 v9.0.0 或 v8.8.15 默認就是最新版,因此選擇安裝 v8.8.12。安裝過程非常曲折,環(huán)境搭建有疑惑的小伙伴可以加入漏洞空間站進行交流。
最終完成安裝并啟動成功:

通過配置 `mailboxd_java_options` 加入調(diào)試信息:

重啟 Zimbra 服務(wù)即可打開遠程調(diào)試:

漏洞出現(xiàn)在 `mboximport` 相關(guān)的功能中,全盤搜索定位到位于 `zimbrabackup.jar` 中的 `MailboxImportServlet` :

從命名規(guī)則和存在的成員函數(shù) `doPost` 來看, `MailboxImportServlet` 應(yīng)該對應(yīng)一個 `Servlet` 對象,但是 `MailboxImportServlet` 繼承于 `ExtensionHttpHandler` 而非 `HttpServlet` :

所以還需要尋找某種相互之間的轉(zhuǎn)換關(guān)系。我們知道 Zimbra 自定義了 `Servlet` 對象的基類 `ZimbraServlet` ,搜索其子類:

定位 `ExtensionDispatcherServlet` :

可以找到相關(guān)配置:


所以 `ExtensionDispatcherServlet` 對應(yīng)的 URL 規(guī)則為 `/service/extension/*` ,回到 `ExtensionDispatcherServlet#service` 函數(shù):

通過 `getHandler` 函數(shù)來尋找對應(yīng)的 `ExtensionHttpHandler` 對象 `handler` (前面定位的 `MailboxImportServlet` 正好繼承于 `ExtensionHttpHandler`),進入 `getHandler` 函數(shù):

提取 URL 中 `/service/extension` 之后的字符串并賦值給 `extPath` ,帶入 `getHandler` 函數(shù):

返回的 `ExtensionHttpHandler` 對象來自于 `sHandlers` 鍵值對,其中的 `key` 來自于 `ExtensionHttpHandler#getPath` 函數(shù),查看定義:

`ExtensionHttpHandler#getPath` :


`mExtension` 為 `ZimbraExtension` 類型,并且在 `init` 函數(shù)中完成初始化,搜索 `ZimbraExtension` 子類:

定位 `BackupExtension` ,里面剛好注冊了 `MailboxImportServlet` 類型:

所以構(gòu)造特定 URL 將調(diào)用 `MailboxImportServlet` ,測試如下:

成功進入 `MailboxImportServlet#doPost` 函數(shù)處理邏輯。
下面分析一下 `doPost` 函數(shù)的處理邏輯,首先通過 `getAuthTokenFromCookie` 從 Cookie 中提取 token 認證信息,并檢查是否為管理員權(quán)限:
AuthToken authToken = ZimbraServlet.getAuthTokenFromCookie(req, resp);if (authToken == null || !authToken.isAdmin()) {Log.mboxmove.warn("Auth failed");this.sendError(resp, 403, "Auth failed");}
進入 `getAuthTokenFromCookie` :

因為這里 `isAdminReq` 默認為 `false` ,因此認證后需要攜帶 `ZM_AUTH_TOKEN` 的 Cookie 值,而非 `ZM_ADMIN_AUTH_TOKEN` :

通過權(quán)限檢查后,將會進行一系列參數(shù)提取與判斷,當(dāng)提供的 `account-name` 等參數(shù)通過驗證后,將進入第 152 行 `importFrom` 函數(shù):

其中 `in` 來自于 POST 請求數(shù)據(jù)包,進入 `importFrom` 函數(shù):

提取 ZIP 壓縮包,調(diào)用 `restore` 函數(shù):

進入 `getAccountSession` 函數(shù):

實例化 `ZipBackupTarget.RestoreAcctSession` 對象,進入構(gòu)造函數(shù):

跟進 `unzipToTempFiles` 函數(shù):

ZIP 壓縮包解壓過程存在路徑穿越漏洞,導(dǎo)致可以向任意路徑寫入 shell 。
通過上述分析,我們可以構(gòu)造一個存在路徑穿越的 ZIP 壓縮包,并發(fā)送特定 POST 請求實現(xiàn)壓縮包解壓路徑穿越:

最終寫入 shell :

