Introducing Qwiet AI AutoFix! Reduce the time to secure code by 95% Read More

Who are you? Who? Who? If you’ve ever hummed that song to yourself when coding, then you already know the fundamental use case for the Lightweight Directory Access Protocol (LDAP). LDAP is the protocol that communicates access and authentication data across various technologies. As a vendor-neutral, open protocol, LDAP works with proprietary directory tools, like Microsoft Active Directory (AD), and other programs, including Linux-based technologies. Essentially, when users authenticate into an application, the client sends a request containing the user’s credentials to the LDAP server. The LDAP server receives the request and verifies these credentials against its database. If everything matches up, the LDAP server knows who the user is and grants access to the application. 

Many organizations use LDAP as part of their single sign-on processes, meaning that threat actors look for exploitable vulnerabilities that enable them to gain unauthorized access to systems, networks, and data. For developers, knowing how to mitigate LDAP exploit risks is critical to protecting an application’s security. 

What is an LDAP vulnerability?

The LDAP protocol itself isn’t inherently insecure, but the implementation can lead to security weaknesses that attackers then exploit. Typically, LDAP vulnerabilities arise from how developers write the queries that an application uses to ask the directory service for user information. 

LDAP uses a hierarchical tree structure called a directory information tree (DIT) to organize entries across various subcategories, like users, groups, servers, or applications. Although only one root exists, the various branches can be nested. The leaves, like users, have attributes but no subordinate entities. 

LDAP filters define the search request criteria, defining or restricting who can access an application. An LDAP vulnerability often  defines the following ten basic filters:

    • Presence: whether an entry contains a specified attribute and is constructed as “(attribute description = *)”, like (objectClass=*)
    • Equality: whether an entry contains a specified attribute value and is constructed as “(attribute description = value to compare)”, like (givenName=Karen)
    • Greater-or-equal:  whether an entry contains at least one value for an attribute that is equal to or greater than the value and is constructed as “(attribute description >=value)”, like (targetAttribute>=3)
    • Less-or equal: whether an entry contains at least one value for an attribute that is equal to or less than the value and is constructed as “(attribute description <=value)”, like (targetAttribute<=3)
    • Substring: whether an entry contains at least one value for a specified attribute that matches a substring assertion and is constructed as “(attribute description = initial component * additional components * final component)”, like (givenName=*Karen*Smith*)
    • Approximate match: whether an entry contains at least one value for a specified attribute that is approximately equal to a value and is constructed as “(attribute description ~= comparison value)”, like (givenName~=Jane) would look for “Karen” or “Karin”
    • Extensible match: the ability to override default matching rule, look for a particular value in any attribute in an entry, or look for a particular value in the attribute and is constructed as “(optional attribute description : = comparison value)”, like (givenName:caseExactMatch:=Karen) to identify entry where Karen is the value for givenName attribute 
  • AND: a combination of zero or more filters that only returns a response that includes all of them and is constructed as “(&(attribute 1)(attribute 2))”, like (&(givenName=Karen)(department=Accounting))
  • OR: a combination of zero or more filters that returns a response where at least one is true and is constructed as “(| (attribute 1) (attribute 2))”, like (|(givenName=Karen) (givenName=Karin) (givenName=Caryn))
  • NOT: one filter component, including AND or OR filters, that returns all results without the given filter component and is constructed as “( ! (filter component))”, like (!(givenName=Karen)) would return all entries that do not include Karen as the givenName

When the application fails to filter parameters appropriately, attackers can inject malicious code or execute arbitrary commands.

How an LDAP injection attack works

Often, the LDAP message contains sensitive data, but the protocol has no inherent security or protections. When the application fails to sanitize user input, attackers can modify the statements, similar to how they engage in SQL injection attacks. 

Some typical LDAP attack types include:

    • Access control bypass: Attackers manipulate a login page by supplying a valid givenName with an AND statement that tells the LDAP server to process only the first filter, enabling them to bypass the access control. 
    • Privilege escalation: Attackers manipulate a query that returns a document list by injecting a Presence filter in conjunction with an AND filter to identify high-value documents
  • Information disclosure: Attackers manipulate the resource strings by injecting a Presence filter and defining a resource type.

