> ## Content Index
> Fetch the complete content index at: https://yokai.hakaisecurity.io/llms.txt
> Use this file to discover other available public pages before exploring further.

# LDAP - Know To Attack
- URL: https://yokai.hakaisecurity.io/ldap-know-to-attack/
- Published: 2025-10-10T14:25:53.000Z
- Updated: 2026-09-08T16:30:49.000Z
- Author: alkarramax junior
- Tags: Insights Blog, #wp, en, #pair-ldap

When performing internal tests, it's common to use LDAP (Lightweight Directory Access Protocol), but its true purpose, utility, and power are often misunderstood. And since our motto is “Understand before you attack,” we'll explore what LDAP is, its origins, the earlier version, its nuances, and much more.

# What are DAP and LDAP?

DAP (Directory Access Protocol) was a protocol created based on the X.500 standard (which we'll discuss in the Directories section) and the OSI model. As we know, the OSI model is not widely used in practice, with TCP/IP being the dominant standard. Because of this, DAP faced performance issues, as it was slow and resource-heavy.

To address these limitations, LDAP emerged, with the term *Lightweight* added to its name. It retained the use of X.500 for directory structure but switched to TCP/IP as its underlying protocol. This made it lighter, faster, and more efficient than its predecessor — and it's still widely used today.

# What are directories?

As mentioned earlier, LDAP uses the X.500 standard to structure its directories. This standard was developed by the ITU-T (International Telecommunication Union – Telecommunication Standardization Sector). The core idea is that there is a single **DIT (Directory Information Tree)**, where all entries are organized — such as groups, users, computers, organizational units (OUs), and more. Each entry contains attributes and the corresponding values for the object it represents.

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXebZbjW8EiOHSlbrKWVFate-mVYBd-hcl_WXaZ7fI5yBmC5p3OLfUp9dZ44wHaHPZiPql6HY4svQtOndFldKJWy31RlSlZPPkQLXmflXs2B8h4KwuMSs3l2dVm_IPuY9wjlG9cR?key=88H8T1ieVFTabheQZtHW4A)

In this image, we can see how the directory is structured: it resembles a tree, with hierarchy as its foundation. **DC=com** represents the root of this directory, and everything beneath it is considered its “children.” Using the user **D3v** as an example, we can see that this object's "parents" are, in ascending order, **Pentest**, **hakai**, and **com**.

A common element in this type of structure is the **DN** (Distinguished Name), which allows us to identify the full path to an object within the directory. For example: **DN: DC=com,DC=hakai,OU=Red Team,CN=Oliveira**. With this DN, we know exactly where the user **Oliveira** is located within the tree.

Now that we understand what LDAP is and how a directory works, a natural question might arise:  
**“What can we actually do with this directory and its objects?”**. To answer that, we need to understand LDAP operations.

# LDAP Operations

There are several operations that can be performed with LDAP, as defined in [**RFC 4511**](https://datatracker.ietf.org/doc/html/rfc4511?ref=yokai.hakaisecurity.io), specifically in section **4.1.1 (Message Envelope)**.

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXerpcIx1SegjmnN_JpMuJji9Sj-WJe38fbRrTOrmAkDmm9R2BHY6z65zJ_3BLcv7xEgym1oK2A-qCEeD1DDz1I38SVvtsVnq4aRbO84eCcPLovpBkpK8UCwLeingS2ZN6UZCNpOcg?key=88H8T1ieVFTabheQZtHW4A)

In this post, we will cover the main LDAP operations: **Bind**, **Add**, **Delete**, **Modify**, and **Search**.

## Bind Operation

The **Bind** operation is used for user authentication. There are two main types of authentication: **Simple** and **SASL** (Simple Authentication and Security Layer). Authentication is detailed in **RFC 4511**, section **4.2 (Bind Operation)**, where you can see exactly how this operation is specified.

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXcwawQ044xUSRG9qqpWpz8iOoruygoPuaEqPJ0LOP5VPOzwCv97-zmn4BZKbKQpW9ReeS1lyLQUIFLQzy7EM41sv51EJY8Ssc22FyVqgRQG4w7OX77jpAilfR56hla8iCVphgzW?key=88H8T1ieVFTabheQZtHW4A)

**Simple Authentication**, as the name suggests, is used for basic authentication using a username and password.

