Skip to content

ESC9, ESC10 and ESC16 detection for ldap_esc_vulnerable_cert_finder #20149

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 18 commits into
base: master
Choose a base branch
from

Conversation

jheysel-r7
Copy link
Contributor

@jheysel-r7 jheysel-r7 commented May 8, 2025

This PR adds detections for ESC9 and ESC10 to the ldap_esc_vulnerable_cert_finder module.
TODO: Write documentation on how to create certificate templates vulnerable to both of these misconfiguration.

Verification

List the steps needed to make sure this thing works

  1. Do: Start msfconsole
  2. Do: use auxiliary/gather/ldap_esc_vulnerable_cert_finder
  3. Do: set LDAPUsername <username>
  4. Do: set LDAPPassword <password>
  5. Do: set LDAPDomain <password>
  6. Do: set RHOSTS <target IP(s)>
  7. Optional: set RPORT <target port> if target port is non-default.
  8. Optional: set SSL true if the target port is SSL enabled.
  9. Do: run

Testing

ESC9

[+] Template: ESC9-Template
[*]   Distinguished Name: CN=ESC9-Template,CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=kerberos,DC=issue
[*]   Manager Approval: Disabled
[*]   Required Signatures: 0
[+]   Vulnerable to: ESC2, ESC4
[!]   Potentially vulnerable to: ESC9 (the template is in a vulnerable configuration but in order to exploit registry key StrongCertificateBindingEnforcement must not be set to 2)
[*]   Notes:
[*]     * ESC2: Template defines the Any Purpose OID or no EKUs (PkiExtendedKeyUsage)
[*]     * ESC4: The account: user1 has edit permissions over the template ESC9-Template making it vulnerable to ESC4
[*]     * ESC4: The account: user1 is a part of the following groups: (Authenticated Users) which have edit permissions over the template object
[*]     * ESC9: Template has msPKI-Enrollment-Flag set to 0x80000 (CT_FLAG_NO_SECURITY_EXTENSION) and specifies a client authentication EKU and user1 has write privileges over user2
[*]  Certificate Template Write-Enabled SIDs:
[*]     * S-1-5-21-2324486357-3075865580-3606784161-1602 (user1)
[*]     * S-1-5-21-2324486357-3075865580-3606784161-1603 (user2)
[*]     * S-1-5-11 (Authenticated Users)
[*]   Certificate Template Enrollment SIDs:
[*]     * S-1-5-21-2324486357-3075865580-3606784161-1602 (user1)
[*]     * S-1-5-21-2324486357-3075865580-3606784161-1603 (user2)
[*]     * S-1-5-11 (Authenticated Users)
[+]   Issuing CA: kerberos-DC2-CA (dc2.kerberos.issue)
[*]     Enrollment SIDs:
[*]       * S-1-5-11 (Authenticated Users)
[*]       * S-1-5-21-2324486357-3075865580-3606784161-519 (Enterprise Admins)
[*]       * S-1-5-21-2324486357-3075865580-3606784161-512 (Domain Admins)
[*] Auxiliary module execution completed

ESC10

[+] Template: ESC10-Template
[*]   Distinguished Name: CN=ESC10-Template,CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=kerberos,DC=issue
[*]   Manager Approval: Disabled
[*]   Required Signatures: 0
[+]   Vulnerable to: ESC2, ESC4
[!]   Potentially vulnerable to: ESC10 (the template is in a vulnerable configuration but in order to exploit registry key StrongCertificateBindingEnforcement must be set to 0 or CertificateMappingMethods must be set to 0x4)
[*]   Notes:
[*]     * ESC2: Template defines the Any Purpose OID or no EKUs (PkiExtendedKeyUsage)
[*]     * ESC4: The account: user1 has edit permissions over the template ESC10-Template making it vulnerable to ESC4
[*]     * ESC4: The account: user1 is a part of the following groups: (Authenticated Users) which have edit permissions over the template object
[*]     * ESC10: Template specifies a client authentication EKU and user1 has write privileges over user2
[*]  Certificate Template Write-Enabled SIDs:
[*]     * S-1-5-21-2324486357-3075865580-3606784161-500 (Administrator)
[*]     * S-1-5-21-2324486357-3075865580-3606784161-1602 (user1)
[*]     * S-1-5-21-2324486357-3075865580-3606784161-1603 (user2)
[*]     * S-1-5-11 (Authenticated Users)
[*]   Certificate Template Enrollment SIDs:
[*]     * S-1-5-21-2324486357-3075865580-3606784161-1602 (user1)
[*]     * S-1-5-21-2324486357-3075865580-3606784161-1603 (user2)
[*]     * S-1-5-11 (Authenticated Users)
[+]   Issuing CA: kerberos-DC2-CA (dc2.kerberos.issue)
[*]     Enrollment SIDs:
[*]       * S-1-5-11 (Authenticated Users)
[*]       * S-1-5-21-2324486357-3075865580-3606784161-519 (Enterprise Admins)
[*]       * S-1-5-21-2324486357-3075865580-3606784161-512 (Domain Admins)

