LDAP
Lightweight Directory Access Protocol (LDAP) is a protocol used for accessing and managing directory information services.
It's commonly associated with Active Directory and openldap, which are directory, e.g. databases optimized for read-heavy access.
ποΈ Ports: 389 (TCP)
π₯ LDAP communications are not encrypted.
π There is a secure version called LDAPS (port 636, over SSL/TLS).
LDAP is derived from the X.500 standards. Messages exchanged between LDAP clients and servers are encoded using ASN.1.
A simple un-encoded LDAP message:
cn=John Doe,ou=Users,dc=example,dc=com
LDAP Queries π£οΈ
LDAP is using parenthesis ( and ) to group expressions.
(objectClass=user)
The star (*) refers to "any" string.
(cn=*doe*)
We can use & and | for logical 'AND' and 'OR.'
(&(objectClass=user)(sAMAccountName=aaa))
(|(sn=xxx)(sn=yyy))
(&(objectCategory=person)(|(sn=xxx)(sn=yyy))(adminCount=1))
We can use Microsoft Active Directory OIDs (or this ref) for advanced filtering. For instance, 1.2.840.113556.1.4.803 allow us to filter objects with a specific UserAccountControl bit enabled.
π According to the documentation above: (userAccountControl:1.2.840.113556.1.4.803:=32) would match users with UAC and no password required (PASSWD_NOTREQD bit).
LDAP Pentester Notes β οΈ
ldapsearch command
You can use ldapsearch to find database entries.
$ ldapsearch -H ldap://ldap.example.com:389 -D "cn=admin,dc=example,dc=com" -w password -b "dc=example,dc=com" "(cn=John Doe)"
$ ldapsearch -h IP -x -b "dc=example,dc=com" -s sub "*"
$ ldapsearch -h IP -x -b "dc=example,dc=com" -s sub "(&(objectclass=user))"
-H: use a custom socket-D/-w: specify authentication data-x: use basic authentication-b: indicate the root of the search
windapsearch command
You can use the windapsearch.py (0.7k β, 2020 πͺ¦) script or the go (0.3k β, 2021 πͺ¦) binary. They make it easier to craft LDAP requests.
$ python3 windapsearch.py --dc-ip IP -u "" -U
$ python3 windapsearch.py --dc-ip IP -u xxx@example.com -p xxx [...]
-PU # user with elevated privs
-G # groups
--da # domain admins
--members xxx # members of group 'xxx'
LDAP Injection
Web applications using LDAP may be vulnerable to LDAP injection. These two expressions are always true: (cn=*) and (objectClass=*).
The most basic authentication bypass is * and * that authenticates as the first user found.
LDAP Pass-back Attack
LDAP Pass-back attack is possible when we have access to the LDAP configuration from a web interface of a device.
We may be able to make the device send its LDAP requests to US by changing the LDAP server IP to ours.
We can set up a responder, but it doesn't always work.
$ sudo responder -I lo # and simulate a device sending cleartext credentials:
$ ldapsearch -x -LLL -H ldap:// -D "bind_dn" -w "password" -b "base_dn" -s sub "(uid=username)"
Some devices may be vulnerable to downgrade attacks and can even send cleartext credentials. Responder may not be able to do that, so we may need to run our own LDAP server:
$ sudo apt-get update && sudo apt-get -y install slapd ldap-utils && sudo systemctl enable slapd
$ sudo dpkg-reconfigure -p low slapd
$ cat changes.lidf
dn: cn=config
changetype: modify
replace: olcLogLevel
olcSaslSecProps: noanonymous,minssf=0,passcred
$ sudo ldapmodify -Y EXTERNAL -H ldapi:// -f changes.lidf
$ sudo cat /etc/ldap/slapd.d/cn=config.ldif # OK?
$ sudo service slapd restart
$ sudo service slapd stop
LDAP Server On Docker
We can use docker-ldap (3.9k β), but I failed to configure it to only allow cleartext authentication.
FROM osixia/openldap
ENV LDAP_ORGANISATION="My Organization" \
LDAP_DOMAIN="za.tryhackme.com" \
LDAP_ADMIN_PASSWORD="admin_password"
# Import LDIF modifications
ENV CONFIG_PATH="/container/service/slapd/assets/config/bootstrap/ldif"
RUN rm -rf ${CONFIG_PATH}/*
COPY config.ldif ${CONFIG_PATH}/01-config-password.ldif
RUN echo "" > ${CONFIG_PATH}/02-security.ldif
As for config.ldif, the code below is incorrect:
dn: cn=config
changetype: modify
add: olcSaslSecProps
olcSaslSecProps: noanonymous,minssf=0,passcred
Build with:
$ docker build . -t xxx:v0.01 --no-cache
$ docker run --name xxx -p 389:389 -d xxx:v0.01
Test with:
$ ldapsearch -H ldap:// -x -LLL -s base -b "" supportedSASLMechanisms
Additional Notes
You can use nxc for many operations, such as to collect everything for bloodhound, enumerate users, etc.
Refer to Active Directory Pentest LDAP for additional notes.
π» To-do π»
Stuff that I found, but never read/used yet.
- On Legacy systems, anyone can initiate LDAP requests. It seems to be called LDAP null bind.
CN=Users,DC=INLANEFREIGHT,DC=LOCAL
Discovery (Linux OpenLDAP and AD have different schemas)
$ cat newou.ldif
dn: ou=NewOU,dc=domain,dc=local
changetype: add
objectClass: organizationalUnit
ou: NewOU
$ ldapmodify -H ldap:// -x -D "cn=admin,dc=rootme,dc=local" -w 'xxx' -f newou.ldif
$ ldapsearch -H ldap:// -x -b "" -s base namingContexts
$ ldapsearch -H ldap:// -x -D "cn=admin,dc=domain,dc=local" -w 'xxx' -b "dc=domain,dc=local" -s sub "*"
$ ldapadd -H ldap:// -x -D "cn=admin,dc=domain,dc=local" -w 'xxx' -f user.ldif
$ DEST="$HOME/tools/ldap2json"
$ git clone -b "master" https://github.com/p0dalirius/ldap2json $DEST
$ python $DEST/analysis/analysis.py -f xxx.json
analysis> searchbase CN=YYY,DC=example,DC=com
analysis> object_by_property_name servicePrincipalName
analysis> object_by_property_name userAccountControl
analysis> object_by_dn CN=XXX,CN=YYY,DC=example,DC=com # to get all information