```bash
ldapsearch -H ldap://hakai.com -x -D "maxin@hakai.com" -w "P@ssw0rd" -b "OU=Pentest,DC=hakai,DC=com"
```

![O atributo alt desta imagem está vazio. O nome do arquivo é AD_4nXehQtZSd-3Q5GZTRtVaS6Qgy7VbspF-IIxAjhCBntu7P1zt5W3V44sk2sT3I3RwQN9brjkwAfTI5-V7CzQbvRZ732_OKIH-2gSd_sZa1Gp8nlQNCrh2TRh4ICWCo9Cdm8Joe6ZygA](https://lh7-rt.googleusercontent.com/docsz/AD_4nXehQtZSd-3Q5GZTRtVaS6Qgy7VbspF-IIxAjhCBntu7P1zt5W3V44sk2sT3I3RwQN9brjkwAfTI5-V7CzQbvRZ732_OKIH-2gSd_sZa1Gp8nlQNCrh2TRh4ICWCo9Cdm8Joe6ZygA?key=88H8T1ieVFTabheQZtHW4A)

Using the **ldapsearch** tool with the **\-x** option (which enables Simple Authentication) and passing the **\-D** flag with the DN of the user to be used — in this case, we can use **maxin@hakai.com** or **CN=maxin,OU=Pentest,DC=hakai,DC=com** — we establish a connection with simple authentication.

From this point onward, and for the remainder of this post, we will use **Wireshark** to analyze the communication. In the following example, we will see how authentication is performed.

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXdpNQZntn_YrfSMzdPmIhKv42jjDDlTvTJjMarFrCPAZNZJdedWgj2gcmVavP5KKTQTtnurF47eJlZ4Kv53sCm_RfHvIV-kJna4GxsMFHIz9yCFtV1vzekSFjIuQQYbuZFRnZSf?key=88H8T1ieVFTabheQZtHW4A)

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXeRektuOzgrweAYdCXaRjnbB3TWVkqI5vB3qn2KE-bcUYD7PuVJ8s8h9MUIltGud-6idCm-T_r6OvXdgb-_0sqlHx9yAhN7WFHgtXtOoiwGfd6cwK1UhY0eXjrhXTKlYYeOlORfgg?key=88H8T1ieVFTabheQZtHW4A)

Unlike Simple Authentication, **SASL** is used for authentication through external protocols, such as **GSSAPI**, which is employed in Kerberos authentication.

To use an external protocol in *ldapsearch*, we use the **\-Y** option.

```bash
ldapsearch -Y GSSAPI -H ldap://dc01.hakai.com -b "dc=hakai,dc=com"
```

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXd6glrnR8xYw59Zv0fnqy4owKTBRO7goVvOyekpkbUWoMcUngzPcDKRZEWmFApWUQBUJVQ53jaIrJUjEcM_i1RJ6ND2XOfKGuBAO0sYTwjtiLz3ytDx7ssw35kJe2sTlxGapZsBXg?key=88H8T1ieVFTabheQZtHW4A)

We can observe that, compared to Simple Authentication, communication using an external protocol is much more complex and requires sending a larger amount of information.

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXdPocyv6kUy_wTzwDObmP0ERKgCyy6vSCEOSIUfCktkDJUJDU5DM8X51x21CA9FQqY_8MAjN_uRmpankkBOmlu6TBVavT3D7xcg15fk0is1g61FB4YrfmUsyDfCn7z7CNAd0Up07w?key=88H8T1ieVFTabheQZtHW4A)

## Add Operation

The **Add** operation is used to add a new entry to the directory. We can include users, groups, computers, and other objects, depending on the permissions of the user performing the action.

In this example, we will add a new machine to the domain. To do this, it's necessary to create an **LDIF (LDAP Data Interchange Format)** file, which will be used by the **ldapadd** command.

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXfqjXJ4wuoi3jvXau0Sjm7rj-PyPvMJ6-17h9_cVQV5TL4gK-IlfXtghrm2Rd_Aaxp0K2eAsTW5G5sugeb-bUncG7yktuRPyBiNT0H9rFH4MrR4k5FiFwrfrCFcMPqeyKWqHev50g?key=88H8T1ieVFTabheQZtHW4A)

