LDAP Injection
Inyección LDAP
Descripción
La inyección LDAP (LDAP Injection) implica explotar aplicaciones basadas en la web que generan sentencias LDAP utilizando la entrada del usuario. En los casos en que una aplicación no desinfecta adecuadamente la entrada del usuario, los atacantes pueden manipular las sentencias LDAP inyectando palabras clave especiales en la consulta, un ataque que es similar a la inyección SQL.
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.directory.*;
public class LDAPSearchExample {
public static void main(String[] args) {
// Entrada del usuario (reemplace esto con su propio mecanismo de entrada)
String userInput = "username"; // Entrada proporcionada por el usuario
// Parámetros de conexión LDAP
String ldapURL = "ldap://your-ldap-server:389";
String baseDN = "ou=users,dc=example,dc=com"; // Reemplace con su DN base
// Configurar el entorno para crear el contexto inicial
Hashtable<String, String> env = new Hashtable<>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, ldapURL);
try {
// Crear el contexto inicial
LdapContext ctx = new InitialLdapContext(env, null);
// Especificar el filtro de búsqueda
String searchFilter = "(uid=" + userInput + ")";
// Establecer los controles de búsqueda
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
// Realizar la búsqueda
NamingEnumeration<SearchResult> results = ctx.search(baseDN, searchFilter, searchControls);
// Iterar a través de los resultados de búsqueda
while (results.hasMore()) {
SearchResult result = results.next();
// Procesar el resultado según sea necesario (p. ej., imprimir atributos)
Attributes attributes = result.getAttributes();
System.out.println("User found: " + attributes.get("cn").get());
}
// Cerrar el contexto
ctx.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
const ldap = require('ldapjs');
const userInput = 'user123';
const ldapQuery = `(uid=${userInput})`; // Vulnerable a la inyección LDAP
const client = ldap.createClient({
url: 'ldap://example.com:389'
});
client.search('ou=users,dc=example,dc=com', {
filter: ldapQuery,
}, (err, res) => {
// Procesar resultados de búsqueda
res.on('searchEntry', (entry) => {
// Manejar la entrada
});
res.on('error', (err) => {
console.error('Error:', err.message);
});
});
<?php
// Código PHP vulnerable con inyección LDAP
$userInput = 'user123';
$ldapQuery = "(uid=$userInput)"; // Vulnerable a la inyección LDAP
$ldapconn = ldap_connect("ldap://example.com");
ldap_bind($ldapconn, "cn=admin,dc=example,dc=com", "adminpassword");
$result = ldap_search($ldapconn, "ou=users,dc=example,dc=com", $ldapQuery);
$entries = ldap_get_entries($ldapconn, $result);
// Procesar resultados de búsqueda
foreach ($entries as $entry) {
// Manejar la entrada
}
ldap_close($ldapconn);
?>
Recomendación
Para mitigar el riesgo de inyección LDAP, considere las siguientes recomendaciones:
-
Consultas parametrizadas: Use consultas parametrizadas en lugar de concatenación directa para construir consultas LDAP.
-
Validación / Desinfección de entrada: Implemente la validación de entrada para asegurarse de que la entrada del usuario se adhiera a los formatos esperados y no contenga caracteres especiales que puedan alterar las consultas LDAP. También desinfecte la entrada del usuario usando métodos como
LdapFilterEncode. -
Use frameworks que protejan automáticamente contra la inyección LDAP: Utilice bibliotecas o API de consulta LDAP bien establecidas y seguras que codifiquen automáticamente la entrada del usuario al crear consultas LDAP.
-
Habilitar autenticación Bind: Usar la autenticación bind limitará la superficie de ataque del servidor LDAP si un atacante logra realizar una inyección LDAP.
-
Privilegio mínimo: El principio de privilegio mínimo es una regla general recomendada para minimizar el impacto de los servicios comprometidos.
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.directory.*;
public class LDAPSearchMitigatedExample {
public static void main(String[] args) {
// Entrada del usuario (reemplace esto con su propio mecanismo de entrada)
String userInput = "username"; // Entrada proporcionada por el usuario
// Parámetros de conexión LDAP
String ldapURL = "ldap://your-ldap-server:389";
String baseDN = "ou=users,dc=example,dc=com"; // Reemplace con su DN base
// Configurar el entorno para crear el contexto inicial
Hashtable<String, String> env = new Hashtable<>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, ldapURL);
try {
// Crear el contexto inicial
LdapContext ctx = new InitialLdapContext(env, null);
// Usar consulta parametrizada para evitar inyección LDAP
String searchFilter = "(uid={0})";
Object[] filterArgs = {userInput};
// Establecer los controles de búsqueda
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
// Realizar la búsqueda
NamingEnumeration<SearchResult> results = ctx.search(baseDN, searchFilter, filterArgs, searchControls);
// Iterar a través de los resultados de búsqueda
while (results.hasMore()) {
SearchResult result = results.next();
// Procesar el resultado según sea necesario (p. ej., imprimir atributos)
Attributes attributes = result.getAttributes();
System.out.println("User found: " + attributes.get("cn").get());
}
// Cerrar el contexto
ctx.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
// Código JavaScript mitigado con validación de entrada y consulta parametrizada
const ldap = require('ldapjs');
const userInput = 'user123';
// Realizar validación de entrada para garantizar que userInput sea seguro para la consulta LDAP
if (isValidUserInput(userInput)) {
const ldapQuery = `(uid=${userInput})`;
const client = ldap.createClient({
url: 'ldap://example.com:389'
});
client.search('ou=users,dc=example,dc=com', {
filter: ldapQuery,
}, (err, res) => {
// Procesar resultados de búsqueda
res.on('searchEntry', (entry) => {
// Manejar la entrada
});
res.on('error', (err) => {
console.error('Error:', err.message);
});
});
} else {
console.log('Invalid userInput');
}
function isValidUserInput(userInput) {
// Implementar lógica de validación de entrada adecuada
// Por ejemplo, verificar caracteres permitidos, longitud, etc.
return /^[a-zA-Z0-9]+$/.test(userInput);
}
<?php
// Código PHP mitigado con validación de entrada y consulta parametrizada
$userInput = 'user123';
// Realizar validación de entrada para garantizar que userInput sea seguro para la consulta LDAP
if (isValidUserInput($userInput)) {
$ldapQuery = "(uid=$userInput)";
$ldapconn = ldap_connect("ldap://example.com");
ldap_bind($ldapconn, "cn=admin,dc=example,dc=com");
$result = ldap_search($ldapconn, "ou=users,dc=example,dc=com", $ldapQuery);
$entries = ldap_get_entries($ldapconn, $result);
// Procesar resultados de búsqueda
foreach ($entries as $entry) {
// Manejar la entrada
}
ldap_close($ldapconn);
} else {
echo 'Invalid userInput';
}
function isValidUserInput($userInput) {
// Implementar lógica de validación de entrada adecuada
// Por ejemplo, verificar caracteres permitidos, longitud, etc.
return preg_match('/^[a-zA-Z0-9]+$/', $userInput);
}
?>
Enlaces
Estándares
- GDPR:
- ART_25
- ART_32
- PCI_STANDARDS:
- REQ_6_2
- REQ_6_3
- REQ_6_4
- REQ_6_5
- SOC2_CONTROLS:
- CC_2_1
- CC_4_1
- CC_7_1
- CC_7_2
- CC_7_4
- CC_7_5
- HIPAA_CONTROLS:
- SECURITY212
- SECURITY213
- SECURITY255