Hacktricks-skills ldap-pentest

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.

install
source · Clone the upstream repo
git clone https://github.com/abelrguezr/hacktricks-skills
manifest: skills/network-services-pentesting/pentesting-ldap/SKILL.MD
source content

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

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

# 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.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

TaskCommand
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