SecureBlockLog inStart a pentest
Vulnerability Repository
HighInjection

LDAP Injection

Unsanitized input embedded in LDAP queries lets attackers bypass authentication, enumerate directory objects, and extract sensitive Active Directory data.

CVSS 8.1CWE CWE-90OWASP A03:2021 — Injection

Description

LDAP injection (CWE-90) occurs when user-supplied input is concatenated into an LDAP filter string without proper escaping, allowing attackers to manipulate the query's logic. LDAP (Lightweight Directory Access Protocol) is the backbone of most enterprise authentication systems — Microsoft Active Directory, OpenLDAP, and Oracle Directory Server all speak LDAP — making this vulnerability class highly relevant to corporate penetration tests and red team engagements.

The vulnerability follows the same root cause as SQL injection: treating user data as code rather than as data. LDAP filter syntax uses parentheses, asterisks, and boolean operators (&, |, !) as structural elements. When these characters appear unescaped in a query, the filter's meaning changes.

LDAP injection surfaces most commonly in web application login forms that authenticate against Active Directory, employee directory search features, and identity management APIs. It falls under OWASP A03:2021 (Injection) and can lead to authentication bypass, sensitive data disclosure from the directory, and in rare cases full directory enumeration.

How It Works

Consider a web login form that constructs the following LDAP bind query:

(&(uid=USERNAME)(password=PASSWORD))

The application builds this filter by string concatenation:

String filter = "(&(uid=" + username + ")(password=" + password + "))";

An attacker supplies *)(uid=*))(|(uid=* as the username and an empty password:

(&(uid=*)(uid=*))(|(uid=*)(password=))

This creates a valid but tautological filter that always returns true — authentication bypass without knowing any valid credentials.

For data extraction, an attacker uses wildcard enumeration. Against a search endpoint:

GET /users?search=*)%28%7C%28sn%3D*

Decoded: *)(|(sn=* — which expands the filter to include all directory entries, leaking names, email addresses, group memberships, and phone numbers stored in the directory.

Active Directory attribute mining: inject *)(objectClass=user)(samAccountName=admin)(userPassword=* to probe for the admin account. Combined with blind boolean-based techniques (similar to blind SQL injection), attackers enumerate attribute values one character at a time.

Tools used in penetration testing include manual Burp Suite manipulation and custom Python scripts using the ldap3 library to iterate through filter mutations.

Impact

  • Authentication Bypass — Logging into applications without valid credentials using wildcard and boolean manipulation
  • User Enumeration — Extracting lists of all usernames, email addresses, and groups from the directory
  • Privilege Escalation — Discovering admin accounts, service accounts, and group memberships for targeted attacks
  • Sensitive Attribute Disclosure — Leaking phone numbers, employee IDs, manager hierarchies, and security group memberships
  • Active Directory Reconnaissance — Mapping trust relationships and delegation configurations useful in follow-on attacks

Detection

  1. Inject LDAP metacharacters — append *, )(, |, &, !, and ))( to login fields and search parameters. A change in application behavior (login success, different error message, expanded results) indicates injection.
  2. Test authentication bypass — try the classic payload *)(uid=*))(|(uid=* as the username with any password. A successful login confirms the vulnerability.
  3. Boolean-based blind testing — submit admin)(|(uid=a* vs admin)(|(uid=z* and compare response times and sizes to infer directory content one character at a time.
  4. Fuzz all directory search endpoints — employee lookups, user profile searches, and group management APIs are common injection points beyond just the login form.
  5. Use Burp Suite Intruder — insert the null byte %00 and common LDAP operators into each parameter and look for anomalous responses.
  6. Review LDAP query construction in source code — search for string concatenation adjacent to ldap_search, DirContext.search(), LdapConnection.Search(), or Net::LDAP.search.

Remediation

Use parameterized LDAP queries or proper escaping. Most LDAP libraries provide escaping utilities — use them consistently:

// Java — JNDI with proper escaping
String safeUser = LdapEncoder.nameEncode(username);
String filter = "(&(uid=" + safeUser + ")(objectClass=person))";
# Python — ldap3
from ldap3.utils.conv import escape_filter_chars
safe_user = escape_filter_chars(username)
search_filter = f"(&(uid={safe_user})(objectClass=person))"

Escape these characters per RFC 4515: \, *, (, ), and the null byte (\00). Replace them with their escaped form (\5c, \2a, \28, \29, \00).

Use bind DN authentication. Bind as the user (providing their full DN and password) rather than searching for them first. This eliminates filter injection in the authentication flow.

Apply least-privilege directory ACLs. The service account used by the application should only have read access to the specific OUs it needs. It should never have access to password attributes or privileged group memberships.

Validate input format. Usernames and email addresses have predictable formats. Allowlist-validate inputs before using them in any LDAP context.

Ready when you are
Scope a pentest in the next two minutes.
Start scoping