After creating the LDIF file, we can execute **ldapadd**, using a user with administrative privileges to perform the operation.

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXcFJUXna4r_suaWJ7qNww4zDHcOlYPrbvQ1ojGQStoWTiyHJ8fUm6X2BBQqACiJL5-eGY9Rtg52iyekDe0dPOX83wJvc6Ox8zctFVnJIZED7RXKoiKyfSOb2_NBqwqH-UNYfYxfAg?key=88H8T1ieVFTabheQZtHW4A)

## Modify Operation

The **Modify** operation is used to change entries in the directory. We can alter LDAP objects depending on the permissions of the user performing the action. Just like with the **Add** operation, this modification is also done through an **LDIF** file.

This operation is very important but not commonly used. If your user has permission over another user or belongs to a privileged group, it's possible to use the modify operation to alter entries in the LDAP directory. For example, if an attacker gains access to an account that belongs to the **Account Operators** group, they could use this operation to add users to other groups in Active Directory.

In this example, we will add the user **Oliveira** to the **Administrators** group.

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXcpAdUKrXdcl2lu91moCyV5y04IVYzRteKPtMdROx2zXWGZIxkqGKOHpjaXSX0YJUjwI00h-fCjPI8w31Mg5B39BJygZP_4mqXhgaeQ-Kv76kMCXgIYsaVIO9qgxhf3LOkM-JGD_A?key=88H8T1ieVFTabheQZtHW4A)

We’ll use the **ldapmodify** tool to perform this action, passing in the previously created LDIF file.

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXe4z24QZtpOEAENExPkt38_cJwUJ9irv8WDMQ2kxeaqCSx5Fu__Z1gS2CgF3PDJy6C6Q4maiuzm-beYZOqLN4F-JzfpiF27yWBF2zw-sCvhvaAoeCQ85wH-4jfhHJyyEckjPgpI?key=88H8T1ieVFTabheQZtHW4A)

## Delete Operation

The **Delete** operation allows you to remove an entry from the directory. Unlike the previous operations, **Delete** does not require an LDIF file, as it is a direct action where you specify the **DN** of the entry to be removed.

In this example, we will delete the computer that was previously created using the **Add** operation.

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXe5x8JwHeMIoyyVKIDyxJvGlbbdraQIwDHCeux349YEdjJrQwntPNl_5ODqIttiH0RvZi08S25ia63jBSylJ5yaNZCYULiptf400fOivMGu_HTT8b1bOufot1WDr6dKiQ11QUYlsQ?key=88H8T1ieVFTabheQZtHW4A)

# Search Operation

The **Search** operation is the most commonly used in LDAP, allowing you to query all information within Active Directory.  
To understand the Search operation, we need to break down the elements required to construct it. In section [**4.5.1 (Search Request)**](https://datatracker.ietf.org/doc/html/rfc4511?ref=yokai.hakaisecurity.io#section-4.5.1) of **RFC 4511**, we can see exactly how it is defined.

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXeyat6CD7Nu1fj40YbmOV2BdyAZGwYle-GJuuX3ATaxXczwb15xYzESKRf6rM2tuFssYd1jzuayHB67nMCKP4iqyirBycJ_xaKJ0YTfIDZzCyv4AT701o1jhn2HRDxXzc03A8hWTA?key=88H8T1ieVFTabheQZtHW4A)

This operation is divided into several components: **baseObject**, **scope**, **derefAliases**, **sizeLimit**, **timeLimit**, **typesOnly**, **filter**, and **attributes**. In this post, we’ll focus on the elements **baseObject**, **scope**, **filter**, and **attributes**.

## Base Object & Scope

The base object defines the point in the “tree” from which the search will begin. For example, if we define the base object as `OU=Pentest,DC=hakai,DC=com`, all the information collected will be from the Pentest organizational unit (OU). In this case, the search will not return data related to other OUs.

Usually, the **baseObject** is defined at the top of the "tree", such as `DC=hakai,DC=com`, so that the search retrieves all possible information.

The **scope**, on the other hand, determines how deep the search goes from the baseObject — which is why these two concepts complement each other. As shown in the previous image, the scope has three options:

- **baseObject (0)**
- **singleLevel (1)**
- **wholeSubtree (2)**

