Pentesting LDAP

ldapsearch Overview

  • LDAP is extremely hard for blue teams/IR to investigate as it is a critical function of AD

  • Log event ID 4648 will be generated from LDAP enumeration, which does not occur in normal AD LDAP traffic

  • It defaults to plain text authentication, so use TLS if you dont want to send creds in the clear

  • -ZZ forces the use of TLS

  • If you use -ZZ and port 636 is not open you will recieve an error message LDAP server is unavailable

  • Add TLS_REQCERT ALLOW to /etc/ldap/ldap.conf to disable certificate validation if you plan on using TLS LDAP

  • To use SSL with LDAP use -H option with ldaps://DC.domain.local

  • If SSL is not set up on the DC you will recieve the error Cant contact LDAP server

--help--
-D --> DN (username to bind with)
-w --> password
-p --> port (depricated option)
-b --> base location to begin your search
-s --> scope, defaults to subtree
-h --> name to append to ldap://
-H --> LDAP server with port specified (ldap://server.org:389)
-P --> protocol (2|3) default is 3
-Z --> start with TLS failover if unavailable
-ZZ --> force the use of TLS
-L --> restrict stdout to LDIFUL, -LL also disable comments
-LLL --> same as above + disable LDIF verion print if you want to export to LDAPAdmin.exe
-E pr=1000/noprompt --> perform up to 1000 requests w/o user prompt to continue
  • To use this tool you need at least the domain for DC --> whoami /fqdn / other enumeration

ldapsearch Generated Logs

4776 credential validation event
4672 special logon (if utilizing admin creds)
4648 logon with credentials specified explicitly
4624/4634 login/logoff for queries

ldapsearch

  • ldapsearch is a great utility to solicit information from a domain controller.

  • Start with attempting to see the scope

ldapsearch -H ldap://10.10.10.161 -x 
#output 
# extended LDIF
#
# LDAPv3
# base <> (default) with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# search result
search: 2
result: 32 No such object
text: 0000208D: NameErr: DSID-0310021B, problem 2001 (NO_OBJECT), data 0, best 
 match of:
        ''
# numResponses: 1
  • From there the next step is to get the DN

ldapsearch -H ldap://10.10.10.161 -x -s base namingcontexts

#output
# extended LDIF
#
# LDAPv3
# base <> (default) with scope baseObject
# filter: (objectclass=*)
# requesting: namingcontexts 
#

#
dn:
namingContexts: DC=htb,DC=local
namingContexts: CN=Configuration,DC=htb,DC=local
namingContexts: CN=Schema,CN=Configuration,DC=htb,DC=local
namingContexts: DC=DomainDnsZones,DC=htb,DC=local
namingContexts: DC=ForestDnsZones,DC=htb,DC=local

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1
  • Note: The DN in the above query is DC=htb,DC=local, which you will need later

  • For this DN it is essentially the name of the domain you are targeting, in this example the target domain was htb.local.

  • At this point take your new found DN and use this query

ldapsearch -H ldap://10.10.10.161 -x -b "DC=htb,DC=local"
  • Recommend directing this output to a file so you can grep

ldapsearch -H ldap://10.10.10.161 -x -b "DC=htb,DC=local" > ldap.out
  • This command will produce a ton of output as it is all the ldap information that you can query

--snip--
name: Security Administrator
objectGUID:: klxj80zg9EmTbS/Pjp/57w==
objectSid:: AQUAAAAAAAUVAAAALB4ltxV1shXFsPNPXQQAAA==
sAMAccountName: Security Administrator
sAMAccountType: 268435456
managedBy: CN=Organization Management,OU=Microsoft Exchange Security Groups,DC
 =htb,DC=local
groupType: -2147483640
objectCategory: CN=Group,CN=Schema,CN=Configuration,DC=htb,DC=local
dSCorePropagationData: 20220922021046.0Z
dSCorePropagationData: 20220922021046.0Z
dSCorePropagationData: 20220922021046.0Z
dSCorePropagationData: 20220922021045.0Z
dSCorePropagationData: 16010101000000.0Z
msExchVersion: 44220983382016
msExchGroupJoinRestriction: 0
msExchProvisioningFlags: 0
msExchMailboxAuditEnable: FALSE
msExchUserBL: CN=Security Admin-Security Administrator,CN=Role Assignments,CN=
 RBAC,CN=First Organization,CN=Microsoft Exchange,CN=Services,CN=Configuration
 ,DC=htb,DC=local
--snip--
  • With your output in a text file, use these grep commands

cat ldap.out| grep -i samaccountname 
--snip--
sAMAccountName: test
sAMAccountName: sebastien
sAMAccountName: santi
sAMAccountName: lucinda
sAMAccountName: andy
sAMAccountName: mark
--snip--
cat ldap.out| grep -i samaccountname | awk '{print $2}'
#use this to just get the usernames to make your user.txt list
cat ldap.out| grep -i memberof   
--snip--   
memberOf: CN=Guests,CN=Builtin,DC=htb,DC=local
memberOf: CN=System Managed Accounts Group,CN=Builtin,DC=htb,DC=local
memberOf: CN=Denied RODC Password Replication Group,CN=Users,DC=htb,DC=local
memberOf: CN=Users,CN=Builtin,DC=htb,DC=local
memberOf: CN=Guests,CN=Builtin,DC=htb,DC=local
--snip--

Building an LDAP Query

  • once we have the above information we can run this ldap query to get all the the object class of person

ldapsearch -H ldap://10.10.10.161 -x -b "DC=htb,DC=local" '(objectClass=Person)'
--snip--
name: Santi Rodriguez
objectGUID:: VSlmUT29FkGHUAJ12EnggA==
userAccountControl: 66048
badPwdCount: 367
codePage: 0
countryCode: 0
badPasswordTime: 133082459752791259
lastLogoff: 0
lastLogon: 0
pwdLastSet: 132134941751348277
primaryGroupID: 513
--snip--
  • For a more specific query where you just want the usernames you can use this query which is an alt method to our above command that utilized awk

ldapsearch -H ldap://10.10.10.161 -x -b "DC=htb,DC=local" '(objectClass=Person)' sAMAccountName
ldapsearch -H ldap://10.10.10.161 -x -b "DC=htb,DC=local" '(objectClass=User)' sAMAccountName sAMAccountType
ldapsearch -H ldap://10.10.10.161 -x -b "DC=htb,DC=local" '(objectClass=Person)' sAMAccountName | grep sAMAccountName
  • Note if you see the above commands return something like this:

requesting:
Guest
DefaultAccount
FOREST$
EXCH01$
$331000-VK4ADACQNUCA
SM_2c8eef0a09b545acb
SM_ca8c2ed5bdab4dc9b
SM_75a538d3025e4db9a
SM_681f53d4942840e18
SM_1b41c9286325456bb
SM_9b69f1b9d2cc45549
SM_7c96b981967141ebb
SM_c75ee099d0a64c91b
SM_1ffab36a2f5f479cb
HealthMailboxc3d7722
HealthMailboxfc9daad
HealthMailboxc0a90c9
HealthMailbox670628e
HealthMailbox968e74d
HealthMailbox6ded678
HealthMailbox83d6781
HealthMailboxfd87238
HealthMailboxb01ac64
HealthMailbox7108a4e
HealthMailbox0659cc1
sebastien
lucinda
andy
mark
santi
  • Most of those accounts are either machine accounts (those that end in $) or exchange accounts that do not allow login or user interaction.

  • For the above example the only account we would be interested in are:

sebastien
lucinda
andy
mark
santi

ldapsearch with creds

ldapsearch -LLL -h 127.0.0.1 -b "dc=rastalabs,dc=local" -x -D "RLAB\ngodfrey_adm" -w "PASSWORD" '(ms-Mcs-AdmPwdExpirationtime=*)' ms-Mcs-AdmPwd

Other Common Queries

  • Query all users collecting login infomation

#no TLS 
ldapsearch -D "cn=epugh_adm,dc=rastalabs,dc=local" -w password123 -h 10.10.120.1 -b "dc=rastalabs,dc=local" -S logoncount "samAccountType=805306368" displayname, lastlogon, logoncount, memberof
#TLS
ldapsearch -ZZ -D "cn=epugh_adm,dc=rastalabs,dc=local" -w password123 -p 636 -h 10.10.120.1 -b "dc=rastalabs,dc=local" -S logoncount "samAccountType=805306368" displayname, lastlogon, logoncount, memberof
  • kerberostable accounts

#no TLS
ldapsearch -D "cn=epugh_adm,dc=rastalabs,dc=local" -w password123 -h 10.10.120.1 -b "dc=rastalabs,dc=local" "samAccountType=805306368" servicePrincipalName admincount
#TLS
ldapsearch -ZZ -D "cn=epugh_adm,dc=rastalabs,dc=local" -w password123 -p 636 -h 10.10.120.1 -b "dc=rastalabs,dc=local" "samAccountType=805306368" servicePrincipalName admincount
  • ASREP Roastable accounts

#no TLS
ldapsearch -D "cn=epugh_adm,dc=rastalabs,dc=local" -w password123 -h 10.10.120.1 -b "(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=4194304))" displayName lastlogon badpasswordtime
#TLS
ldapsearch -ZZ -D "cn=epugh_adm,dc=rastalabs,dc=local" -w password123 -p 636 -h 10.10.120.1 -b "(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=4194304))" displayName lastlogon badpasswordtime
  • Pull all DCs in domain in addition to their Operating System

#no TLS
ldapsearch -D "cn=epugh_adm,dc=rastalabs,dc=local" -w password123 -H ldap://10.10.120.1 -b "(&(objectClass=computer)(userAccountControl:1.2.840.113556.1.4.803:=8192))" operatingSystem
#TLS
ldapsearch -ZZ -D "cn=epugh_adm,dc=rastalabs,dc=local" -w password123 -p 636 -H ldap://10.10.120.1 -b "(&(objectClass=computer)(userAccountControl:1.2.840.113556.1.4.803:=8192))" operatingSystem
  • Dump all of AD *This is alot of output*

#no TLS
ldapsearch -D "cn=epugh_adm,dc=rastalabs,dc=local" -w password123 -H ldap://10.10.120.1 -b "(objectClass=*)" > Output.ldif
#TLS
ldapsearch -ZZ -D "cn=epugh_adm,dc=rastalabs,dc=local" -w password123 -p 636 -H ldap://10.10.120.1 -b "(objectClass=*)" > Output.ldif
  • See the size of the domain

#no TLS 
ldapsearch -LLL -h 10.10.120.1 -D "CN=epugh,OU=ServiceAccounts,DC=rastalabs,DC=local" -w password123 -E pr=1000/noprompt -b "dc=rastalabs,dc=local" -s sub '(objectClass=*)' distinguishedName > AD_Size.ldif
#TLS
ldapsearch -ZZ -LLL -h 10.10.120.1 -p 636 -D "CN=epugh,OU=ServiceAccounts,DC=rastalabs,DC=local" -w password123 -E pr=1000/noprompt -b "dc=rastalabs,dc=local" -s sub '(objectClass=*)' distinguishedName > AD_Size.ldif

Last updated