LDAP injection

Improper sanitization of LDAP queries

Python

LDAP injection: the basics

What is LDAP injection?

LDAP injection is, at heart, quite similar to SQL injection. LDAP is a look-up protocol for information stored about an organization. It also has an authentication system, as much of this information can be confidential or private. However, if not implemented correctly, LDAP authentication can be circumvented and/or cause some nasty information disclosure problems.

About this lesson

In this lesson, you will learn how LDAP injection works and how to prevent the unauthenticated from becoming illegitimately authenticated. We will first inspect a sample Python program that is vulnerable to an LDAP injection attack, then explore how this vulnerability arises, its mutations, and how to prevent it from happening in your codebase.

FUN FACT

Polish Notation

The syntax for LDAP is derived from a notation called “Polish notation”, where the operator prefixes the operands. For example, if the operation were addition, then we would traditionally write 2 + 3, however, in Polish notation, this would be written as + (2 3).

LDAP injection in action

Hacking into EvilCorp

EvilCorp has come to the realization that even evil companies need to keep track of all their employees. Outsourcing is hard (harder when you’re evil), so they have resorted to developing an internal tool to store information about their employees for them — and it uses LDAP!

Ironically, evil things even happen to evil companies, and a disgruntled employee (you, specifically) found their application to be vulnerable to LDAP injection.

Hacking EvilCorp

  • STEP 1
  • STEP 2
  • STEP 3
  • STEP 4
  • STEP 5

Setting the stage

Sitting down for your morning coffee, you want to know how much data EvilCorp has about you. You know the endpoint, so you start investigating.

ldap-start.svg

Let’s take a look at what went wrong with EvilCorp’s backend.

LDAP injection under the hood

How are LDAP queries constructed?

LDAP is a hierarchical information lookup protocol where the query parameters filter out content. As mentioned in the fun fact earlier, these LDAP queries are formatted using “Polish notation”. Comparisons in LDAP queries are of the form:

(field=value)

If we wanted to query an LDAP server for all information relating to Jedi who were either a “master” or who fought in the clone wars and are still alive, we could query a server with:

(|(jediType=master)(&(cloneWars=yes)(alive=yes))

Breaking this query down, the operator (|, which means or) comes first, followed by its two arguments. The first argument compares the input (right), with the category (jediType). The second argument is another operator, which checks to filter for all subjects who fought in the clone wars and are still alive. Darth Vader could probably find a use case for this query…

FUN FACT

Standardization time!

The LDAP search filters are so important they get their own RFC! Check out the details here.

Where does the vulnerability come in?

LDAP injection is similar in spirit to SQL injection because they both come from the same error: missing input sanitization! When user input is passed straight into an LDAP query without proper sanitization, then the user can make their own modifications to the query being made, and introduce their own logic!

To illustrate this, let's have a look at a function in Python that might handle an LDAP query request:

This function retrieves the URL parameter jediType and directly substitutes it into the LDAP search query. If you make a curl request to get master Jedis (or interact with a website that does this for you), then your request might look something like:

https://darth.vader.site/jediFinder?jediType=master

Which would produce the LDAP query we saw earlier:

(|(jediType=master)(&(cloneWars=yes)(alive=yes))

However, if we instead submitted something a little bit different:

https://darth.vader.site/jediFinder?jediType=*)(cloneWars=*)

Then the request would look like:

(|(jediType=*)(cloneWars=*))(&(cloneWars=yes)(alive=yes))

This would then be interpreted by the LDAP server as a request for everything that matches any type of jedi or had any relation to the clone wars! I’m sure Vader wouldn’t want his lowly stormtroopers having access to his personal database, so how would he stop them doing so?

Scan your code & stay secure with Snyk - for FREE!

Did you know you can use Snyk for free to verify that your code
doesn't include this or other vulnerabilities?

Scan your code

LDAP injection mitigation

Sanitizing user input

Lucky for us, the remedy for LDAP injection is fairly simple: don’t blindly accept user input! To prevent LDAP injection, we escape the characters which would permit a user to modify the request.

The LDAP library in Python provides us with some utility for filtering out these unwanted characters, through the escape_filter_chars method. More information about the API for LDAP filtering can be found here.

We can then take our example above and safely sanitize the user input to remove the vulnerability!

FUN FACT

Blind LDAP injections

LDAP injections are cool and all, but their lesser-known associate, blind LDAP injections, are in a class of their own. They arise when the user cannot see the results of their requests, but can somehow still infer information about what exists in an LDAP directory (e.g., through error messages or timing information). Unsurprisingly, this vulnerability is also closely associated with blind SQL injections!

Keep learning

To learn more about LDAP injections, check out some other great content produced by Snyk: