# 389 - LDAP

## Introduction

**Port**: 389 (TCP)

The **Lightweight Directory Access Protocol** (LDAP) enables anyone to locate data about organisations, users, devices, and other static data within directories. It works with printers, computers, and other devices connected via the Internet or a company’s intranet.

Furthermore, LDAP is a tool for extracting and editing data stored in Active Directory. Each user account in an AD has several attributes, such as the user’s full name and passwords. This information can be easily retrieved by sending string-based queries that match the specified filters.

```
FILTER=(<ATTRIBUTE><COMPARISON_OPERATOR><VALUE>)(cn=*Marmeus*)
```

* Comparison operators: =, >=,<=,\~=

Also, a filter can be the combination of other filters using boolean operators.

* Boolean operators: &, |, !

For example, the following filter searches for all the users whose common name contains "Marmeus".

```
(&(objectClass=user)(cn=*Marmeus*))
```

## General Enumeration

Using Nmap without proving any credentials the attacker could retrieve:

* Available LDAP public information
* The root DSA-specific Entry (DSE)

```
nmap -n -sV -p389 --script="ldap* not brute" <DC_IP>ldapsearch  -LLL -x -h <IP> -s sub -b 'DC=<DOMAIN>' # Obtain data starting from the domain
```

## Impacket

If the attacker has already used AD user credentials, the impacket program GetADUsers.py could gather data about the domain's users and their corresponding email addresses.

```
GetADUsers.py -all <DOMAIN.LOCAL>/<USER>:<PASSWORD> -dc-ip <DC_IP>
```

## Ldapsearch

Ldapsearch allows the attacker to dump the available LDAP information by using anonymous or null binding user credentials. Alternativaly, you can use [PyLDAPSearch](https://github.com/Tw1sm/pyldapsearch).

```
ldapsearch -LLL -x { -h <IP|DOMAIN> | -H ldap://<DOMAIN> } [-D '<DOMAIN/USERNAME>' -w '<PASSWORD>'] [-s <SCOPE>] [-b '<FILTER>']
```

There are different levels of scope:

* **Base**: Examines only the level specified by the base DN.
* **One**: Examines only the level immediately below the base DN
* **Sub**: Examines the subtree below the base DN and includes the base DN level.

### Useful base dn for search

Here you have some base dn for search:

* Find **Naming Contexts** (Get base domain):

```
ldapsearch -LLL -x -h <TARGET> -s base namingcontextsldapsearch -LLL -x -h <TARGET> -b '' -s base '(objectclass=*)'
```

* Obtain more information about the domain. `'DC=<DOMAIN>,DC=<TLD>'`
* Find **users**:`"CN=Users,DC=<DOMAIN>,DC=<TLD>"`
* Show **user information**.`"CN=<USERNAME>,CN=Users,DC=<DOMAIN>,DC=<TLD>"`
* Find **computers**: `"CN=Computers,DC=<DOMAIN>,DC=<TLD>"`
* Find **Administrators**:`"CN=*Admin*,CN=Users,DC=<DOMAIN>,DC=<TLD>"`
* Find **Domain users**: `"CN=Domain Users,CN=Users,DC=<DOMAIN>,DC=<TLD>"`
* Show **Remote Desktop Group** members: `"CN=Remote Desktop Users,CN=Builtin,DC=<DOMAIN>,DC=<TLD>"`
* Find **ServicePrincipalName** accounts: `"(&(samAccountType=805306368)(servicePrincipalName=*))"`
* Find **GPOs**: "`(objectCategory=groupPolicyContianer)"`

Finally, with the following command, you can obtain the number of object occurrences in order to identify less common ones.

```
ldapsearch -x -h <IP> -s sub -b 'DC=<DOMAIN>,DC=com' | awk '{print $1}' | sort | uniq -c | sort -nr 
```

### LDAP To Bloodhound

Some LDAP might be useful to ingest them into BloodHound. To do so, you can use [BOFHound](https://github.com/coffeegist/bofhound) to convert the LDAP search log into a JSON file that can be interpreted by BloodHound.

```bash
bofhound -i ~/.pyldapsearch/logs/pyldapsearch_20250313.log [-o file.json] --properties-level All
```

## References

* [389, 636, 3268, 3269 - Pentesting LDAP](https://book.hacktricks.xyz/pentesting/pentesting-ldap)
* [Enumerating AD users with LDAP](https://vk9-sec.com/enumerating-ad-users-with-ldap/)
* [Windows AD](https://pentestbook.six2dez.com/post-exploitation/windows/ad)
* [WINDOWS ACTIVE DIRECTORY LDAP SEARCH](https://rioasmara.com/2020/02/23/windows-active-directory-ldap-search/)
