LDAP Injection

ID

php.ldap_injection

Severity

critical

Resource

Injection

Language

Php

Tags

CWE:90, NIST.SP.800-53, OWASP:2021:A3, PCI-DSS:6.5.1

Description

LDAP Injection occurs when user-controlled input is improperly incorporated into LDAP queries, allowing attackers to modify the query logic and potentially access or manipulate unauthorized data.

Rationale

LDAP Injection is a security vulnerability that arises when an application dynamically constructs LDAP queries using unsanitized user input. If an attacker injects special LDAP characters, they can alter the intended query logic, bypass authentication mechanisms, or extract sensitive data from the directory service.

Consider the following vulnerable PHP code, which attempts to authenticate a user via LDAP:

<?php
  $ldapconn = ldap_connect("ldap://example.com");

  if (!$ldapconn) {
    die("Could not connect to LDAP server.");
  }

  ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);

  $username = $_POST['username'];
  $password = $_POST['password'];

  // Vulnerable query construction
  $filter = "(&(uid=$username)(userPassword=$password))";

  $search = ldap_search($ldapconn, "dc=example,dc=com", $filter);
  $result = ldap_get_entries($ldapconn, $search);

  if ($result["count"] > 0) {
    echo "Authentication successful.";
  } else {
    echo "Invalid username or password.";
  }

An attacker can exploit this by entering )(uid=) as the username, effectively modifying the query to retrieve all users, potentially bypassing authentication.

This effectively broadens the search filter beyond the intended scope, potentially exposing all entries in the directory.

Remediation

To mitigate LDAP Injection in PHP, the following best practices should be applied:

  1. Escape User Input: Use ldap_escape() to properly sanitize user input before inserting it into LDAP queries.

  2. Use Parameterized Queries: If supported by the LDAP library, prefer prepared queries.

  3. Limit Query Scope: Avoid exposing unnecessary attributes and restrict LDAP searches to specific organizational units.

  4. Authenticate Securely: Instead of searching for a user via ldap_search(), use ldap_bind() for authentication.

Here is the secure version of the previous example:

<?php
  $ldapconn = ldap_connect("ldap://example.com");
  $ldapconn = ldap_connect("ldap://example.com");

  if (!$ldapconn) {
    die("Could not connect to LDAP server.");
  }

  ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);

  $username = ldap_escape($_POST['username'], "", LDAP_ESCAPE_FILTER);
  $password = $_POST['password'];

  // Secure authentication using ldap_bind
  $bind_dn = "uid=$username,ou=users,dc=example,dc=com";
  $bind = @ldap_bind($ldapconn, $bind_dn, $password);

  if ($bind) {
    echo "Authentication successful.";
  } else {
    echo "Invalid username or password.";
  }

By using ldap_escape(), we ensure that special characters are properly escaped, preventing attackers from altering LDAP queries. Additionally, ldap_bind() is used instead of ldap_search() for authentication, reducing the attack surface significantly.

Configuration

The detector has the following configurable parameters:

  • sources, that indicates the source kinds to check.

  • neutralizations, that indicates the neutralization kinds to check.