Defensive Programming Tips-2: LDAP Injection

Cenk Kalpakoğlu21 Jan 2021
Secure CodingAppSec

In the second part of our series, we will cover LDAP (Lightweight Directory Access Protocol) injection attacks

First, we will try to understand LDAP better, then we will discuss how to identify LDAP injection vulnerabilities and finally we will look at secure-by-default practices to prevent such vulnerabilities.

LDAP is a protocol for querying and modifying directory services running over TCP/IP.

The most widely used implementations of LDAP services are Microsoft ADAM (Active Directory Application Mode), OpenLDAP and SunOne Directory Server.

LDAP applications store and organize information in a structure based on a tree of directory entries which provides powerful browsing and searching capabilities.

This means you can even write complex “queries” for certain operations using “filters”. (see RFC 4515)

LDAP injection attacks are used to exploit web-based applications that construct LDAP statements based on user input.

It’s a fairly similar technique to SQL injection but the good news is that it’s much easier to detect in many ways.

That’s why it’s a good starting point for application security engineers to begin with their Threat Modelling(TM).

The most common problems that cause LDAP injections can be divided into three categories:

  • The lack of LDAP know-how
  • The lack of safer, parameterized LDAP query functions
  • The widespread use of LDAP to authenticate users

We can understand potential attack vectors by looking at the use cases of LDAP.

From an AppSec engineering perspective identifying potential entry points is crucial and the limited scope of LDAP makes it very easy to apply this approach.

For example, even though LDAP is mostly used for authentication, authorization is also another common use case that might make some internal services vulnerable to LDAP injection attacks in practice.

Now let’s go over a simple example. The following snippet executes a simple LDAP Search in Golang.

Defensive Programming Tips-2: LDAP Injection

At first glance**`baseDN`and`filter`**seem like dynamic inputs so we need to focus on those first. Also attributes parameter may be a variable for some other cases but this doesn’t necessarily mean it could be an injection point.

So, baseDN and filter parameters are potential “entry” points for this snippet. DN stands for distinguished name and might be something like:

ou=Physics Department, dc=Caltech, dc=edu

or

ou=Mathematics Department, dc=Caltech, dc=edu

In LDAP queries, baseDN is used to filter a group or a subgroup (e.g. to search all users in the physics department) and Filter is the query itself.

Depending on the LDAP adapter you are using, the query or “the filter” may be slightly different but the idea is the same.

Now, let’s trace the filter variable:

filter = "(&(objectClass=person)(|(sAMAccountName=\" + username + ")(mail="+ username +")))"

We can see clearly that the username has been passed to the filter variable without proper sanitization which leads to a trivial LDAP injection vulnerability here.

As an application security engineer, you should also be aware that the same vulnerability can be implemented in multiple ways.

In some cases developers tend to use wrappers (helper functions) or string formats as shown in the examples below:

filterDn = "(&(objectClass=person)(|(sAMAccountName={username})(mail={username})))"
...
filter = string.Replace(filterDn, "{username}", username -1)
filter = fmt.Sprintf("(&(objectClass=person)(|(sAMAccountName=%s)(mail=%s)))", username, username)

To prevent LDAP injection attacks, here is what you need to pay attention to as a software developer and as an AppSec engineer;

For developers:

  • Sanitization is always a good practice to prevent injection attacks and for LDAP following characters should always be filtered
    ( ) ! | & *.
    
  • Use of damage limitation strategies like whitelisting or field validation is encouraged.

For AppSec engineers:

The easiest way to prevent LDAP injection attacks is to scan your code with a SAST tool. However, as we have seen above the same vulnerability could be implemented in slightly different ways.

Most of the security scanners first parse the given code and create an abstract-syntax-tree (AST) and then run dozens of queries (patterns or anti-patterns) to identify vulnerabilities.

So as a best practice AppSec engineers should create their own rules to quickly check sensitive parts of the project which might lead to LDAP injection attacks.

Next time we will discuss static application security tests, AST parsers, source and sink concepts and how to develop some custom SAST rules.

Get A Demo