Each of these options defines the depth level of the search. To better illustrate this, see the following image:

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXfrk--mO9MihW2NTsjOu4ABm0CMAQZMEIFd1NCFdmP0oK335NsI02GDTnKGY0wPjAaUU_ZRqIUODTb_Z2TR4KB_zs6t5blh7zkF7_jZiLHEIxStWzl9qWR8gkU12jK6TR28ZgJybw?key=88H8T1ieVFTabheQZtHW4A)

In this case, we define the **baseObject** as `DC=hakai,DC=com`.

If we set the **scope** to **baseObject** (highlighted in red), the scope is limited precisely to the defined base point. When choosing **singleLevel** (highlighted in blue), the scope covers only one level below the baseObject. The **wholeSubtree** option (highlighted in green) allows you to view the entire tree starting from the defined base.

The most commonly used scope option is **wholeSubtree**, but it’s important to be aware of all available options. In this example, we’ll use **ldapsearch** again, without explicitly defining the scope:

```bash
ldapsearch -H ldap://hakai.com -x -D "maxin@hakai.com" -w "P@ssw0rd" -b "DC=hakai,DC=com" "objectClass=user" cn
```

We can observe in **Wireshark** that the data being sent matches exactly what is specified in the **RFC**.

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXcV-GEeIOOFtukwdMW18HJPcyimtm8Wx531kdTc0QQbrVUsS-e6E1ZFmLgULt_IPrDhD_0zFItbS3tEH3vU8_mvJ8o6bc5JKbkrEu4GOzBh3ndS2p-oK7P9BKUidEr654wk48D7Yg?key=88H8T1ieVFTabheQZtHW4A)

In the **ldapsearch** command, the **\-b** option defines the **baseObject**, and the **\-s** option defines the **scope**. Since we didn’t specify a value for the scope, the default **wholeSubtree** is used, as shown in the image.

## Attributes & Filter

### Attributes

In this section, we'll start by talking about **attributes**, which form the foundation for understanding filters in LDAP.

All objects in Active Directory have attributes. To view these attributes, we can perform a simple search using **ldapsearch**.

```bash
ldapsearch -H ldap://hakai.com -LLL -x -D "maxin@hakai.com" -w "P@ssw0rd" -b "DC=hakai,DC=com" "cn=maxin"
```

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXd-g5A2IoavCPOosgdfiWZxoWDJj0UIEpkuGnzawEzfvdGRH_4cCS9BMupgHmgDhxSD41YqTpUnGuPQ5WF6M5bEGO8T_OwL709oPhToTZOHOjYaQelx6bm21jZWfvFUfi3IMLwH8g?key=88H8T1ieVFTabheQZtHW4A)

Below, we present some of the attributes of the object **maxin**. Based on these attributes, we can apply what is called **Attribute Selection** to filter which information we want to retrieve. It’s important to note that in the **ldapsearch** command, attribute selection is defined at the end of the command.

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXcfErqOqcwV7rq30YK59fQfuM1gSbTuokDkW227oZDTtZ63Dpz29wh4nq_Wy9ZJS_tJk2FZkANN5mIZjJe0bDw1sEZlMmAB9AAhFJEZJm9hxmRVJ6kpxh5RZDIbpS3ps_6-jZJ7?key=88H8T1ieVFTabheQZtHW4A)

By capturing this LDAP query in **Wireshark**, we can see the selected attributes.

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXcFpPtTmRvzoDDF_SLeXe7Bkp9OOlIpBm4YX_tSZGmy63iHSmqi6_f5HhLjW2MiYe0LppgfqVwwlNzVWFArtTcm04frUzT2TnBoJrD5pOnlYli-hjfHuFHUQjfMLS1y2Ujrh_I8?key=88H8T1ieVFTabheQZtHW4A)

It’s interesting to understand what happens when we perform a simple LDAP search without explicitly defining a **Filter** or **Attribute Selection**.

```bash
ldapsearch -H ldap://hakai.com -x -D "maxin@hakai.com" -w "P@ssw0rd" -b "DC=hakai,DC=com"
```

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXdNHX7Evq2eCb00HJdjcaL24m7owClt0rYtmrTFY9C-C-9wIFWg0cMG6T4KIwSetC0kTtzjJllX6VeidMdAHrA4RQyWg0jPyGN5Dzy646_BqaUbU-Koh1PL5z0LykWF4hJfvO_Q?key=88H8T1ieVFTabheQZtHW4A)

