ldapsearch — LDAP / AD Enumeration
Ctrl+F:
userlist·dn: CN=·user export·description·users.txt
External: Internal All The Things — Enumeration
What is ldapsearch?
ldapsearch is the standard Linux CLI for querying LDAP directories. On OSCP it is used against Active Directory (ports 389 / 636) to pull users, groups, computers, and attributes — often with anonymous bind (no creds).
OSCP use: Port 389 open → try anonymous
ldapsearch→ dump users → look for SPNs, descriptions with passwords, AS-REP roastable accounts. With creds, query deeper before Bloodhound + Sharphound.
Install (Kali)
sudo apt update && sudo apt install -y ldap-utilsVerify: ldapsearch -VV
Full install index → Installation - Kali Setup
📌 When to Use
| Situation | Action |
|---|---|
| Nmap shows 389/tcp or 636/tcp | Run anonymous ldapsearch |
| Have domain name from SMB/DNS | Build base DN: DC=corp,DC=local |
| Anonymous bind works | Dump users/groups → wordlists for Kerbrute, AS-REP |
| Have domain creds | Authenticated search for SPNs, admins, descriptions |
Alternatives: enum4linux (automates LDAP + SMB), windapsearch, Nmap ldap-search script.
📌 Base DN — Finding the Search Base
Convert domain corp.local → DC=corp,DC=local
#Finding names:
ldapsearch -H ldap://10.129.234.71 -x -s base -b "" namingContexts
# From Nmap ldap-rootdse
nmap -p 389 --script ldap-rootdse TARGET
# From enum4linux / SMB
enum4linux -a TARGET
# From DNS / hostname
# dc01.corp.local → DC=corp,DC=local📌 Core Syntax
ldapsearch -H ldap://TARGET -x -b "BASE_DN" [filter] [attributes]| Flag | Meaning |
|---|---|
-H ldap://IP | LDAP URI (use ldaps:// for 636) |
-x | Simple authentication (password bind) |
-D "user@domain" | Bind DN / username |
-w password | Password |
-b "DC=..." | Search base |
-s sub | Subtree search (default) |
-LLL | Cleaner output (no comments/wrap) |
📌 Anonymous Enumeration (No Creds)
# Test anonymous bind — does anything return?
ldapsearch -H ldap://10.10.10.10 -x -b "DC=domain,DC=local"
# All users
ldapsearch -H ldap://10.10.10.10 -x -b "DC=domain,DC=local" "(objectClass=user)" sAMAccountName
# All groups
ldapsearch -H ldap://10.10.10.10 -x -b "DC=domain,DC=local" "(objectClass=group)" cn
# All computers
ldapsearch -H ldap://10.10.10.10 -x -b "DC=domain,DC=local" "(objectClass=computer)" cn
# Cleaner output
ldapsearch -H ldap://10.10.10.10 -x -LLL -b "DC=domain,DC=local" "(objectClass=user)" sAMAccountName | grep sAMAccountName📌 Authenticated Queries
ldapsearch -H ldap://10.10.10.10 -x \
-D "user@domain.local" -w 'Password123' \
-b "DC=domain,DC=local" "(objectClass=user)" sAMAccountName description
# LDAPS (636)
ldapsearch -H ldaps://10.10.10.10 -x \
-D "user@domain.local" -w 'Password123' \
-b "DC=domain,DC=local" "(objectClass=user)"📌 High-Value LDAP Filters (OSCP)
# Users with SPN set (Kerberoast targets)
ldapsearch -H ldap://10.10.10.10 -x -b "DC=domain,DC=local" \
"(&(objectClass=user)(servicePrincipalName=*))" sAMAccountName servicePrincipalName
# AS-REP roastable (DONT_REQ_PREAUTH = 4194304)
ldapsearch -H ldap://10.10.10.10 -x -b "DC=domain,DC=local" \
"(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=4194304))" sAMAccountName
# Domain admins group members
ldapsearch -H ldap://10.10.10.10 -x -b "DC=domain,DC=local" \
"(&(objectClass=group)(cn=Domain Admins))" member
# Descriptions (often contain passwords in labs)
ldapsearch -H ldap://10.10.10.10 -x -b "DC=domain,DC=local" \
"(objectClass=user)" sAMAccountName description | grep -v "^#"📌 Extract Usernames to File
Ctrl+F:
userlist·dn: CN=·user export·users.txt
# From saved ldapsearch output (your pipeline)
ldapsearch -H ldap://10.10.10.10 -x -b "DC=domain,DC=local" "(objectClass=user)" > ldapsearch.out
cat ldapsearch.out | grep 'dn: CN=' | cut -d '=' -f 2 | cut -d ',' -f 1 | uniq > userlist.txt
# sAMAccountName (often cleaner)
ldapsearch -H ldap://10.10.10.10 -x -LLL -b "DC=domain,DC=local" \
"(objectClass=user)" sAMAccountName | grep sAMAccountName | awk '{print $2}' | sort -u > users.txt
# nxc export
nxc ldap DC_IP -u admin -p password --users 2>&1 | tee users_export.txtWhen: After anonymous or authenticated ldapsearch — feed Kerbrute, AS-REP, spray.
kerbrute userenum --dc 10.10.10.10 -d domain.local userlist.txt
impacket-GetNPUsers domain.local/ -dc-ip 10.10.10.10 -no-pass -usersfile userlist.txt
nxc ldap DC01.domain.local -u userlist.txt -p '' --asreproast asreproast.txtSee CrackMapExec - nxc > 📌 8b) User export & user descriptions · Pipelines & Chaining.
📌 Nmap LDAP Scripts
nmap -p 389 --script ldap-search,ldap-rootdse,ldap-brute TARGET📌 windapsearch (Alternative)
Often faster for AD-specific dumps (./windapsearch.py):
windapsearch -d domain.local --dc-ip 10.10.10.10 -U # users
windapsearch -d domain.local --dc-ip 10.10.10.10 -G # groups
windapsearch -d domain.local --dc-ip 10.10.10.10 --da # domain admins
windapsearch -d domain.local --dc-ip 10.10.10.10 --da -U user -P pass📌 What to Look For
- User list → AS-REP / spray / Kerbrute
- servicePrincipalName → Kerberoast
- description / info fields → cleartext passwords
- member / memberOf → group membership, Domain Admins
- pwdLastSet / lockout → password policy hints
📌 Quick Copy/Paste
# Anonymous user dump
ldapsearch -H ldap://TARGET -x -LLL -b "DC=domain,DC=local" "(objectClass=user)" sAMAccountName
# Auth bind
ldapsearch -H ldap://TARGET -x -D "user@domain.local" -w pass -b "DC=domain,DC=local" "(objectClass=*)"
# SPN hunt
ldapsearch -H ldap://TARGET -x -b "DC=domain,DC=local" "(&(objectClass=user)(servicePrincipalName=*))" sAMAccountName servicePrincipalName