在3月6日,@steventseeley 在twitter上发布了关于 Zoho 企业产品 Zoho ManageEngine Desktop Central 中的反序列化远程代码执行漏洞。该产品是一款基于 Web 的企业级服务器、桌面机及移动设备管理软件,可对桌面机以及移动设备管理的整个生命周期提供完全的支持,提供软件分发、补丁管理、资产管理、系统配置、远程控制、USB 外设管理、移动设备及应用管理等功能模块,帮助 IT 管理员集中远程管理大量的 PC 和 IOS/Android/Windows 移动设备。
Zoho ManageEngine Desktop Central < 10.0.474
本文使用10.0.465 x64复现分析,历史版本下载移步。
首先反序列化漏洞,肯定需要先找到反序列化的点。
查看 DesktopCentral_Server\webapps\DesktopCentral\WEB-INF\web.xml
发现了名为 CewolfServlet
的servlet
,对应的类为 DesktopCentral_Server\lib\cewolf-1.2.4.jar
中的 de.laures.cewolf.CewolfRenderer
,对应的url为/cewolf/*
CewolfRenderer
类继承 HttpServlet
是一个 servlet
,在其 doGet
方法中
imgKey
可控,然后调用 storage.getChartImage(imgKey, request)
。Storage
类是一个接口,在这个jar包中,FileStorage
类实现了 Storage
接口的 getChartImage
方法。
很明显的看到直接将之前传入的 img
当作 imgKey
参数,然后通过 getFileName()
获取文件名然后进行 ObjectInputStream
的 readObject()
,再看 getFileName()
。
进行了一个简单的拼接,无伤大雅。
捋一下,通过img传入参数触发读文件进而反序列化,现在的问题就是这个恶意的序列化文件我们怎么传上去,并且路径要有_chart
。
web.xml中寻找上传的servlet
跟进之后发现udid、filename可控,并且udid被拼接到文件保存目录中。
String localDirToStore = baseDir + File.separator + "mdm-logs" + File.separator + this.customerID + File.separator + this.deviceName + "_" + udid;
那么我们可以跨目录上传,在上文中我们传入文件名触发反序列化时会拼接 this.basePath + "_chart" + id
到路径中,所以我们需要构造一个 _chart
的路径 aaa\..\..\..\webapps\DesktopCentral\_chart
。
再来看对文件名的处理
然后文件名转小写之后进行了 FileUploadUtil.hasVulnerabilityInFileName(fileName, "log|txt|zip|7z")
的校验,然后拼接为完整的文件路径,看下校验了什么。
然后进行 isContainDirectoryTraversal()
、 isCompletePath()
、 isValidFileExtension()
的校验。
private static boolean isContainDirectoryTraversal(String fileName) { return fileName.contains("/") || fileName.contains("\\"); } private static boolean isCompletePath(String fileName) { String regexFileExtensionPattern = "([a-zA-Z]:[\\ \\\\ / //].*)"; Pattern pattern = Pattern.compile(regexFileExtensionPattern); Matcher matcher = pattern.matcher(fileName); return matcher.matches(); } private static boolean isContainExecutableFileExt(String fileName) { if (fileName.indexOf("\u0000") != -1) { fileName = fileName.substring(0, fileName.indexOf("\u0000")); } String fileExtension = FilenameUtils.getExtension(fileName).trim(); if (!fileExtension.trim().equals("")) { fileExtension = fileExtension.toLowerCase(); ArrayList executableFileExts = new ArrayList(Arrays.asList("jsp", "js", "html", "htm", "shtml", "shtm", "hta", "asp")); if (executableFileExts.contains(fileExtension)) { return true; } } return false; }
判断是否文件名进行了目录穿越、是否是合法后缀等,但是因为之前的目录是由udid控制的,并不影响我们的文件上传。而在web.xml中引入了security-mdm-agent.xml
在 security-mdm-agent.xml
中有一个校验,只允许文件名为 logger.txt|logger.zip|mdmlogs.zip|managedprofile_mdmlogs.zip
所以构造如下请求,即可上传文件
DesktopCentral_Server\lib
中有 commons-collections.jar(3.1)
、commons-beanutils-1.8.0.jar
,完美。使用ysoserial生成序列化文件,先上传然后触发反序列化就完事了。注意ysoserial的pom.xml要和目标的jar版本一样。
截至2020/03/20 9.34分,官网版本为10.0.515,已经修复了漏洞,请更新。
文笔垃圾,措辞轻浮,内容浅显,操作生疏。不足之处欢迎大师傅们指点和纠正,感激不尽。