La inyección LDAP puede ser particularmente peligrosa al ser explotada en sus mecanismos de autentificación. Los atacantes pueden manipular las queries LDAP para bypassear controles de seguridad ganando acceso a aplicaciones.

Por ejemplo, debajo está un trozo de código PHP simplificado usado en una aplicación web para la autentificación de usuarios en el servidor LDAP.

php
<?php
$username = $_POST['username'];
$password = $_POST['password'];

$ldap_server = "ldap://localhost";
$ldap_dn = "ou=People,dc=ldap,dc=thm";
$admin_dn = "cn=tester,dc=ldap,dc=thm";
$admin_password = "tester"; 

$ldap_conn = ldap_connect($ldap_server);
if (!$ldap_conn) {
    die("Could not connect to LDAP server");
}

ldap_set_option($ldap_conn, LDAP_OPT_PROTOCOL_VERSION, 3);

if (!ldap_bind($ldap_conn, $admin_dn, $admin_password)) {
    die("Could not bind to LDAP server with admin credentials");
}

// LDAP search filter
$filter = "(&(uid=$username)(userPassword=$password))";

// Perform the LDAP search
$search_result = ldap_search($ldap_conn, $ldap_dn, $filter);

// Check if the search was successful
if ($search_result) {
    // Retrieve the entries from the search result
    $entries = ldap_get_entries($ldap_conn, $search_result);
    if ($entries['count'] > 0) {
        foreach ($entries as $entry) {
            if (is_array($entry)) {
                if (isset($entry['cn'][0])) {
                    $message = "Welcome, " . $entry['cn'][0] . "!\n";
                }
            }
        }
    } else {
        $error = true;
    }
} else {
    $error = "LDAP search failed\n";
}
?>

Este código es vulnerable porque inserta directamente el input proporcionado por el usuario ($username y $password) en la query LDAP sin sanitizar ni escapar.

Para explotar esta vulnerabilidad, un atacante puede subir un nombre de usuario con un filtro LDAP malicioso. Por ejemplo, el atacante podría usar un nomber de usuario como *, lo que traducido a la query LDAP siempre se evalúa como true.

Esta query autentificará exitosamente si hay algún usuario en el directorio LDAP, ya que la condición inyectada uid=* siempre será true.


Técnicas de Bypass de Autentificación

Tautology-Based Injection

La inyección basada en tautología (repetición innecesaria y poco afortunada) involucra insertar condiciones en una query LDAP que son inherentemente ciertas, asegurando así que la query devuelve true. Este método es particularmente efectivo contra queries construuídas con el input del usuario sin sanitizar correctamente. Considera una query de autentificación LDAP donde el username y password se insertan desde el input del usuario.

php
(&(uid={userInput})(userPassword={passwordInput}))

Un atacante podría ofrecer un input tautology-based, como *)(|(& para userInput} y pwd) para {passwordInput}, lo que transforma la query en:

php
(&(uid=*)(|(&)(userPassword=pwd)))

Esta query bypassea la comprobación de la contraseña debido a cómo los operadores lógicos se usan en el filtro. La query consiste en dos partes, uso combinado y el operador AND (&).

  1. (uid=*): Esta parte del filtro coincide con cualquier entrada con un atributo uid, es decir, todos los usuarios.
  2. (|(&)(userPassword=pwd)): El operador OR (|) significa que cualquiera de las dos condiciones dentro necesita ser true para sobrepasar el filtro. En LDAP, una condición AND (&)vacía se considera siempre true. La otra condición comprueba si el atributo userPassword coincide con el valor pwd, que fallará si el usuario no usa pwd como contraseña.

Poniéndolo todo junto, la segunda parte del filtro (|(&)(userPassword=pwd)) siempre será true debido a la condición (&). El operador OR sólo necesita que una de sus condiciones sea true, por lo que el OR entero es true sin importar la contraseña.

Wildcard Injection

los wildcards (*) se utilizan en las queries LDAP para coincidir con cualquier secuencia de caracteres, haciéndolos herramientas poderosas para búsquedas amplias. Sin embargo, cuando el input del usuario que contiene wildcards no se sanitiza correctamente, puede llevar a resultados de query no intencionados, como bypassear la autentificación. Por ejemplo, si la query de búsqueda se ve así:

php
(&(uid={userInput})(userPassword={passwordInput}))

Un atacante piede usar un wildcard como input en ambos uid y password. Usar * en el nomber de usuario puede hacer que la query ignore nombres específicos y se centre en la password. Sin embargo al haber un wildcard (*) presente en la contraseña, no valida el contenido de esta contra un valor esperado. En su lugar sólo comprueban la existenca del atributo userPassword sin importar su contenido.

Esto significa que la query devolverá un resultado positivo para cualquier usuario sin verificar que la contraseña dada durante el proceso de autentificación coincide con la contraseña guardada.


Ejemplo de Bypasseo de Autentificación

Para demostrar un ataque simple de inyección LDAP, ve a http://IP/normal.php. Basado en el código de arriba, la aplicación construye una query LDAP para la autentificación basada en el input del usuario sin la sanitización adecuada.

Un atacante puede explotar esto subiendo un username y una password con un caracter que la aplicación no espera, como un asterisco para los atributos uid y userPassword. Esto hace que la condición siempre se evalue en true, bypasseando la comprobación de contraseña.

Username y Password Inyectados

php
username=*&password=*

Exploiting LDAP

Componente Resultante de Query LDAP

php
(&(uid=*)(userPassword=*))

Exploiting LDAP

Esta inyección siempre hace que la condición de la query LDAP sea true. Sin embargo, usar sólo el caracter * resultará siempre en el primer resultado. Para apuntar a información específica, el atacante puede usar un payload como f*, lo que buscará un uid que comience por f.

Exploiting LDAP