ldapsearch: Complete Guide to LDAP Enumeration and Directory Service Queries Using Kali Linux

ldapsearch: Complete Guide to LDAP Enumeration and Directory Service Queries Using Kali Linux

ldapsearch is a command-line utility from the OpenLDAP project used to query LDAP (Lightweight Directory Access Protocol) directory servers, most commonly Microsoft Active Directory Domain Controllers, but also standalone OpenLDAP, FreeIPA, and other directory services. LDAP is the protocol that underlies Active Directory’s object storage (users, groups, computers, organizational units, group policies), and because many AD environments permit unauthenticated (“anonymous”) binds or low-privilege authenticated binds by default, ldapsearch can extract an enormous amount of domain intelligence directly — often without needing any specialized AD tooling.

During enumeration, ldapsearch is used to:

It is a foundational tool for Active Directory enumeration and is frequently the very first thing run against port 389/636 once a Domain Controller is identified.

Installation

# Kali Linux (preinstalled as part of ldap-utils)
sudo apt update
sudo apt install ldap-utils -y

# Verify
ldapsearch -VV
which ldapsearch

Syntax

ldapsearch -x -H ldap://<target> -b "<base DN>" [options] [filter] [attributes]

Command-Line Options

OptionDescription
-xUse simple authentication instead of SASL
-H uriLDAP URI, e.g., ldap://192.168.10.10 or ldaps://192.168.10.10
-b basednBase DN to search from, e.g., "DC=corp,DC=local"
-D binddnDistinguished name to bind with (for authenticated bind)
-w passwordPassword for the bind DN (plaintext, on command line)
-WPrompt interactively for bind password (safer than -w)
-s scopeSearch scope: base, one, or sub (default sub)
-LLLMinimal output: no comments, no version, no line wrapping
-o ldif-wrap=noDisable LDIF line wrapping for cleaner parsing
-Z / -ZZUse StartTLS (optional/required)
-p portSpecify port (default 389, or 636 for LDAPS)
-vVerbose
-d levelDebug level
<filter>LDAP search filter, e.g., "(objectClass=user)"
<attrs>Space-separated list of attributes to return, e.g., sAMAccountName mail

Common useful filters:

FilterPurpose
(objectClass=*)Return everything (used with base scope to get root DSE)
(objectClass=user)All user objects
(objectClass=group)All group objects
(objectClass=computer)All computer objects
(&(objectClass=user)(admincount=1))Privileged accounts (protected by AdminSDHolder)
(userAccountControl:1.2.840.113556.1.4.803:=2)Disabled accounts
(description=*)Objects with a non-empty description field

Basic Usage

Query the root DSE (anonymous bind) to discover the base DN and server capabilities:

ldapsearch -x -H ldap://192.168.10.10 -s base -b "" "(objectClass=*)" namingContexts

Expected output:

# extended LDIF
#
# LDAPv3
# base <> with scope baseObject
# filter: (objectClass=*)
# requesting: namingContexts 
#

dn:
namingContexts: DC=corp,DC=local
namingContexts: CN=Configuration,DC=corp,DC=local
namingContexts: CN=Schema,CN=Configuration,DC=corp,DC=local

# search result
search: 2
result: 0 Success

Practical Examples

Example 1 — Discover base DN via anonymous root DSE query

ldapsearch -x -H ldap://192.168.10.10 -s base -b "" namingContexts
namingContexts: DC=corp,DC=local

Example 2 — Anonymous bind, dump all objects under the base DN

ldapsearch -x -H ldap://192.168.10.10 -b "DC=corp,DC=local"
# extended LDIF
#
# corp.local
dn: DC=corp,DC=local
objectClass: top
objectClass: domain
...
# Users, Users, corp.local
dn: CN=Users,DC=corp,DC=local
objectClass: container

Example 3 — Enumerate all usernames (sAMAccountName)

ldapsearch -x -H ldap://192.168.10.10 -b "DC=corp,DC=local" \
  "(objectClass=user)" sAMAccountName -LLL
dn: CN=Administrator,CN=Users,DC=corp,DC=local
sAMAccountName: Administrator

dn: CN=jdoe,CN=Users,DC=corp,DC=local
sAMAccountName: jdoe

dn: CN=asmith,CN=Users,DC=corp,DC=local
sAMAccountName: asmith

Example 4 — Authenticated bind with domain credentials

ldapsearch -x -H ldap://192.168.10.10 -D "jdoe@corp.local" -W \
  -b "DC=corp,DC=local" "(objectClass=user)" sAMAccountName mail
