Port 389 – LDAP
Pentesting LDAP
From a pentesting perspective, LDAP is a goldmine of information. It can lead to obtaining user accounts, descriptions, service accounts, SPNs for Kerberoasting, and potential plaintext passwords hiding in object attributes. Even without credentials, LDAP can often leak valuable intel.
Discovery and Enumeration
Discovery
Start by identifying whether LDAP is exposed and what version is running. The goal here is to detect the protocol, confirm it’s LDAP, and identify if anonymous access may be possible. You can use the Nmap tool to discover servers with the LDAP ports 389 or 636 open.
nmap -p 389,636 -sV 10.1.1.1 #Check for LDAP or LDAPS services on a single host nmap -p 389,636 -sV 10.1.1.0/24 #Check for LDAP or LDAPS services on a subnet nmap -p 389,636 -sV -iL targets.txt #Check for LDAP or LDAPS services on a list of IPs
Use the NSE scripts to fingerprint the LDAP service and possibly retrieve the naming context (root domain):
nmap -n -sV --script "ldap* and not brute" 10.1.1.1 #Use NSE LDAP scripts
Look for responses like:
- Microsoft Windows Active Directory LDAP
- OpenLDAP
- Indication of anonymous bind support
Enumeration
Once LDAP is confirmed, move to enumeration. The aim is to pull as much information as possible from the server, either anonymously or with credentials, such as:
-
Naming context (domain info)
-
Usernames
-
Computer accounts
-
Group memberships
-
Descriptions (which may leak creds)
-
SPNs (for Kerberoasting)
Null Bind / Anonymous Enumeration
Some LDAP servers allow binding without credentials. If enabled, this is a quick win to start extracting basic info. You can use the ldapsearch command-line tool.
ldapsearch -x -H ldap://10.1.1.1:389 -s base -b "" "(objectClass=*)" #Check if anonymous bind works and get domain root
If the above is successful, you can try to enumerate users and other LDAP objects directly.
ldapsearch -x -H ldap://10.1.1.1 -b "dc=example,dc=local" #Attempt full enumeration with anonymous bind
Even without creds, you may be able to extract:
-
Users (sAMAccountName)
-
Descriptions (which often leak internal info)
-
Domain naming context
-
OU structure
Authenticated Enumeration
If credentials are available (domain user, service account, low-priv creds), LDAP can be fully queried using the ldapsearch command-line tool. Use the naming context returned from the rootDSE query as your base (-b)
Credential Hunting
Many organisations store credentials, temporary passwords, or legacy info in the description field of user accounts. You should always grep LDAP output for sensitive strings.
ldapsearch -LLL -H ldap://10.1.1.1 -D "domain\user" -w "pass" -b "dc=example,dc=local" "(objectClass=user)" sAMAccountName description | grep -iE 'pass|pwd|key|legacy' #Dump all user descriptions and grep for keywords
Alternatively, you can craft specific filters:
ldapsearch -LLL -H ldap://10.1.1.1 -D "domain\user" -w "pass" -b "dc=example,dc=local" "(&(objectCategory=person)(objectClass=user)(description=*pass*))" #Only users where the description field contains the word "pass"
SPN and Kerberoasting
Once you have valid credentials (even low-priv), you can use LDAP to enumerate Service Principal Names (SPNs), which are tied to service accounts and are the target for Kerberoasting.
ldapsearch -LLL -H ldap://10.1.1.1 -D "domain\user" -w "pass" -b "dc=example,dc=local" "(servicePrincipalName=*)" servicePrincipalName sAMAccountName #Find all user accounts with SPNs set
Then use impacket to obtain the hashes:
GetUserSPNs.py domain.local/<user>:<password> -dc-ip 10.1.1.1 -outputfile spns.txt
This outputs hashes you can crack offline with hashcat or john.
Filter Examples and LDAP Flags
LDAP filters allow us to fine-tune queries. Below are powerful examples to use during enumeration:
| Filter Purpose | LDAP Filter Expression |
|---|---|
| All users | (objectClass=user) |
| User accounts only | (&(objectCategory=person)(objectClass=user)) |
| Description contains ‘pass’ | (&(objectClass=user)(description=*pass*)) |
| SPNs set | (servicePrincipalName=*) |
| No password required | userAccountControl:1.2.840.113556.1.4.803:=32 |
| Password never expires | userAccountControl:1.2.840.113556.1.4.803:=65536 |
| Admin accounts | (&(objectCategory=person)(objectClass=user)(adminCount=1)) |
Other Tools
The following tools are also useful to help automate or streamline LDAP enumeration.
windapsearch -d example.com --dc-ip 10.1.1.1 -u [email protected] -p 'Password123' --full #Full AD search
ldapdomaindump -u 'DOMAIN\\user' -p 'pass' 10.1.1.1 -o ./ldap_dump #JSON & HTML output
godap 10.1.1.1 #Check for anonymous ldap bind