ESC16

Scenario 1

[+] Template: ESC16-Template
[*]   Distinguished Name: CN=ESC16-Template,CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=kerberos,DC=issue
[*]   Manager Approval: Disabled
[*]   Required Signatures: 0
[+]   Vulnerable to: ESC4, ESC9, ESC10, ESC16
[*]   Notes:
[*]     * ESC4: The account: user1 has edit permissions over the template ESC16-Template.
[*]     * ESC9: The account: user1 has edit permission over the accounts: user1, user3, user2 which have enrollment rights for this template. Registry value: StrongCertificateBindingEnforcement=0.
[*]     * ESC10: The account: user1 has edit permission over the accounts: user1, user3, user2 which have enrollment rights for this template. Registry values: StrongCertificateBindingEnforcement=0, CertificateMappingMethods=4.
[*]     * ESC16: Template is vulnerable due StrongCertificateBindingEnforcement = 0 and the CA's disabled policy extension list includes: 1.3.6.1.4.1.311.25.2.
[*]  Certificate Template Write-Enabled SIDs:
[*]     * S-1-5-21-2324486357-3075865580-3606784161-500 (Administrator)
[*]     * S-1-5-21-2324486357-3075865580-3606784161-1602 (user1)
[*]     * S-1-5-21-2324486357-3075865580-3606784161-1603 (Misconfigured Certificate Template Finder)
[*]     * S-1-5-21-2324486357-3075865580-3606784161-1604 (user3)
[*]     * S-1-5-21-2324486357-3075865580-3606784161-1609 (user2)
[*]     * S-1-5-11 (Authenticated Users)
[*]   Certificate Template Enrollment SIDs:
[*]     * S-1-5-21-2324486357-3075865580-3606784161-1602 (user1)
[*]     * S-1-5-21-2324486357-3075865580-3606784161-1603 (Misconfigured Certificate Template Finder)
[*]     * S-1-5-21-2324486357-3075865580-3606784161-1604 (user3)
[*]     * S-1-5-21-2324486357-3075865580-3606784161-1609 (user2)
[*]     * S-1-5-11 (Authenticated Users)
[+]   Issuing CA: kerberos-DC2-CA (dc2.kerberos.issue)
[*]     Enrollment SIDs:
[*]       * S-1-5-11 (Authenticated Users)
[*]       * S-1-5-21-2324486357-3075865580-3606784161-519 (Enterprise Admins)
[*]       * S-1-5-21-2324486357-3075865580-3606784161-512 (Domain Admins)

Scenario 2