If no filter is specified, **ldapsearch** will default to the filter `objectClass=*`. This means the search will return all object classes present in Active Directory — essentially all objects. The **attributes** field, when set to 0, is interpreted as `*`, which causes all attributes of the objects matched by the filter to be returned.

Now that we understand the basics of Attribute Selection, we can move on to **Filters**. In search operations, the filter is one of the most important elements, as it determines exactly what kind of information will be collected. And this filtering is based on the attributes of the objects.

### Filter

By consulting **RFC 4511** again, specifically the section related to filters, we find something quite interesting.

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXfczkf8d23Pt9JN2koO9GhNUDDkGnQslFYgi9okNVreBjIgJeQFsYEV6vHDqUkpSce7NfnqxujgvtoRs-3QWia3AE_rc0GkFJIcCNp_51cN-aoxmftzixb6ldaEFpceFnlqsyXn?key=88H8T1ieVFTabheQZtHW4A)

The RFC defines various types of filters, including the so-called **Boolean operators** — **AND (0)**, **OR (1)**, and **NOT (2)** — which we will discuss later in this post. In addition to those, there are other filters such as:

- **equalityMatch (3)**
- **substrings (4)**
- **greaterOrEqual (5)**
- **lessOrEqual (6)**
- and others.

To better understand how each type of filter works, let’s start with one of the most basic: **equalityMatch (3)**.

In the following example, we will filter all objects whose **CN** attribute is equal to `"maxin"`. Since there is only one object with this name, the result will be a single entry — the **maxin** object itself.

```bash
ldapsearch -H ldap://hakai.com -x -D "maxin@hakai.com" -w "P@ssw0rd" -b "DC=hakai,DC=com" "cn=maxin"
```

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXfoDg3aRg6n4YWAjuspG-uMZSfTzuqccEbKXLf83bpMO3yzBsYrQouropY9bBdhi9dd6dF5cVDGIwB-vvRhwsu186iEWJq5fUPoDgZ2hWzswmcEGFOhN4aCeA5Nt8PCKVOZxgDsKg?key=88H8T1ieVFTabheQZtHW4A)

By capturing this operation in **Wireshark**, we can see exactly what the RFC describes: the use of **equalityMatch (3)**, the **attributeDesc** field (which indicates the attribute being filtered), and the **assertionValue** (the value defined in the query).

Another very useful filter type is **substrings (4)**. A practical example would be:  
`cn=ad*`. In this case, we’re using the **CN** attribute with a wildcard (`*`) to search for all objects whose **Common Name (CN)** starts with “ad”. Although this example uses the CN attribute, the **substrings** filter can be applied to many other attributes depending on your needs.

```bash
ldapsearch -H ldap://hakai.com -LLL -x -D "maxin@hakai.com" -w "P@ssw0rd" -b "DC=hakai,DC=com" "cn=ad*" cn
```

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXcWmb_fSopaUos0UBI2UGRpKYNgIt63p9vOZSgIu9tbmzE95eFS15UIWCr9rGty5JiAa4i7f66-U8-j0LB5tnFKXt5jcOuLNBOq_k7tel1BPYlQQMuQMHbmQTdfkWg7KvgPc-ppKw?key=88H8T1ieVFTabheQZtHW4A)

This filter will return all objects whose **CN** starts with “ad”. It’s important to note that **Windows** (and consequently **Active Directory**) is **case-insensitive**, meaning it does not differentiate between uppercase and lowercase letters. That’s why names with uppercase letters will also appear in the results.

By capturing this operation in **Wireshark**, we can clearly see how the search was executed.

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXdIG_aWBv_8VHSdsCakpZjJB28-KhBrObDaJiyy_CzyPPWFsmASppCpRMl7WIIlBsZwsRXAaQskFFVyLynqUXwSLnQp0tbJSLDWIr8FiT0UoUQtzUJ7Y7hpm2xRTTQ1i1A77g-NnA?key=88H8T1ieVFTabheQZtHW4A)

There are two additional filters worth highlighting: **greaterOrEqual (5)** and **lessOrEqual (6)**. Let’s understand how they work and how they can be used in more advanced queries.

Both follow the same usage pattern — you need to provide a value such as a number, letter, or symbol.

