Why is this an issue?
LDAP injections occur in an application when the application retrieves untrusted data and inserts it into an LDAP query without sanitizing it
first.
An LDAP injection can either be basic or blind, depending on whether the server’s fetched data is directly returned in the web application’s
response.
The absence of the corresponding response for the malicious request on the application is not a barrier to exploitation. Thus, it must
be treated the same way as basic LDAP injections.
What is the potential impact?
In the context of a web application vulnerable to LDAP injection: after discovering the injection point, attackers insert data into the vulnerable
field to execute malicious LDAP commands.
The impact of this vulnerability depends on how vital LDAP servers are to the organization.
Below are some real-world scenarios that illustrate some impacts of an attacker exploiting the vulnerability.
Data leakage or corruption
In typical scenarios where systems perform innocuous LDAP operations to find users or create inventories, an LDAP injection could result in data
leakage or corruption.
Privilege escalation
A malicious LDAP query could allow an attacker to impersonate a low-privileged user or an administrator in scenarios where systems perform
authorization checks or authentication.
Attackers use this vulnerability to find multiple footholds on target organizations by gathering authentication bypasses.
How to fix it in Core PHP
Code examples
The following noncompliant code is vulnerable to LDAP injection because untrusted data is concatenated to an LDAP query without prior sanitization
or validation.
Noncompliant code example
$ldapconn = ldap_connect("localhost");
if($ldapconn){
$user = $_GET["user"];
$filter = "(&(objectClass=user)(uid=" . $user . "))";
$dn = "dc=example,dc=org";
ldap_list($ldapconn, $dn, $filter); // Noncompliant
}
Compliant solution
$ldapconn = ldap_connect("localhost");
if($ldapconn){
$user = $ldap_escape($_GET["user"], "", LDAP_ESCAPE_FILTER);
$filter = "(&(objectClass=user)(uid=" . $user . "))";
$dn = "dc=example,dc=org";
ldap_list($ldapconn, $dn, $filter);
}
How does this work?
As a rule of thumb, the best approach to protect against injections is to systematically ensure that untrusted data cannot break out of the
initially intended logic.
For LDAP injection, the cleanest way to do so is to use parameterized queries if it is available for your use case.
Another approach is to sanitize the input before using it in an LDAP query. Input sanitization should be primarily done using native libraries.
Alternatively, validation can be implemented using an allowlist approach by creating a list of authorized and secure strings you want the
application to use in a query. If a user input does not match an entry in this list, it should be rejected because it is considered unsafe.
Important note: The application must sanitize and validate on the server-side. Not on client-side front-ends.
The most fundamental security mechanism is the restriction of LDAP metacharacters.
For Distinguished Names (DN), special characters that need to be escaped include:
For Search Filters, special characters that need to be escaped include:
For PHP, the core library function ldap_escape
allows sanitizing
these characters.
In the compliant solution example, the ldap_escape
function is used with the LDAP_ESCAPE_FILTER
flag, which sanitizes
potentially malicious characters in the search filter. The function can also be used with the LDAP_ESCAPE_DN
flag, which sanitizes the
distinguished name (DN).
How to fix it in Symfony
Code examples
The following noncompliant code is vulnerable to LDAP injection because untrusted data is concatenated to an LDAP query without prior sanitization
or validation.
Noncompliant code example
use Symfony\Component\Ldap\Ldap;
use Symfony\Component\Ldap\LdapInterface;
private function userLookup(Ldap $conn, Request $request)
{
$user = $request->query->get('user');
$conn->bind("cn=example,dc=example,dc=org", "example");
$query = $conn->query('dc=example,dc=org', '(&(objectclass=user)(uid=' . $user . '))'); // Noncompliant
$query->execute();
}
Compliant solution
use Symfony\Component\Ldap\Ldap;
use Symfony\Component\Ldap\LdapInterface;
private function userLookup(Ldap $conn, Request $request)
{
$user = $conn->escape($request->query->get('user'),'', LdapInterface::ESCAPE_FILTER);
$conn->bind("cn=example,dc=example,dc=org", "example");
$query = $conn->query('dc=example,dc=org', '(&(objectclass=user)(uid=' . $user . '))');
$query->execute();
}
How does this work?
As a rule of thumb, the best approach to protect against injections is to systematically ensure that untrusted data cannot break out of the
initially intended logic.
For LDAP injection, the cleanest way to do so is to use parameterized queries if it is available for your use case.
Another approach is to sanitize the input before using it in an LDAP query. Input sanitization should be primarily done using native libraries.
Alternatively, validation can be implemented using an allowlist approach by creating a list of authorized and secure strings you want the
application to use in a query. If a user input does not match an entry in this list, it should be rejected because it is considered unsafe.
Important note: The application must sanitize and validate on the server-side. Not on client-side front-ends.
The most fundamental security mechanism is the restriction of LDAP metacharacters.
For Distinguished Names (DN), special characters that need to be escaped include:
For Search Filters, special characters that need to be escaped include:
For Symfony, the LDAP component method escape
allows sanitizing these
characters.
In the compliant solution example, the Ldap::escape
method is used with the ESCAPE_FILTER
flag, which sanitizes
potentially malicious characters in the search filter. The function can also be used with the ESCAPE_DN
flag, which sanitizes the
distinguished name (DN).
Symfony also provides an ad-hoc alternative for user lookup called LDAP User Provider
. As opposed to the LDAP
component, the LDAP User Provider handles already user input sanitization.
Resources
Standards