Reconstructing LDAP Directory Queries via PCAP Analysis and Enumeration Pattern Detection
Theory
Why This Matters
In the 2017 Equifax breach, post-compromise analysis revealed that attackers spent weeks performing LDAP queries against Active Directory to enumerate all user accounts, group memberships, and administrative principals before executing credential theft. The LDAP query traffic was captured on a network tap but went unanalysed until after the breach was disclosed, because analysts were not trained to recognise LDAP enumeration patterns in raw PCAP data. LDAP is the backbone of every Active Directory environment — it exposes the complete organisational hierarchy, all user accounts, all groups, service principal names, and password policy details to any authenticated (or in misconfigured deployments, anonymous) requestor. Understanding how to read and reconstruct LDAP traffic from a PCAP is essential for determining what an attacker discovered during a reconnaissance phase.
Core Concept
LDAP (Lightweight Directory Access Protocol) operates on TCP port 389 (plaintext) and TCP port 636 (LDAPS — TLS). All messages are encoded in ASN.1 BER (Basic Encoding Rules), a binary format. Wireshark dissects this automatically.
The fundamental operations: BindRequest (authenticate — either Simple with DN + plaintext password, or SASL with negotiated mechanism), SearchRequest (query — specifying baseObject, scope, filter, and requested attributes), SearchResultEntry (one response record), SearchResultDone (end of results), UnbindRequest (end session).
A Simple Bind sends the Distinguished Name and password in plaintext over port 389. An anonymous bind uses an empty DN and password — some LDAP servers permit this, allowing unauthenticated enumeration. SASL (Simple Authentication and Security Layer) mechanisms include GSSAPI (Kerberos) and NTLM; these are more complex but the channel is still unencrypted on port 389.
LDAP search filters follow a Polish-prefix notation: (objectClass=*) matches all objects; (&(objectClass=user)(memberOf=CN=Domain Admins,DC=corp,DC=com)) matches users who are Domain Admins. Reconstructing what an attacker searched for reveals exactly what they were trying to enumerate.
LDAP response attributes — returned in SearchResultEntry messages — can include sAMAccountName (login name), memberOf (group memberships), userPrincipalName, mail, distinguishedName, pwdLastSet, userAccountControl (disabled/enabled/password-never-expires flags), and servicePrincipalName (Kerberoastable accounts).
Technical Deep-Dive
# View all LDAP operations in a PCAP
tshark -r capture.pcap -Y "ldap" -T fields
-e frame.number -e frame.time_relative -e ip.src -e ip.dst
-e ldap.protocolOp -e ldap.baseObject -e ldap.filter
-E header=y -E separator="|"
# Extract Simple Bind credentials (DN + password)
tshark -r capture.pcap
-Y "ldap.BindRequest_element and ldap.simple"
-T fields -e frame.time_relative
-e ip.src -e ldap.name -e ldap.simple
# ldap.name = bind DN, ldap.simple = plaintext password
# List all unique search filters used (reveals enumeration intent)
tshark -r capture.pcap
-Y "ldap.SearchRequest_element"
-T fields -e ip.src -e ldap.baseObject -e ldap.filter
| sort -u
# Extract attributes returned in search results
tshark -r capture.pcap
-Y "ldap.SearchResultEntry_element"
-T fields -e frame.time_relative
-e ldap.AttributeDescription -e ldap.AssertionValue
-E separator="|" | head -40
# Detect anonymous bind attempts (empty DN)
tshark -r capture.pcap
-Y "ldap.BindRequest_element"
-T fields -e frame.time_relative
-e ip.src -e ldap.name -e ldap.simple
| awk -F" " '$3=="" && $4=="" {print "ANONYMOUS BIND from " $2 " at " $1}'
# Python/ldap3 equivalent query (for understanding; do not run against live target without auth)
# This shows what the captured traffic represents structurally
from ldap3 import Connection, Server, ALL, NTLM, ALL_ATTRIBUTES
# Equivalent of what the LDAP Bind + Search in the PCAP represents:
# Bind: cn=svc_account,dc=corp,dc=com with password "captured_password"
# Search: baseObject="dc=corp,dc=com", filter="(objectClass=user)",
# attributes=["sAMAccountName","memberOf","userPrincipalName"]
# Scapy does not have a high-level LDAP builder for searches;
# use tshark field extraction for PCAP analysis instead.
# Decode ASN.1 BER manually from raw bytes (for custom protocol analysis)
import struct
def read_tlv(data, offset=0):
"""Read one ASN.1 TLV triple from data at offset."""
tag = data[offset]
length = data[offset + 1]
if length & 0x80:
n_bytes = length & 0x7f
length = int.from_bytes(data[offset+2:offset+2+n_bytes], "big")
offset += n_bytes
value = data[offset + 2: offset + 2 + length]
return tag, value, offset + 2 + length
Analytical Methodology
- Open the PCAP in Wireshark. Apply display filter
ldapto isolate all LDAP traffic. Note source IPs and determine which are domain controllers (typically serving both port 389 and port 88/Kerberos) versus clients. - Apply filter
ldap.BindRequest_elementto identify all bind operations. Look forldap.simplefield — its presence indicates a Simple Bind with a plaintext password. Note the DN and password for each bind. - Apply filter
ldap.SearchRequest_elementto enumerate all searches. Sort or group byldap.filterto identify patterns: broad(objectClass=*)queries indicate reconnaissance; queries for(memberOf=CN=Domain Admins...)indicate privilege escalation intelligence gathering. - Apply filter
ldap.SearchResultEntry_elementand examineldap.AttributeDescriptionandldap.AssertionValueto see exactly what data the server returned. In Wireshark, expand the LDAP tree in the packet details pane to read each attribute-value pair. - Right-click any LDAP packet from a specific session and select Follow → TCP Stream to read the complete bind-search-response sequence in sequence.
- Use tshark to export all unique search filters and response attributes to CSV for offline analysis. Cross-reference returned account names with known privileged accounts.
- In NetworkMiner, LDAP is not dissected automatically, but the Credentials tab will capture Simple Bind credentials. The raw packet hex view assists in manual ASN.1 inspection.
- Determine whether any searches targeted
servicePrincipalNameattributes — this indicates potential Kerberoasting preparation. Searches for(userAccountControl:1.2.840.113556.1.4.803:=65536)(password never expires) identify high-value targets. - Document the complete enumeration timeline: first bind timestamp, last search timestamp, total queries, distinct object types queried, and all usernames and passwords extracted from Simple Binds.
Common Analytical Errors
- Ignoring anonymous binds: Some analysts skip bind analysis and jump to search queries. An anonymous bind that successfully returns search results indicates a misconfigured LDAP server that allows unauthenticated enumeration — a critical finding in its own right, separate from any credential theft.
- Reading only the filter, not the response: The search filter reveals intent; the SearchResultEntry reveals what was actually obtained. An analyst who documents only filters without examining returned attributes cannot determine the actual intelligence value of the reconnaissance.
- Missing LDAP over LDAPS (port 636): Encrypted LDAP traffic on port 636 appears as TLS in the PCAP. Without TLS key material, the LDAP content is unavailable, but the connection metadata (source IP, DC IP, session duration, volume) still indicates directory access.
- Confusing message IDs with sequence: LDAP is an asynchronous protocol; multiple requests can be in flight simultaneously, each with a unique messageID. Grouping request/response pairs by messageID (not by frame order) is required for accurate session reconstruction.
- Overlooking SASL NTLM/Kerberos bind evidence: Even though SASL binds do not expose credentials in plaintext, the presence of NTLM NEGOTIATE/CHALLENGE/AUTHENTICATE frames or Kerberos AP-REQ within an LDAP session identifies the authenticating account and domain, and NTLM hashes are recoverable for offline cracking.
NICE Framework Alignment
| Code | Knowledge/Skill/Task Statement | How This Card Develops It |
|---|---|---|
| K0046 | Knowledge of intrusion detection systems and methodologies | Identifying LDAP enumeration patterns that SIEM and IDS rules detect: anonymous binds, high query rates, broad objectClass searches |
| K0093 | Knowledge of network protocols | Understanding LDAP's ASN.1 BER encoding, BindRequest/SearchRequest mechanics, SASL vs Simple authentication, and Active Directory attribute semantics |
| K0221 | Knowledge of OSI model and network layers | Locating LDAP at the application layer over TCP, distinguishing port 389 plaintext from port 636 TLS encapsulation |
| S0046 | Skill in performing packet-level analysis | Using Wireshark ldap filters, tshark field extraction for bind credentials and search filters, and correlating queries with responses via messageID |
| T0023 | Collect intrusion artifacts for use in forensic analysis | Extracting LDAP bind credentials, enumerated user accounts, group memberships, and search filter sequences as structured forensic evidence |
Further Reading
- The Active Directory Security Handbook — Sean Metcalf (adsecurity.org) — LDAP Enumeration Techniques chapter
- Network Forensics: Tracking Hackers Through Cyberspace — Sherri Davidoff & Jonathan Ham, Chapter 11: Directory Services Forensics (Prentice Hall)
- RFC 4511: Lightweight Directory Access Protocol (LDAP): The Protocol — Sermersheim (IETF)
Challenge Lab
Reinforce your learning with a hands-on generated challenge based on this card's competency.