[+] Template: ESC16-Template
[*]   Distinguished Name: CN=ESC16-Template,CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=kerberos,DC=issue
[*]   Manager Approval: Disabled
[*]   Required Signatures: 0
[+]   Vulnerable to: ESC4, ESC10, ESC16
[*]   Notes:
[*]     * ESC4: The account: user1 has edit permissions over the template ESC16-Template.
[*]     * ESC10: The account: user1 has edit permission over the accounts: user1, user3, user2 which have enrollment rights for this template. Registry values: StrongCertificateBindingEnforcement=2, CertificateMappingMethods=4.
[*]     * ESC16: Template is vulnerable due to the active policy EditFlags having: EDITF_ATTRIBUTESUBJECTALTNAME2 set (which is essentially ESC6) combined with the CA's disabled policy extension list including: 1.3.6.1.4.1.311.25.2.
[*]  Certificate Template Write-Enabled SIDs:
[*]     * S-1-5-21-2324486357-3075865580-3606784161-500 (Administrator)
[*]     * S-1-5-21-2324486357-3075865580-3606784161-1602 (user1)
[*]     * S-1-5-21-2324486357-3075865580-3606784161-1603 (Misconfigured Certificate Template Finder)
[*]     * S-1-5-21-2324486357-3075865580-3606784161-1604 (user3)
[*]     * S-1-5-21-2324486357-3075865580-3606784161-1609 (user2)
[*]     * S-1-5-11 (Authenticated Users)
[*]   Certificate Template Enrollment SIDs:
[*]     * S-1-5-21-2324486357-3075865580-3606784161-1602 (user1)
[*]     * S-1-5-21-2324486357-3075865580-3606784161-1603 (Misconfigured Certificate Template Finder)
[*]     * S-1-5-21-2324486357-3075865580-3606784161-1604 (user3)
[*]     * S-1-5-21-2324486357-3075865580-3606784161-1609 (user2)
[*]     * S-1-5-11 (Authenticated Users)
[+]   Issuing CA: kerberos-DC2-CA (dc2.kerberos.issue)
[*]     Enrollment SIDs:
[*]       * S-1-5-11 (Authenticated Users)
[*]       * S-1-5-21-2324486357-3075865580-3606784161-519 (Enterprise Admins)
[*]       * S-1-5-21-2324486357-3075865580-3606784161-512 (Domain Admins)
[+] Template: ESC4_Group_Ancestry_Check

Copy link

github-actions bot commented May 8, 2025

Thanks for your pull request! Before this can be merged, we need the following documentation for your module:

@jheysel-r7 jheysel-r7 added rn-modules release notes for new or majorly enhanced modules and removed needs-docs labels May 8, 2025
@jheysel-r7 jheysel-r7 linked an issue May 21, 2025 that may be closed by this pull request
@smcintyre-r7 smcintyre-r7 self-assigned this May 27, 2025
@jheysel-r7
Copy link
Contributor Author

Thanks for the review @smcintyre-r7. I added a datastore option in 31e2fca to allow the user to attempt to read the registry key values related to ESC9, 10 and potentially 16 later.

I've included some excerpts from a few different testing scenarios, a bit about the user who ran the module and the test environment.

testing

  • Low priv user: user3
  • user3 is a member of group1
  • group1 is member of group2
  • group2 has edit permissions over ESC4_Group_Ancestry_Check
[+] Template: ESC4_Group_Ancestry_Check
[*]   Distinguished Name: CN=ESC4_Group_Ancestry_Check,CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=kerberos,DC=issue
[*]   Manager Approval: Disabled
[*]   Required Signatures: 0
[+]   Vulnerable to: ESC4
[*]   Notes: ESC4: The account: user3 has edit permissions over the template ESC4_Group_Ancestry_Check.
  • user2 is not an admin so they can't query StrongCertificateBindingEnforcement and CertificateMappingMethods
  • RUN_REGISTRY_CHECKS is set to false (you get the same output when RUN_REGISTRY_CHECKS is set to true you just have to wait an extra ~20 seconds for the registry query to fail)
  • ESC9 is marked as "Potentially Vulnerable"
[+] Template: ESC9-Template
[*]   Distinguished Name: CN=ESC9-Template,CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=kerberos,DC=issue
[*]   Manager Approval: Disabled
[*]   Required Signatures: 0
[+]   Vulnerable to: ESC4
[!]   Potentially vulnerable to: ESC9 (the template is in a vulnerable configuration but in order to exploit registry key StrongCertificateBindingEnforcement must not be set to 2)
[*]   Notes:
[*]     * ESC4: The account: user2 has edit permissions over the template ESC9-Template.
[*]     * ESC9: The account: user2 has edit permission over the account: user3 which has enrollment rights for this template.
  • user1 is an admin so they can query the registry keys in question
  • RUN_REGISTRY_CHECKS is set to true
  • doesn't report "potentially vulnerable"
  • prints registry keys in notes
  • doesn't run find_esc9_vuln_cert_templates because StrongCertificateBindingEnforcement=2 so the target can't be vulnerable to ESC9 but still correctly runs and reports ESC10 vulnerable templates because CertificateMappingMethods=4
