代碼審計 | Zoho 從未授權訪問到遠程 RCE
ZOHO ManageEngine ServiceDesk Plus(SDP)是美國卓豪(ZOHO)公司的一套基于 ITIL 架構的 IT 軟件。該軟件集成了事件管理、問題管理、資產管理IT項目管理、采購與合同管理等功能模塊。
使用該系統的國家以國外為主,比如 fofa 的查詢結果:

下面分析一下 CVE-2021-44077 這個漏洞的成因,從未授權訪問說起。
0x01 未授權訪問
根據 Web.xml 文件可以看到 RestAPI 的請求都會交由 struts 來處理:
<servlet> <servlet-name>actionservlet-name> <servlet-class> org.apache.struts.action.ActionServlet servlet-class> <servlet-mapping> <servlet-name>actionservlet-name> <url-pattern>/RestAPI/*url-pattern> servlet-mapping>
其中還有一段配置,根據注釋可以看出來,以下的 URL 需要進行登錄認證。例如 xxx.do:
<security-constraint> <web-resource-collection> <web-resource-name>Secured Core Contextweb-resource-name> <url-pattern>*.dourl-pattern> <url-pattern>/appurl-pattern> <url-pattern>/ui/*url-pattern> <url-pattern>*.ccurl-pattern> <url-pattern>*.lsurl-pattern> <url-pattern>/SoftwareFileUploader.upurl-pattern> <url-pattern>/WOResolutionFileUploader.upurl-pattern> <url-pattern>*.jsonurl-pattern> <url-pattern>*.jspurl-pattern> <url-pattern>/servlet/*url-pattern> <url-pattern>/ze/*url-pattern> <url-pattern>/aplusintegurl-pattern> <url-pattern>/RestAPI/WC/TwoFactorActionurl-pattern> web-resource-collection> <auth-constraint> <role-name>*role-name> auth-constraint> security-constraint>
同樣配置了一份不需要進行登錄 URL:
<security-constraint> <web-resource-collection> <web-resource-name>Secured Core Contextweb-resource-name> <url-pattern>/approval/*url-pattern> <url-pattern>/purchase/ApprovalDetails.jspurl-pattern> <url-pattern>/jsp/AuthError.jspurl-pattern> <url-pattern>/AuthError.jspurl-pattern> <url-pattern>/jsp/pagenotfound.jspurl-pattern> <url-pattern>/jsp/exceptionerror.jspurl-pattern> <url-pattern>/ze/*url-pattern> <url-pattern>/servlet/HdFileDownloadServleturl-pattern> <url-pattern>/workorder/CloseWorkOrder.jspurl-pattern> <url-pattern>/PurchaseRequestFileUploader.upurl-pattern> <url-pattern>/PurchaseOrderFileUploader.upurl-pattern> <url-pattern>/workorder/SDPOutlookAddIn.jspurl-pattern> <url-pattern>/j_security_checkurl-pattern> <url-pattern>/RestAPI/TwoFactorActionurl-pattern> web-resource-collection> security-constraint>
在代碼 org.apache.catalina.realm.RealmBase#findSecurityConstraints 中用到了上面所述的配置信息。
但令人不解的情況發生了,當構造了 /RestAPI/ImportTechnicians, 這種方式并不在上述的兩個配置信息之中那么是否需要登錄呢?
根據調試會發現如下圖,在經過 findSecurityConstraints 的一頓匹配之下,由于匹配不上,最終的返回是 null。程序進入 if 語句塊,繼續執行下一個管道操作,因而 /RestAPI/ImportTechnicians 是不需要進行認證的。同理類似于 /RestAPI/xxxx 的訪問接口都不需要認證。



0x02 任意文件上傳
在 com.adventnet.servicedesk.setup.action.ImportTechniciansAction#execute 處有一個明顯的文件寫入動作,且文件內容來自于上傳表單。

根據配置文件可以構造出對應的請求,執行完畢后會在 bin 目錄下保存上傳的文件。
<action name="ImportTechnicians" path="/ImportTechnicians" scope="request" type="com.adventnet.servicedesk.setup.action.ImportTechniciansAction"> <forward name="GetInputFile" path="/setup/GetTechInputFile.jsp"/> <forward name="ImportConfirmation" path="/setup/TechImportConfirmation.jsp"/> <forward name="MapFields" path="/setup/TechMapFields.jsp"/> action>

0x03 命令執行
在 com.manageengine.s247.util.S247Util#installAgentProgress 處調用 bin 目錄下的 msiexec.exe,結合剛才的文件上傳,因此可以傳入一個名為 msiexe.exe 的文件,再調用該接口即可。

installAgentProgress 在 com.manageengine.s247.actions.S247Action#s247AgentInstallationProcess 這個 action 中得以調用。

最后把未授權和文件上傳結合起來,就可以完成一次未授權的命令執行了。

總結
在尋找未授權訪問的原因時花了一點時間,一開始以為是在 Filter 之中做的鑒權,但是排查了幾個 Filter 之后沒有發現。接著就是一步一步調試,最終發現是在 Tomcat Pipline 機制里做的鑒權。反復比對配置文件,也沒找出配置錯誤的點,因為它不僅僅配了需要認證的 URL,也配置了不需要認證的 URL,被迷惑了許久,算是踩了一個大坑。