代码审计 | 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,被迷惑了许久,算是踩了一个大坑。