```bash
ldapsearch -H ldap://hakai.com -LLL -x -D "maxin@hakai.com" -w "P@ssw0rd" -b "DC=hakai,DC=com" "cn>=a" cn
```

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXdyh-hZNOcQs18evkQy7s-PUlzLbGEqnjStxnmstpW0FYgyFPg7QBieeB6z5xQt8wY0ZAIGbDzKUmkUTC1DWMkbJamlEspbBtjTB-5LWk7WyNVPpnd7tbFLYOUCnh65ULj3OEoA?key=88H8T1ieVFTabheQZtHW4A)

What exactly is **greaterOrEqual** doing in this case? When we use this filter with the letter **“a”**, LDAP converts the character to its decimal value in the ASCII table — which is **97**. From there, it returns all objects whose attribute values start from **97** onward — in other words: a, b (98), c (99), d (100), and so on. The smaller the value provided (in ASCII terms), the broader the search scope becomes.

In the next example, we used the symbol **“!”**, which corresponds to **33** in the ASCII table. This query returned **711 entries**, compared to the previous example using the letter **“a”** (ASCII value 97), which returned only **455 entries**. This demonstrates how lower ASCII values significantly increase the search scope.

```bash
ldapsearch -H ldap://hakai.com -LLL -x -D "maxin@hakai.com" -w "P@ssw0rd" -b "DC=hakai,DC=com" "cn>=!" cn
```

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXfIN6riNkVtBj4xTafvPy28022HK50YO5rf6Fgw6mwsShUW2ZNngkSzHvaGZKh-3De-spIEEoZMa87dxIjy6_TVfbeh32aa_CH_845mUiiDQSkJWdeHYsb2v5-dW1EZ9Xj4Q8Sl3Q?key=88H8T1ieVFTabheQZtHW4A)

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXeeXJ8PJDMmLxDIPle0o9akLpWWhRMkAStR58EkUCxH5HtXAyHXdRW36jSQ6uRK7NgZVLjTWflwNuYpxu5dSx4gXb1tYr-3jjacHwQuQdlf4cAGfqPcfCBHa3QRaAgsKt29hwpxrQ?key=88H8T1ieVFTabheQZtHW4A)

Understanding how **greaterOrEqual** works makes the use of **lessOrEqual** a logical next step, since both follow the same operational pattern. The "trick" now is to reverse the logic: use a letter or symbol with a **high ASCII value** to limit the results — in other words, go the opposite way and filter only objects with values **less than or equal to** the one specified.

```bash
ldapsearch -H ldap://hakai.com -LLL -x -D "maxin@hakai.com" -w "P@ssw0rd" -b "DC=hakai,DC=com" "cn<=a" cn
```

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXdpm-JWTzYGE9tqsClA2HmkcJJKrYyHXPT3233ck0i9p7O0RUBP0IgNGVA_fpHaV7asheaYeOnFgErXmLTHUz5dwUbEe6IMCcuRe92jIFFpoNClspbeAM9V7CdqDU53i0BNWPvQXg?key=88H8T1ieVFTabheQZtHW4A)

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXdNb5ZpiRPKJyBQn4R7T1rgzpZXl4Gb_xPBZKqtWwejO3nxhL4Q9anK1HRxYeGVaeAwYM_Xn47hEiSi3RXq0Q4zaPTOnn-k9DE-QRQ3HEVp-6g1XX-b_xDMiVzye4lV4u_Hm-erXA?key=88H8T1ieVFTabheQZtHW4A)

### Search Extensions

As mentioned earlier, **ldapsearch** does not return all available attributes of objects by default. For example, the **ntSecurityDescriptor** attribute is extremely important because it contains information about **DACLs** and **SACLs**, which define permissions and auditing. However, if we try to query it directly, as shown in the example below:

```text
"cn=maxin" ntSecurityDescriptor
```

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXf5s87mM1bOzGwMivjHS6PsAAwIp9moekhKhkExtEAom60GGmUAqk7ExxMb0lJQjBV_2JfsCcpp26KXnUK77hiVzN7uuzOWMjf48oVEh2Er9Oa5WYRNwrzuD8w_n38QShj-XgDT?key=88H8T1ieVFTabheQZtHW4A)

We won’t get any results for this attribute. But that doesn’t mean it can’t be accessed.

To retrieve it, we use a feature called **Search Extensions** in **ldapsearch**, enabled with the **`-E`** flag.