In a blind LDAP injection, the attackers use the server responses to make inferences by asking true and false questions, like a game of Guess Who.  A blind LDAP attack typically involves the multiple steps like the following:

  • Querying various attributes to determine whether they exist or not based on the true/false response. For example, they may try to determine whether someone named Karen is a user by using (&(givenName=Karen)(objectClass=User). 
  • Determining whether the directory includes department attributes by using (&(givenName=Karen)(department=*)(objectClass=user)
  • If Karen is a valid user and the department attribute exists, then the server returns a valid response. 
  • Using wildcards or comparison operators to identify different department data, like (&(realName=Karen)(department=a*))(objectclass=user))
  • Using multiple wildcards to get answers faster, like (&(realName=Karen)(department=*count*))(objectclass=user))

 

Mitigating LDAP Exploit Risks

The Open Worldwide Application Security Project (OWASP) suggests the following three defense options for developers. 

Escape all variables

Escaping typically uses either a back slash or double quote to tell the application to interpret the character string as text rather than a closed string. Typically, you should apply this just before the content that will pass to the target interpreter. 

When mitigating risks related to LDAP vulnerabilities, you should use the following:

  • Distinguished name (DN) escaping: LDAP uses DN to store names, similar to a unique identifier, meaning that attackers can use them to access resources.
  • Search filter escaping: Every DN points to one entry so you must escape any untrusted data added to LDAP queries in application code when sanitizing a search filter input or using a DN as a username-like credential for resource access.

Use frameworks that automate output encoding

Output encoding prevents the browser from interpreting user-supplied or untrusted data, preventing attacks by converting special characters into plain text. For example, output encoding would read “&” as the word “and” rather than a command. 

Frameworks and templating engines that automatically default to safe output encoding include:

  • ReactJS
  • AngularJS 
  • Handlebars
  • LiquidJS
  • Rails
  • Java Encoder Project
  • .Net 

Additional defenses

OWASP suggests adopting both of the above defenses as well as the following two additional ones:

    • Least privilege: Minimize the privileges assigned to the LDAP binding account
    • Enabling bind authentication: Configuring protocol with bind authentication that requires verifications and authorization checks against valid credentials
  • Allow-list validation: Defining a set of values for any given input that could come from untrusted sources

 

Qwiet AI: Real-Time Visibility into Exploitable Vulnerabilities

With Qwiet AI’s preZero platform, you can check for vulnerabilities in millions of lines of code in minutes, enabling you to get the accurate and detailed findings necessary to protect your application from LDAP injections. 

PreZero identifies vulnerabilities and then adds context to help you prioritize remediation activities by giving you visibility into the ones attackers can actually exploit. Using Qwiet AI, you can eliminate thousands of false positives for a noise-free list that prioritizes your riskiest code, enabling faster time-to-market. 

Take our preZero platform for a free spin to see how Qwiet AI can help you identify and remediate race condition vulnerabilities. 

About ShiftLeft

ShiftLeft empowers developers and AppSec teams to dramatically reduce risk by quickly finding and fixing the vulnerabilities most likely to reach their applications and ignoring reported vulnerabilities that pose little risk. Industry-leading accuracy allows developers to focus on security fixes that matter and improve code velocity while enabling AppSec engineers to shift security left.

A unified code security platform, ShiftLeft CORE scans for attack context across custom code, APIs, OSS, containers, internal microservices, and first-party business logic by combining results of the company’s and Intelligent Software Composition Analysis (SCA). Using its unique graph database that combines code attributes and analyzes actual attack paths based on real application architecture, ShiftLeft then provides detailed guidance on risk remediation within existing development workflows and tooling. Teams that use ShiftLeft ship more secure code, faster. Backed by SYN Ventures, Bain Capital Ventures, Blackstone, Mayfield, Thomvest Ventures, and SineWave Ventures, ShiftLeft is based in Santa Clara, California. For information, visit: www.shiftleft.io.

Share