Sécuriser aujourd'hui

Protéger demain

Introduction

Afin de bien comprendre les injections LDAP, il est nécessaire de revenir aux bases et donc à son fonctionnement. LDAP (Lightweight Directory Access Protocol) est un protocole permettant la communication avec des annuaires (comme un Active Directory) et de les interroger.

LDAP permet de stocker des informations comme une base de données. Ainsi on affecte à chaque objet une série d'attributs qui permet de les définir :

dn: cn=doe,dc=domain,dc=com
objectclass: inetOrgPerson
cn: doe
sn: Doe John
userpassword: SomePassword
mobile: 0601010101
description: Pentester

On stocke alors tous les objets dans une structure d'arbre, et on recherche un objet en parcourant les branches:

Recherche dans l'annuaire

Pour rechercher dans un annuaire LDAP, on utilise des filtres, qui permettent de chercher dans tous les objets. Ces filtres se construisent à partir d'opérateur (AND, OR, NOT ...) et de vérification de la valeur d'un attribut (name=Dupuit ...).

(&(objectClass=person)(!(objectClass=computer)))

Comme en SQL, il est ainsi possible de faire des requêtes très précises et la structure d'arbre est optimisé pour la recherche d'objets.

Filtres LDAP

Afin de bien comprendre comment réaliser une injection LDAP, il est nécessaire de voir quelques règles et opérateurs importants sur les filtres :

  • "(&)" correspond à TRUE et "(|)" correspond à FALSE
  • L'opérateur "*" correspond à n'importe quelle chaine de caractère. Ainsi "John*" correspond à toutes les chaines de caractères commençant par "John"

injection

De la même manière que les requêtes SQL, il est possible d'injecter dans une requête LDAP si celle-ci est mal préparée. Prenons l'exemple d'une authentification. En SQL, la requête ressemblerait à :

SELECT username, password
FROM users
WHERE username='input login' and password ='input password';

Pour une requête LDAP le filtre ressemblerait à :

(&
(objectClass=inetOrgPerson)
(cn='input login')
(userpassword='input password')
)

Comme pour l'exploitation d'injection SQL, il est possible avec les filtres LDAP de contourner le mécanisme d'authentification, et avec une technique plus élaborée de récupérer la valeur des attributs de certains objets. Nous allons voir plus en détail les 2 manières les plus communes d'exploiter cette vulnérabilité.

Exploitation : Bypass d'authentification

Une des principales manières d'exploiter une injection LDAP est le contournement d'authentification. Un peu à la manière d'une injection SQL, on essaie d'ajouter dans les filtres une directive "OU VRAI" dans la requête d'authentification afin que celle-ci retourne au moins un utilisateur.

Avec les filtres LDAP cela est possible de plusieurs manières, la plus simple est de tout simplement mettre un "*" dans les champs d'authentification.

Ainsi le filtre deviendra:

(&
(objectClass=inetOrgPerson)
(cn=*)
(userpassword=*)
)

Ce filtre retournera tous les utilisateurs car le caractère * correspond à toutes les chaines de caractères, et on contournera alors potentiellement l'authentification.

On pourrait alors imaginer se prémunir de ce genre d'attaque en filtrant le caractère * dans la requête. On pourrait toujours injecter d'une autre manière, en incluant de nouvelles conditions dans les filtres.

On peut imaginer mettre les valeurs suivantes dans les champs d'authentification :

  • admin)(|(&
  • password)

Ainsi le filtre serait alors :

(&
(objectClass=inetOrgPerson)
(cn=admin)
(|
(&)
(userpassword=password)
)
)

On peut voir le résultat de la requête en regardant chaque filtre séparément :

  • Le premier filtre permet de récupérer les objets personnes de l'annuaire
  • Le deuxième filtre récupère un objet ayant pour cn (common name) admin, on récupère alors l'administrateur
  • Le troisième filtre ne fait rien, car c'est un filtre OU avec une directive vraie absolue. On contourne alors le filtre sur le mot de passe

La requête renvoie alors les informations liées à l'administrateur et permet de contourner l'authentification.

Exploitation : Récupération de données (LDAP injection en aveugle)

Outre le fait de contourner un système d'authentification ou de permission, une injection LDAP peut permettre de récupérer les données de certains champs et objets qui devraient être inaccessibles. Reprenons le cas du filtre d'authentification pris précédemment, on peut tenter de récupérer le numéro de téléphone de l'admin pour l'exemple (stocké dans l'attribut "mobile").

Dans un premier temps on peut vérifier que cet attribut existe. Pour cela on reprend un moyen de contourner l'authentification en mettant des "\*" dans les champs. On injecte ensuite un nouveau champ dans les filtres :

  • login: *)(mobile=*
  • password : *

Les filtres deviennent alors :

(&
(objectClass=inetOrgPerson)
(cn=*)
(mobile=*)
(userpassword=*)
)

Si la requête permet de nous connecter alors le champ "mobile" existe bien et il sera ensuite possible de récupérer sa valeur. Si on a un échec de connexion alors c'est que la requête a renvoyé une erreur et que ce champ n'existe pas (Il est donc possible de Fuzzer les attributs des personnes).

Une fois les attributs identifiés, on peut récupérer leurs valeurs en utilisant le caractère "*". En effet en mettant "a*" par exemple, on cible les attributs dont la valeur commence par "a", on peut donc tester tous les caractères possibles suivis d'une étoile pour trouver le premier caractère du champ mobile.

Ici on trouve que le login "*)(mobile=0*" permet de se connecter, on en déduit que le premier caractère du champ mobile commence par un "0" (ce qui semble logique en effet).

Pour trouver le second caractère, on teste l'ensemble des caractères entre "0" et "*", on trouve alors que le login "*)(mobile=06*" permet de se connecter. On fait de même pour les caractères suivants et on sera alors en mesure de récupérer tout l'attribut.

Remédiation

Deux principales manières existent pour se prémunir de ce genre d'attaques :

  • Filtrer les champs utilisateurs. En effet, certains caractères spéciaux ne devraient pas être autorisés dans les champs utilisateurs, ainsi un des caractères spéciaux est présent, il doit être échappé. Voici la liste des caractères à mettre en liste noire * ( ) \ NUL .
  • Si vous utilisez .NET, il est possible d'utiliser le framework LINKtoAD. Celui-ci permet d'utiliser une librairie qui traduira les différents arguments en filtres LDAP prévenant toute injection.

Conclusion

Les injections LDAP, bien plus méconnues que les injections SQL, sont particulièrement dangereuses. Elles permettent en effet de contourner les mesures de contrôle d'accès et même de récupérer les données présentes dans l'annuaire. Ce risque ne doit donc pas être sous estimé quand on fait le choix d'utiliser cette technologie, d'autant plus que les remédiations ne sont pas très dures à mettre en place.