```bash
-E '1.2.840.113556.1.4.801=::MAMCAQc=' 'cn=maxin' ntSecurityDescriptor
```

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXew4Hq_vVcI9ac78ln-Zxdu-VoALbBvnJud1y1oesOHFpy8XNDw4d9wOqSDcGEVW3lD67FLbcLLCt9-2wGuuF8aG4uUOsTNUd5yev5liQ2O1QU7iuLEWaDWSnX7hW3fJXlZbGSvbQ?key=88H8T1ieVFTabheQZtHW4A)

Let’s break it down to understand why this query works. The **Search Extensions** option accepts only **OIDs** (Object Identifiers). The OID **1.2.840.113556.1.4.801** is interpreted as an extension called **SD\_FLAGS**.

**SD\_FLAGS** defines which parts of the **ntSecurityDescriptor** will be returned. The main components and their corresponding values are:

- **DACL** (Discretionary Access Control List): 1
- **SACL** (System Access Control List): 2
- **Owner**: 4
- **Group**: 8

If we want to retrieve **DACL**, **SACL**, and **Owner**, we need to add the values: **1 + 2 + 4 = 7**. The value **`MAMCAQc=`** seen in the extension is a **base64-encoded blob** that represents this number (7), encoded in the **ASN.1 structure** required by **SD\_FLAGS**.

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXfuvAriHqvjKs_rwJlwASbz9RRD4m3ZenaE66Wigtgk7mDSnVQ7JR1ZHA8kWfxCasxi3NUgYIYPcU40X8Dx-wyrvxoFOjtBpYplu7RlqBXg4jkf7_tFacP1XgAJtcTXP8UoyXVb?key=88H8T1ieVFTabheQZtHW4A)

### Boolean Operators

Boolean operations in LDAP allow the construction of more complex and specific filters using the AND, OR, and NOT operators. Let’s better understand how each of them works in practice.

The AND operation is represented by the symbol **&**. Like the OR operation (which we will see next), it requires combining two or more conditions, each enclosed in parentheses. The structure looks like this: **&(condition1)(condition2)**.

In this example, we perform a simple check. We are verifying if the object belongs to the **user** class and if the **CN** equals **maxin**. Both conditions must be true for the object to be returned.

```bash
ldapsearch -H ldap://hakai.com -LLL -x -D "maxin@hakai.com" -w "P@ssw0rd" -b "DC=hakai,DC=com" '(&(objectClass=user)(cn=maxin))'
```

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXdhx0Z6EqvazPTudiwMk0lhMKI8yGIHjrUsdUNrh8sfFRX76vPLjcpd9jrBEfiLrzIq5yetCWtQGkcZvWIhtJUYsLxt9-x9ybflutoHl-y5vA0Ei8f7y7pmqU8JUt4IacGIvzCu?key=88H8T1ieVFTabheQZtHW4A)

We can improve this filter by using what we learned in the previous section with the **greaterOrEqual** operator. We are checking all objects of the **user** class that match the search filter `cn>=!`.

```bash
ldapsearch -H ldap://hakai.com -LLL -x -D "maxin@hakai.com" -w "P@ssw0rd" -b "DC=hakai,DC=com" '(&(objectClass=user)(cn>=!))'
```

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXe_fNS8EaeDV4cTXlX8DccehhRpWTWAVu4dU9DlBGTQnDrdaUrE3mi2bJ4zCTbDn5GL6Dqompt3ma0fX9kHe1ISdRNcO2tXvEYxMu4Kd3Z6JDx9jLUimbAvRUElV8exggLCXo3M4w?key=88H8T1ieVFTabheQZtHW4A)

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXepKUg2-l_sSe_zj1v8cj3sgIoqj1BsxUgy_MZP_jFzOZgx-VDrAMpnZCEiRf1DdurazFZ4mdaJ49_A_LzDWjwOXosLMW5vhGBCBUpOoXGj8ZoD_XfV8IkoHjHj1T1w0aI7eo_qQQ?key=88H8T1ieVFTabheQZtHW4A)

The OR operation follows the same structure as AND, but with a fundamental difference: it is enough for one of the conditions to be true for the object to be returned.

To use OR, we use the symbol "**|**", as follows: **|(condition1)(condition2)**. Normally, OR is combined with other boolean operations to create more precise filters. For example:

```text
'(&(objectClass=user)(|(cn=maxin)(cn=luriel)))'
```

