VMware View Planner 远程代码执行漏洞复现(CVE-2021-21978)

1.漏洞原理:

VMware View Planner 的 web 上传接口中itrLogPath参数未进行严格的校验,允许攻击者实施目录穿越,将文件上传至任意目录。

在攻击者上传恶意脚本文件覆盖特定的 web 程序执行脚本时,可造成远程代码执行。

2.影响版本:

vmware:view_planner: 4.6

3.漏洞环境:

下载地址:

链接:https://pan.baidu.com/s/1DtCBw6zW1IuEzBQbKLQeuQ

提取码:rc1s

 

下载之后直接拖到虚拟机:

设置完密码后界面如下:

 

 

访问:

 

 

 

 

exp工具地址:

https://github.com/skytina/CVE-2021-21978

利用成功如下:

 

 

 访问链接查看log_upload_wsgi.py

 

 

4.漏洞分析:

对应目录:/etc/httpd/html/wsgi_log_upload/log_upload_wsgi.py

#! /usr/bin/env python3
import cgi
import os,sys
import logging
import json

WORKLOAD_LOG_ZIP_ARCHIVE_FILE_NAME = "workload_log_{}.zip"

class LogFileJson:
    """ Defines format to upload log file in harness

Arguments:
    itrLogPath : log path provided by harness to store log data
    logFileType : Type of log file defined in api.agentlogFileType
    workloadID [OPTIONAL] : workload id, if log file is workload specific

"""
    def __init__(self, itrLogPath, logFileType, workloadID = None):
        self.itrLogPath = itrLogPath
        self.logFileType = logFileType
        self.workloadID = workloadID

def to_json(self):
        return json.dumps(self.__dict__)

@classmethod
    def from_json(cls, json_str):
        json_dict = json.loads(json_str)
        return cls(**json_dict)

class agentlogFileType():
    """ Defines various log file types to be uploaded by agent

"""
    WORKLOAD_ZIP_LOG = "workloadLogsZipFile"

try:
    # TO DO: Puth path in some config
    logging.basicConfig(filename="/etc/httpd/html/logs/uploader.log",filemode='a', level=logging.ERROR)
except:
    # In case write permission is not available in log folder.
    pass

logger = logging.getLogger('log_upload_wsgi.py')

def application(environ, start_response):
    logger.debug("application called")

if environ['REQUEST_METHOD'] == 'POST':
        post = cgi.FieldStorage(
            fp=environ['wsgi.input'],
            environ=environ,
            keep_blank_values=True
        )
        # TO DO: Puth path in some config or read from config is already available
        resultBasePath = "/etc/httpd/html/vpresults"
        try:#从cgi中获取logfile和logMetaData两个参数数据
            filedata = post["logfile"]
            metaData = post["logMetaData"]

if metaData.value:#如果logMetaData参数传入了json数据,则从json数据中获取itrLogPath和logFileType两个键值,随之将itrLogPath和logFileType与resultBasePath 进行路径拼接
                logFileJson = LogFileJson.from_json(metaData.value)

if not os.path.exists(os.path.join(resultBasePath, logFileJson.itrLogPath)):#判断路径是否存在,不存在则创建,
                os.makedirs(os.path.join(resultBasePath, logFileJson.itrLogPath))

if filedata.file:#之后判断logfile是否为上传文件
                if (logFileJson.logFileType == agentlogFileType.WORKLOAD_ZIP_LOG):
                    filePath = os.path.join(resultBasePath, logFileJson.itrLogPath, WORKLOAD_LOG_ZIP_ARCHIVE_FILE_NAME.format(str(logFileJson.workloadID)))
                else:#上传了文件,如果logFileType参数的值不等于workloadLogsZipFile 则直接将resultBasePath,itrLogPath,logFileType三个参数的值进行路径拼接,并进行文件写入。
                    filePath = os.path.join(resultBasePath, logFileJson.itrLogPath, logFileJson.logFileType)

#由于缺少路径规范过滤,只需要稍微构造一下数据包即可上传恶意文件到任意路径
                with open(filePath, 'wb') as output_file:
                    while True:
                        data = filedata.file.read(1024)
                        # End of file
                        if not data:
                            break
                        output_file.write(data)

body = u" File uploaded successfully."
                start_response(
                    '200 OK',
                    [
                        ('Content-type', 'text/html; charset=utf8'),
                        ('Content-Length', str(len(body))),
                    ]
                )
                return [body.encode('utf8')]

except Exception as e:
            logger.error("Exception {}".format(str(e)))
            body = u"Exception {}".format(str(e))
    else:
        logger.error("Invalid request")
        body = u"Invalid request"

start_response(
        '400 fail',
        [
            ('Content-type', 'text/html; charset=utf8'),
            ('Content-Length', str(len(body))),
        ]
    )
    return [body.encode('utf8')]

 

 在源文件的基础上增加的命令执行的代码:

 

 

 其中上传的文件内容是log_upload_wsgi.py的源文件,但添加了执行命令的代码,在上传成功之后,再请求一次logupload端点,收到curl请求,命令执行成功。

5.修复建议:

下载补丁:https://my.vmware.com/web/vmware/downloads/details?downloadGroup=VIEW-PLAN-460&productId=1067&rPId=53394

升级到最新版本

参考链接:

https://paper.seebug.org/1495/

 

posted @ 2021-03-26 14:49  playe  阅读(652)  评论(0编辑  收藏  举报