[+] Template: ESC10-Template
[*]   Distinguished Name: CN=ESC10-Template,CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=kerberos,DC=issue
[*]   Manager Approval: Disabled
[*]   Required Signatures: 0
[+]   Vulnerable to: ESC4, ESC10
[*]   Notes:
[*]     * ESC4: The account: user1 has edit permissions over the template ESC10-Template.
[*]     * ESC10: The account: user1 has edit permission over the account: user1 which has enrollment rights for this template. Registry values: StrongCertificateBindingEnforcement=2, CertificateMappingMethods=4.
  • same as above but StrongCertificateBindingEnforcement is not set to 2 so the target is vulnerable to ESC9 and it's corresponding "find method" find_esc9_vuln_cert_templates is run :
[+] Template: ESC9-Template
[*]   Distinguished Name: CN=ESC9-Template,CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=kerberos,DC=issue
[*]   Manager Approval: Disabled
[*]   Required Signatures: 0
[+]   Vulnerable to: ESC4, ESC9, ESC10
[*]   Notes:
[*]     * ESC4: The account: user1 has edit permissions over the template ESC9-Template.
[*]     * ESC9: The account: user1 has edit permission over the accounts: user1, user3, user2 which have enrollment rights for this template. Registry value: StrongCertificateBindingEnforcement=0.
[*]     * ESC10: The account: user1 has edit permission over the accounts: user1, user3, user2 which have enrollment rights for this template. Registry values: StrongCertificateBindingEnforcement=0, CertificateMappingMethods=4.

@jheysel-r7 jheysel-r7 requested a review from smcintyre-r7 May 30, 2025 00:21
end

def enum_registry_values
endpoint = "http://#{datastore['RHOST']}:5985/wsman"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The WMI port number here should be configurable. I know this could be done with SMB as well. I figured this is non-default functionality and thought it might be nice to be able to run Powershell commands (this might come in handy for ESC16). @smcintyre-r7 if you have any concerns around this design choice let me know.

find_esc13_vuln_cert_templates
find_esc15_vuln_cert_templates
if registry_values && registry_values[:disabled_extension_list]&.include?('1.3.6.1.4.1.311.25.2')
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It probably makes sense to run find_esc16_vuln_cert_templates even if we don't have the registry keys - in order to follow the same pattern of marking those templates as "Potentially vulnerable"... 🤔

ESC16 i guess is still a WIP, I need to refine the esc16_raw_filter to correctly match both scenario 1 & 2 - with UPN / SAN requirements.

Comment on lines 510 to 511
# Cache the registry values in @ldap_objects
@ldap_objects << { type: :registry_values, values: registry_values }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This just doesn't exactly seem right. The @ldap_objects should just contain ldap objects, caching registry values and the authenticated user is great but they should be kept separate because it's confusing to store things that aren't LDAP object here. Maybe @registry_values, keyed by the registry key would be a better fit?


def get_authenticated_user_info
# Check if the authenticated user info is already cached
cached_user_info = @ldap_objects.find { |obj| obj[:type] == :authenticated_user }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related to my other comment about storing things that aren't LDAP objects in the @ldap_objects array seems counter-intuitive. This also seems like we probably don't even need to cache it. If @whoami is caching the name of the current user, then the LDAP object can just be cached and stored with the other LDAP objects by it's sAMAccountName attribute.

Comment on lines 738 to 743
edit_flags = registry_object[:values][:edit_flags]
if edit_flags.to_i & 0x00040000 != 0
esc_entries.each do |entry|
certificate_symbol = entry[:cn][0].to_sym
@certificate_details[certificate_symbol][:techniques] << 'ESC16'
@certificate_details[certificate_symbol][:notes] << 'ESC16: Template is vulnerable due to the active policy EditFlags having the bit: 0x00040000 set (which is essentially ESC6) combined with the CA\'s disabled policy extension list including: 1.3.6.1.4.1.311.25.2.'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a contant we can add to and use from MsCrtd for 0x00040000? That'd also make the description more readable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The flag is defined by Microsoft as EDITF_ATTRIBUTESUBJECTALTNAME2:
https://learn.microsoft.com/en-us/defender-for-identity/security-assessment-edit-vulnerable-ca-setting