Enter LDAP Password:
dn: CN=jdoe,CN=Users,DC=corp,DC=local
sAMAccountName: jdoe
mail: jdoe@corp.local

Example 5 — Search for privileged (AdminCount=1) accounts

ldapsearch -x -H ldap://192.168.10.10 -D "jdoe@corp.local" -w 'Passw0rd!' \
  -b "DC=corp,DC=local" "(&(objectClass=user)(admincount=1))" sAMAccountName -LLL
dn: CN=Administrator,CN=Users,DC=corp,DC=local
sAMAccountName: Administrator

dn: CN=svc_backup,CN=Users,DC=corp,DC=local
sAMAccountName: svc_backup

Example 6 — Search description fields for accidentally leaked credentials

ldapsearch -x -H ldap://192.168.10.10 -D "jdoe@corp.local" -w 'Passw0rd!' \
  -b "DC=corp,DC=local" "(description=*)" sAMAccountName description -LLL
dn: CN=tempuser,CN=Users,DC=corp,DC=local
sAMAccountName: tempuser
description: temp pw Summer2026!

Example 7 — Enumerate all computer objects (workstations/servers)

ldapsearch -x -H ldap://192.168.10.10 -D "jdoe@corp.local" -w 'Passw0rd!' \
  -b "DC=corp,DC=local" "(objectClass=computer)" dNSHostName operatingSystem -LLL
dn: CN=DC01,OU=Domain Controllers,DC=corp,DC=local
dNSHostName: dc01.corp.local
operatingSystem: Windows Server 2019 Standard

dn: CN=WKSTN05,CN=Computers,DC=corp,DC=local
dNSHostName: wkstn05.corp.local
operatingSystem: Windows 11 Enterprise

Example 8 — Enumerate all groups and their members

ldapsearch -x -H ldap://192.168.10.10 -D "jdoe@corp.local" -w 'Passw0rd!' \
  -b "DC=corp,DC=local" "(objectClass=group)" cn member -LLL
dn: CN=Domain Admins,CN=Users,DC=corp,DC=local
cn: Domain Admins
member: CN=Administrator,CN=Users,DC=corp,DC=local
member: CN=asmith,CN=Users,DC=corp,DC=local

Example 9 — Find disabled accounts using a bitwise LDAP filter

ldapsearch -x -H ldap://192.168.10.10 -D "jdoe@corp.local" -w 'Passw0rd!' \
  -b "DC=corp,DC=local" "(userAccountControl:1.2.840.113556.1.4.803:=2)" sAMAccountName -LLL
dn: CN=old_svc,CN=Users,DC=corp,DC=local
sAMAccountName: old_svc

Example 10 — Using LDAPS (encrypted, port 636)

ldapsearch -x -H ldaps://192.168.10.10:636 -D "jdoe@corp.local" -w 'Passw0rd!' \
  -b "DC=corp,DC=local" "(objectClass=user)" sAMAccountName -LLL
dn: CN=jdoe,CN=Users,DC=corp,DC=local
sAMAccountName: jdoe

Common Use Cases

Automation with Bash

#!/bin/bash
# ldap_userlist.sh - Extract a clean sAMAccountName list from a Domain Controller
DC="192.168.10.10"
BASEDN="DC=corp,DC=local"
BINDDN="jdoe@corp.local"
BINDPW='Passw0rd!'
OUT="domain_users.txt"

ldapsearch -x -H "ldap://$DC" -D "$BINDDN" -w "$BINDPW" \
    -b "$BASEDN" "(objectClass=user)" sAMAccountName -LLL \
    | grep "^sAMAccountName:" | awk '{print $2}' | sort -u > "$OUT"

echo "[+] Extracted $(wc -l < "$OUT") usernames to $OUT"

Tips and Best Practices

Troubleshooting

ProblemLikely CauseSolution
ldap_bind: Invalid credentials (49)Wrong bind DN format or passwordTry user@domain.tld format, or full CN=...,DC=...,DC=... DN
ldap_sasl_bind(SIMPLE): Can't contact LDAP server (-1)Port blocked or wrong protocol/port comboConfirm with nmap -p389,636 <ip>; try ldaps:// on 636
Anonymous bind returns nothingAnonymous LDAP disabled (default on modern AD)Requires valid domain credentials (even a low-privilege account is usually enough)
ldap_bind: Strong(er) authentication required (8)Server enforces signed/encrypted LDAPUse -Z for StartTLS or connect via ldaps://
Search returns partial results onlyDefault LDAP result size/time limits on the serverAdd -z 0 (no size limit, if permitted) or narrow search scope/filter

References

Exit mobile version