metasploit-framework
metasploit-framework copied to clipboard
Add in support for GUIDs, Certificate Handling, and SIDs to ldap_query Module
Adds support for GUIDs, reading certificates and outputting their details, and handling SIDs to auxiliary/gather/ldap_query.rb. Also add in some time related element support.
Verification
- [ ] Install ADCS on either a new or existing domain controller
- [ ] Open the Server Manager
- [ ] Select Add roles and features
- [ ] Select "Active Directory Certificate Services" under the "Server Roles" section
- [ ] When prompted add all of the features and management tools
- [ ] On the AD CS "Role Services" tab, leave the default selection of only "Certificate Authority"
- [ ] Completion the installation and reboot the server
- [ ] Reopen the Server Manager
- [ ] Go to the AD CS tab and where it says "Configuration Required", hit "More" then "Configure Active Directory Certificate..."
- [ ] Select "Certificate Authority" in the Role Services tab
- [ ] Keep all of the default settings, noting the value of the "Common name for this CA" on the "CA Name" tab (this value corresponds to the
CAdatastore option) - [ ] Accept the rest of the default settings and complete the configuration
- [ ] Add a new entry to the
ldap_queries_default.yamlwith the following content (overwrite any existing entries with same name):
- action: ENUM_ADCS_CAS
description: 'Enumerate ADCS certificate authorities.'
base_dn_prefix: 'CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=Configuration'
filter: '(objectClass=pKIEnrollmentService)'
attributes:
- cn
- name
- cACertificateDN
- dNSHostname
- certificateTemplates
- objectGUID
- caCertificate
- [ ] Start
msfconsole - [ ]
use auxiliary/gather/ldap_query - [ ]
set RHOSTS <target IP> - [ ]
set ACTION ENUM_ADCS_CAS - [ ]
set BIND_DN <DOMAIN>\\<USERNAME> - [ ]
set BIND_PW <PASSWORD> - [ ]
run - [ ] Verify that the
cacertificatefield looks similar to the following and is no longer a binary blob of data:
cacertificate Version: 0x2, Subject: /DC=com/DC=daforest/CN=daforest-WIN-BR0CCBA
815B-CA, Issuer: /DC=com/DC=daforest/CN=daforest-WIN-BR0CCBA815B-C
A, Signature Algorithm: sha256WithRSAEncryption, Extensions: keyUs
age = Digital Signature, Certificate Sign, CRL Sign | basicConstra
ints = critical, CA:TRUE | subjectKeyIdentifier = DD:1C:7F:D8:EE:F
9:A8:D0:AA:6E:AC:55:61:E0:70:AC:45:03:70:6C | 1.3.6.1.4.1.311.21.1
= ...
- [ ] Verify that the
objectguidfield is now decoded into a valid GUID. You can verify if the GUID is valid by opening up a Active Directory Module for Powershell prompt and typing inget-adobject -id <OBJECT GUID>and if its valid you should see some output like the following, instead of an object not found error:
PS C:\Users\Administrator> get-adobject -id "87564274-339B-4CFB-8686-8CBE2F4AB035"
DistinguishedName Name ObjectClass ObjectGUID
----------------- ---- ----------- ----------
CN=S-1-5-4,CN=ForeignSecurityPrincipals,DC=daforest,DC=com S-1-5-4 foreignSecurityPrincipal 87564274-339b-4cfb-8686-8cbe2f4ab035
PS C:\Users\Administrator>
- [ ] Finally modify
ldap_queries_default.yamland include the following:
- action: ENUM_SID
description: 'Enumerate SIDs.'
filter: '(objectSID=*)'
attributes:
- cn
- name
- objectSID
- [ ]
reload - [ ]
set ACTION ENUM_SID - [ ]
run - Verify you now see output similar to the following with the
objectSIDfield properly decoded into an SID instead of being a binary blob.
CN=DnsUpdateProxy CN=Users DC=daforest DC=com
=============================================
Name Attributes
---- ----------
cn DnsUpdateProxy
name DnsUpdateProxy
objectsid S-1-5-21-3290009963-1772292745-3260174523-1102
- [ ] Update the
ldap_queries_default.yamlfile and add the follow entry:
- action: ENUM_TIME_ELEMENTS
description: 'Enumerate time elements'
filter: '(CreationTime=*)'
attributes:
- cn
- name
- creationTime
- lockoutDuration
- maxPwdAge
- minPwdAge
- systemFlags
- [ ]
reload - [ ]
set ACTION ENUM_TIME_ELEMENTS - [ ]
run - [ ] Verify that you get decoded
maxPwdAge,minPwdAgeelements, thatlockoutDurationis a time string and not an integer anymore, and thatsystemFlagsis decoded into a string and isn't a negative integer anymore.
msf6 auxiliary(gather/ldap_query) > run
[*] Running module against 172.22.163.183
[+] Successfully bound to the LDAP server!
[*] Discovering base DN automatically
[+] 172.22.163.183:389 Discovered base DN: DC=daforest,DC=com
DC=daforest DC=com
==================
Name Attributes
---- ----------
creationtime 2022-09-01 19:37:37 UTC
lockoutduration 0:00:30:00
maxpwdage 42:00:00:00
minpwdage 1:00:00:00
name daforest
systemflags FLAG_DISALLOW_DELETE | FLAG_DOMAIN_DISALLOW_RENAME | FLAG_DOMAIN_DISALLOW_MOVE
CN=Builtin DC=daforest DC=com
=============================
Name Attributes
---- ----------
cn Builtin
creationtime 2022-08-18 17:48:12 UTC
lockoutduration 0:00:30:00
maxpwdage 42:22:47:31
minpwdage 0:00:00:00
name Builtin
systemflags FLAG_DISALLOW_DELETE | FLAG_DOMAIN_DISALLOW_RENAME | FLAG_DOMAIN_DISALLOW_MOVE
[*] Auxiliary module execution completed
msf6 auxiliary(gather/ldap_query) >
The code all looks reasonable to me. I ran through all the proposed test cases and everything worked as intended :+1: .
The only concern I have is the logic associating the types with the decoders. From the screenshot @adfoster-r7 posted, it looks like other tools are applying similar decoding logic to the binary strings returned by ldap. I know we want to optimize for the most common use case of Active Directory but it seems worth mentioning that a schema could feasibly exist where for example the objectsid is not in the expected format. I think at a minimum we'd want to have exception handling (or basic checks like lenght) that falls back to printing the escaped binary string when the decoding logic fails.
@msjenkins-r7 test this please.
Release Notes
This improves the existing ldap_query module by allowing it to decode some data types into a human readable format.