CVE-2020-10189 Zoho ManageEngine Desktop Central反序列化RCE

警告
本文最后更新于 2020-03-21,文中内容可能已过时。

跟着清水川崎师傅学习.

在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 发现了名为 CewolfServletservlet,对应的类为 DesktopCentral_Server\lib\cewolf-1.2.4.jar 中的 de.laures.cewolf.CewolfRenderer,对应的url为/cewolf/*

https://y4er.com/img/uploads/20200321182965.png

https://y4er.com/img/uploads/20200321185502.png

CewolfRenderer 类继承 HttpServlet 是一个 servlet,在其 doGet 方法中

https://y4er.com/img/uploads/20200321182003.png

imgKey 可控,然后调用 storage.getChartImage(imgKey, request)Storage 类是一个接口,在这个jar包中,FileStorage 类实现了 Storage 接口的 getChartImage 方法。

https://y4er.com/img/uploads/20200321181041.png

很明显的看到直接将之前传入的 img 当作 imgKey 参数,然后通过 getFileName() 获取文件名然后进行 ObjectInputStreamreadObject(),再看 getFileName()

https://y4er.com/img/uploads/20200321183565.png

进行了一个简单的拼接,无伤大雅。

捋一下,通过img传入参数触发读文件进而反序列化,现在的问题就是这个恶意的序列化文件我们怎么传上去,并且路径要有_chart

web.xml中寻找上传的servlet

https://y4er.com/img/uploads/20200321186974.png

跟进之后发现udid、filename可控,并且udid被拼接到文件保存目录中。

https://y4er.com/img/uploads/20200321185491.png

1
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

再来看对文件名的处理

https://y4er.com/img/uploads/20200321186665.png

然后文件名转小写之后进行了 FileUploadUtil.hasVulnerabilityInFileName(fileName, "log|txt|zip|7z") 的校验,然后拼接为完整的文件路径,看下校验了什么。

https://y4er.com/img/uploads/20200321184618.png

然后进行 isContainDirectoryTraversal()isCompletePath()isValidFileExtension() 的校验。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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

https://y4er.com/img/uploads/20200321187536.png

security-mdm-agent.xml 中有一个校验,只允许文件名为 logger.txt|logger.zip|mdmlogs.zip|managedprofile_mdmlogs.zip

https://y4er.com/img/uploads/20200321183022.png

所以构造如下请求,即可上传文件

https://y4er.com/img/uploads/20200321181636.png

DesktopCentral_Server\lib 中有 commons-collections.jar(3.1)commons-beanutils-1.8.0.jar,完美。使用ysoserial生成序列化文件,先上传然后触发反序列化就完事了。注意ysoserial的pom.xml要和目标的jar版本一样。

https://y4er.com/img/uploads/20200321181885.png

截至2020/03/20 9.34分,官网版本为10.0.515,已经修复了漏洞,请更新。

  1. https://srcincite.io/pocs/src-2020-0011.py.txt
  2. https://www.anquanke.com/post/id/200474
  3. https://www.manageengine.com/products/desktop-central/remote-code-execution-vulnerability.html

文笔垃圾,措辞轻浮,内容浅显,操作生疏。不足之处欢迎大师傅们指点和纠正,感激不尽。