I've defined it at the top of this file for now as I'm not sure it belongs in MsCrtd as it's not prefixed with CT_FLAG but if there's a better place for it/ we want it in MsCrtd, I'd be happy to move it.

Comment on lines 482 to 497
conn.shell(:powershell) do |shell|
registry_values[:certificate_mapping_methods] = run_registry_command(shell, 'HKLM:\\SYSTEM\\CurrentControlSet\\Control\\SecurityProviders\\Schannel', 'CertificateMappingMethods')
registry_values[:strong_certificate_binding_enforcement] = run_registry_command(shell, 'HKLM:\\SYSTEM\\CurrentControlSet\\Services\\Kdc', 'StrongCertificateBindingEnforcement')

active_policy_name = run_registry_command(shell, 'HKLM:\\SYSTEM\\CurrentControlSet\\Services\\CertSvc\\Configuration\\*\\PolicyModules', 'Active')
registry_values[:disabled_extension_list] = run_registry_command(shell, 'HKLM:\\SYSTEM\\CurrentControlSet\\Services\\CertSvc\\Configuration\\*\\PolicyModules', 'DisableExtensionList', active_policy_name)
registry_values[:edit_flags] = run_registry_command(shell, 'HKLM:\\SYSTEM\\CurrentControlSet\\Services\\CertSvc\\Configuration\\*\\PolicyModules', 'EditFlags', active_policy_name)
end

if registry_values[:strong_certificate_binding_enforcement] == '1'
vprint_good('ESC9 could be exploitable using Kerberos due to StrongCertificateBindingEnforcement being set to 1')
elsif registry_values[:strong_certificate_binding_enforcement] == '0'
vprint_good('ESC10 could be exploitable using Kerberos due to StrongCertificateBindingEnforcement being set to 0')
elsif registry_values[:strong_certificate_binding_enforcement] == '2'
vprint_error('ESC9 and ESC10 cannot be exploited using Kerberos due to StrongCertificateBindingEnforcement being set to 2')
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A lot of these values should really be converted to integers instead of being left as strings because they are REG_DWORD values AFAIK. That would make checking for flags easier later on.

users = []
enroll_sids.each do |sid|
user_object = get_object_by_sid(sid.value)
next unless user_object && user_object[:ntsecuritydescriptor] && user_object[:objectclass]&.include?('user')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this is checking all of the users in the security descriptor that directly have enrollment rights. What this is missing are groups that have enrollment rights. So if a user has enrollment rights through a group that they're a member of, we're missing checking if we can write to that user object.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great catch - in this test scenario user1 has write privs over user3 who is a member of group1 which is a member of group2 which can enroll into the template titled: ESC9-Template-Group-Inheritance-Enroll-Test:

[+] Template: ESC9-Template-Group-Inheritance-Enroll-Test
[*]   Distinguished Name: CN=ESC9-Template-Group-Inheritance-Enroll-Test,CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=kerberos,DC=issue
[*]   Manager Approval: Disabled
[*]   Required Signatures: 0
[+]   Vulnerable to: ESC9, ESC10
[*]   Notes:
[*]     * ESC9: The account: user1 has edit permission over the user: user3 which has enrollment rights for this template. Registry value: StrongCertificateBindingEnforcement=0.
[*]     * ESC10: The account: user1 has edit permission over the user: user3 which has enrollment rights for this template. Registry values: StrongCertificateBindingEnforcement=0, CertificateMappingMethods=4.

Co-authored-by: Spencer McIntyre <[email protected]>
@jheysel-r7 jheysel-r7 changed the title ESC9 and ESC10 detection for ldap_esc_vulnerable_cert_finder ESC9, ESC10 and ESC16 detection for ldap_esc_vulnerable_cert_finder Jun 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
rn-modules release notes for new or majorly enhanced modules
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add Support for ESC9 & ESC10
2 participants