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-utils

Verify: ldapsearch -VV

Full install index → Installation - Kali Setup


📌 When to Use

SituationAction
Nmap shows 389/tcp or 636/tcpRun anonymous ldapsearch
Have domain name from SMB/DNSBuild base DN: DC=corp,DC=local
Anonymous bind worksDump users/groups → wordlists for Kerbrute, AS-REP
Have domain credsAuthenticated search for SPNs, admins, descriptions

Alternatives: enum4linux (automates LDAP + SMB), windapsearch, Nmap ldap-search script.


📌 Base DN — Finding the Search Base

Convert domain corp.localDC=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]
FlagMeaning
-H ldap://IPLDAP URI (use ldaps:// for 636)
-xSimple authentication (password bind)
-D "user@domain"Bind DN / username
-w passwordPassword
-b "DC=..."Search base
-s subSubtree search (default)
-LLLCleaner 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.txt

When: 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.txt

See 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
  • servicePrincipalNameKerberoast
  • 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