모의해킹&웹취약점진단/주•통기반 웹 취약점 점검

03. LDAP 인젝션

sheow13 2023. 12. 26. 13:18
728x90

 개요

- 응용 프로그램이 사용자 입력 값에 대한 적절한 필터링 및 유효성 검증을 하지 않아 공격자는 로컬 프록시를 사용함으로 LDAP 문의 변조가 가능하며, 공격 성공 시 승인되지 않은 쿼리에 권한을 부여하고, LDAP 트리 내의 내용 수정이나 임의의 명령 실행등이 가능한 취약점

- 해당 공격을 통해 로그인 인증 우회, 권한 관리 우회, 정보 공개 등을 목적으로 진행

- 주요정보통신기반시설 취약점 진단 기준으로 03. LDAP 인젝션 해당

 

 

 

LDAP란?

- LDAP(Lightweight Directory Access Protocol)은 사용자가 조직, 구성원 등에 대한 데이터를 찾는 데 도움이 되는 프로토콜로, LDAP는 LDAP 디렉터리에 데이터를 저장하고 사용자가 디렉터리에 액세스할 수 있도록 인증하기 위해 주로 사용

 

 LDAP 쿼리 문법 구조

[https://book.hacktricks.xyz/pentesting-web/ldap-injection 참조]

- LDAP 쿼리는 기본적으로 &(AND)와 |(OR)를 사용하여 쿼리문을 구성

- (&) : 무조건 참값이라는 특수 상수

- (|) : 무조건 거짓이라는 특수 상수

- (&(조건1)(조건2)) : 조건 1과 조건2를 모두 만족하는 값을 조회

- (|(조건1)(조건2)) : 조건 1 또는 조건2를 만족

 

 LDAP Injection 예시

예시 1
user=admin)(&)
pw=임의의 값
실제 쿼리 문: (&(User=admin)(&))(PASSWORD=Pwd))
-> user IDadmin이고, 무조건 참(&)을 만족하는 값으로, 이후 조건값인 패스워드 입력과 상관없이 무조건 참으로 admin 계정으로 접근 가능

 

예시 2
user=*
password=*
실제 쿼리문 : (&(user=*)(password=*))
-> user 모두(*)와 패스워드 모두(*)를 만족하는 값으로, 로그인을 우회하여 접근 가능

 

LDAP Injection Cheat Sheat

예시
*
*)(&
*))%00
)(cn=))\x00
*()|%26'
*()|&'
*(|(mail=*))
*(|(objectclass=*))
*)(uid=*))(|(uid=*
*/*
*|
/
//
//*
@*
|
admin*
admin*)((|userpassword=*)
admin*)((|userPassword=*)
x' or name()='username' or 'x'='y

 

 LDAP Injection 점검 방법

수동 점검

- 웹사이트의 사용자 인수 값을 입력받은 애플리케이션에 LDAP Injection Cheat Sheet 입력 후, 에러 페이지 또는 특이사항이 발생하는지 확인

 

자동화 도구를 통한 점검

- 자동화 도구를 사용하여 점검하고자 하는 사이트에 LDAP Injection 취약 여부 점검

- 아래 예시는 Burp Suite Professional Active Scan을 예시로 들었으며, 자세한 사항은 점검 도구 Tab에서 burp suite 참고

 

LDAP 대응방안

1. 시큐어코딩을 통해 LDAP 질의문에 특수문자가 들어가지 않도록 설정

from ldap3 import Connection, Server, ALL
from ldap3.utils.conv import escape_filter_chars
from django.shortcuts import render

config = {
	"bind_dn": "cn=read-only-admin,dc=example,dc=com",
	"password": "password",
}

def ldap_query(request):
	search_keyword = request.POST.get('search_keyword','')

	dn = config['bind_dn']
	password = config['password']
	address = 'ldap.goodsource.com' server = Server(address, get_info=ALL)
	conn = Connection(server, dn, password, auto_bind=True )

	# 사용자의 입력에 필터링을 적용하여 공격에 사용될 수 있는 문자를
	# 이스케이프하고 있다

	escpae_keyword = escape_filter_chars(search_keyword)
	search_str = '(&(objectclass=%s))' % escpae_keyword

	conn.search(
	 'dc=company,dc=com',
	 search_str,
 	 attributes=['sn', 'cn', 'address', 'mail', 'mobile', 'uid'],
 	)
    
 	return render(request, '/ldap_query_response.html', {'ldap':conn.entries})