Complimentary 90-day, on-prem license available for entities involved in Covid19 response.

What is LDAP Injection and How to Prevent It

Category: Web Security Readings - Last Updated: Fri, 13 Mar 2020 - by Zbigniew Banach

LDAP injection attacks exploit input validation vulnerabilities to inject and execute queries to Lightweight Directory Access Protocol servers. By supplying specially constructed user inputs to a vulnerable application, attackers can extract potentially sensitive information from an organization’s LDAP directory. LDAP services are crucial for the daily operation of many organizations, and a successful LDAP injection attack can provide valuable information for further attacks on systems and applications. In this article, we will look at how LDAP injection works and see how it can be prevented to improve web application security.

LDAP injection

The Importance of LDAP Servers

The Lightweight Directory Access Protocol, or LDAP, is an open application protocol for accessing and maintaining directory services in an IP network (see RFC 4511 for the specification). Organizations typically store information about users and resources in a central directory (such as Active Directory), and applications can access and manipulate this information using LDAP statements. In effect, LDAP servers are a gateway to a wealth of sensitive information, including user credentials, staff names and roles, shared network resources device and so on. Although less publicized than SQL injection attacks, LDAP injection attacks can yield valuable information about an organization’s internal infrastructure and potentially even provide attackers with access to database servers and other internal systems.

LDAP Statement Syntax

Clients can query an LDAP server by sending requests for directory entries that match specific filters. If entries are found that match the LDAP search filter, the server returns the requested information. Search filters used in LDAP queries follow the syntax specified in RFC 4515 (originally RFC 2254). Filters are constructed from any number of LDAP attributes specified as key-value pairs in parentheses. Filters can be combined using logical and comparison operators and can include wildcards. Here are a few examples:

  • (cn=John*) matches entries where the common name starts with John (* matches any character)
  • (!(cn=*Doe)) matches entries where the common name doesn’t end with Doe (! is logical NOT)
  • (&(cn=J*)(cn=*Doe)) matches entries where the common name starts with J and ends with Doe (& is logical AND)
  • (&(|(cn=John*)(cn=Jane*))(cn=*Doe)) matches entries where the common name starts with John or Jane and ends with Doe (| is logical OR)

Multiple filters and operators are combined using prefix notation (Polish notation), with arguments following the operator. For a full description of LDAP search filter syntax, see RFC 4515.

How LDAP Injection Works

As with SQL injection and related code injection attacks, LDAP injection vulnerabilities occur when an application inserts unsanitized user input directly into an LDAP statement. By crafting suitable string values using LDAP filter syntax, attackers can cause the LDAP server to execute a variety of queries and other LDAP statements. If combined with misconfigured or compromised permissions, LDAP injections may allow attackers to modify the LDAP tree and tamper with business-critical information.

While LDAP injections come in many shapes and sizes, here are two typical approaches:

  • Authentication bypass: Directory services are commonly used for user authentication and authorization, so the most basic LDAP injection attacks attempt to bypass password checking. Take the following vulnerable JavaScript code that directly assembles a simple LDAP filter from user inputs stored in the variables enteredUser and enteredPwd:

    filterContent = "(&(userID=" + enteredUser + ")(password=" + 
      enteredPwd + "))"

    For non-malicious users, the resulting filter should be something like:

    (&(userID=johndoe)(password=johnspwd))

    If this query is true, the user and password combination exists in the directory, so the user is logged in. However, an attacker can enter LDAP filter code as the user ID (shown in red) to create a filter that is always true, for example:

    (&(userID=*)(userID=*))(|(userID=*)(password=anything))

    This can allow the attacker to gain access without a valid user name or password.

  • Information disclosure: If a vulnerable application uses LDAP filters to provision shared resources, for example printers, an attacker performing recon might inject LDAP filter code to list all resources in the organization’s directory. Let’s say the following filter intended to list printers and scanners is assembled in an unsafe way:

    (|(resType=printer)(resType=scanner))

    If the attacker can enter another value instead of printer and knows that userID is used for user names in the directory, they might inject the following code:

    (|(resType=printer)(userID=*))(resType=scanner))

    This will list all printer and user objects, and the scanner part will be ignored by the server (only the first complete filter is processed).

Blind LDAP Injection

To directly query an LDAP server, the attacker needs to know (or guess) the attribute names so they can be specified in a filter. Blind LDAP injection is a more advanced exploitation technique for extracting unknown information by sending multiple requests and checking server responses to determine if the query is valid. Combined with additional optimizations and automation, this allows attackers to obtain information using a series of yes/no questions: a valid server response means “yes”, and a server error means “no”. Effective blind injection attacks typically involve several steps:

  • Attribute discovery: Attackers can query a variety of likely attributes and monitor server responses. If an attribute exists, the server will return a valid response. Otherwise, an error or empty response is returned. Let’s say an application unsafely constructs an AND filter to retrieve users, such as:

    (&(userID=John Doe)(objectClass=user))

    If the attacker can manipulate the user ID value, they can inject code like the following to check if user objects in this directory have a department attribute:

    (&(userID=John Doe)(department=*))(objectClass=user))

    If the department attribute exists (and John Doe is a valid user ID), the server will return a valid response. Otherwise, the attacker can try other attribute names.

  • Booleanization: Once an attribute name is known, the attacker can send a series of requests containing wildcards and/or comparison operators to determine specific attribute values. Again, only two server responses are considered, so booleanization is the process of transforming the search process into a series of true/false tests.

    Let’s say the department attribute from the previous example exists. To discover the department name, the attacker can start by injecting the following code to check the first letter:

    (&(userID=John Doe)(department=a*))(objectClass=user))

    A valid server response means that a department starting with the letter “a” exists. The attacker can continue the process for ab*, ac*, and so forth, to discover subsequent characters. For numeric values, the operators <= (less than or equal to) and >= (greater than or equal to) can be used to go through the likely value space.

  • Character set reduction: To minimize the number of requests, attackers can use multiple wildcards to find out which characters are present anywhere in the target value. For example, a valid server response for the following injection:

    (&(userID=John Doe)(department=*x*))(objectClass=user))

    means that a department name containing the letter “x” exists. If an error or empty response is returned, the attacker can eliminate this character from the scan. This can greatly reduce the number of requests needed to find the target value.

Preventing LDAP Injection in Web Applications

As with many other injection attacks, proper input validation and encoding in the application layer is critical to eliminate LDAP injection vulnerabilities. Every user input that might be used within LDAP queries should be sanitized according to application requirements and encoded to ensure that any remaining LDAP special characters are safely escaped, including at least ( ) ! | & *. The OWASP cheat sheet has more detailed information about escaping techniques. For maximum security and convenience, a ready framework or library should be used for escaping special characters and assembling LDAP filters.

Netsparker

Keep up with the latest web security
content with weekly updates.