In this case, we use an AND in conjunction with an OR. Notice that, after the condition (&(objectClass=user), we open another parenthesis — this contains the OR operation, with two internal conditions. Here, since both conditions within the OR are true (the CNs maxin and Luriel exist) and the AND condition is also satisfied, both objects are returned.

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXdHQsfhScdRYIfhzTfst-Cuy_gs0qQc1epK4PHzVIPG2O0qPgdqJNhc9PJ2BnyttVupIyT6TW5Hg5TxcOjHsH5kfWYFwXLTzs73CE2iH7gIvlBlQ4vdgCcpRA_1X2okkAHAItomzQ?key=88H8T1ieVFTabheQZtHW4A)

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXflFMOUTg_yvLT0aua-LDlsVyy5gfLX_ZsUykOyCM05kK2z5wC5bOvKjHCI1XR0zH6-Jxp8uf4M5RBT2IZQON8N_3AzY2jgIfLymAd2FG7Cxa4n0l1EyUsiMPXTCNNxQjYWFmhzhg?key=88H8T1ieVFTabheQZtHW4A)

When analyzing this search in Wireshark, we can observe an interesting pattern: the filter starts with AND (0), and inside it there is an OR (1) — exactly as structured in the command. This clearly shows how the filter is interpreted by LDAP.

The NOT operation, represented by the symbol "**!**", is the last boolean operation available in LDAP. As the name suggests, this operation negates the given condition. Unlike AND and OR, NOT requires only a single condition, meaning only one pair of parentheses is necessary.

In this command, we are searching for all objects of the user class that do not have CN=maxin. The result will be a list of all users except the maxin object.

```text
'(&(objectClass=user)(!(cn=maxin)))' cn
```

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXeypHNQQBOm5WQ4Nll2OOJulLp6uFbzCuafkKpu9Jks14EWkRUh0Ya6Q3JZZbzcw2Sxh7K3fm4gWlIVGdzXcJE7zf5HTDDhl9p80MdgG_hyd8ZuaCHm89QZkPFuwoBbkhu3CcevXA?key=88H8T1ieVFTabheQZtHW4A)

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXdo0BFBwv6ZjAEIyPq_ndPQeaXKLo53aH0au3bY76izYF4fgt_reCvXGmC6R7pHFpHB1tnAYnqU4ai8ycwReSVxxfb8iZi7hs2nYL1eWDxEpSD01mpFz5x9irtMqix_dSBjms_IqA?key=88H8T1ieVFTabheQZtHW4A)

In the image above, we can clearly see in Wireshark the presence of the AND operation (0) and, within it, the NOT operation (2) applied to the condition.

These were simple examples to demonstrate the use of Boolean Operators in *LDAP*. Despite the simplicity of the cases presented, these operations have a much broader application, especially when integrated into web-based authentication mechanisms, where they can be used to build or manipulate access logic based on *LDAP* filters.

# Conclusion

When we come across an Active Directory environment, understanding how LDAP works is essential. Even if we don’t use it directly, it is almost always working behind the scenes. That’s why knowing the protocol, understanding how it operates, and how to extract information consciously is extremely important. Widely used tools like BloodHound, for example, make extensive use of LDAP to collect data and perform correlations — such as the *ntSecurityDescriptor* attribute mentioned earlier, which allows identifying permissions between objects and what a user can or cannot do in the domain. Another example is Certipy, used in the reconnaissance and exploitation of vulnerabilities in Active Directory Certificate Services (AD CS). Like BloodHound, Certipy also uses LDAP to search for and structure critical information.

These examples clearly demonstrate how powerful the protocol is. Although commonly remembered only for its search function, LDAP also allows adding, modifying, and deleting entries in the directory — functionalities which, if misused or exploited, can seriously compromise an environment.

We always emphasize the importance of understanding how systems — protocols, services, etc. — truly work before trying to attack them. It’s no use if we don’t understand what’s happening and just attempt to attack. In this scenario, we end up simply running tools without comprehending what’s really going on — and most likely without achieving any meaningful results. Understand first, then attack!

I hope this blog post has helped you, in some way, to better understand the LDAP protocol and everything that can really be done with it. Additionally, this post was also meant to show how curiosity and the desire to understand can lead to significant comprehension of any topic. I hope this demonstration serves as fuel for everyone reading and encourages you to do the same.