LDAP enumeration tool built for anonymous-bind enumeration against ForgeRock / OpenDJ directory servers. Also works against other LDAPv3 implementations, but the workarounds and heuristics are tuned for ForgeRock's quirks.
- Authorized use only. Only run this against systems you have explicit written permission to test.
- Use at your own risk. No warranties, no guarantees, no liability.
- This tool was vibe coded with Claude by @riversen.
Comprehensive LDAP enumeration designed to extract as much data as possible from an anonymously-accessible directory. Handles several ForgeRock-specific issues that break generic tools:
- Paged Results control denied — ForgeRock commonly blocks the Simple Paged Results control (OID
1.2.840.113556.1.4.319) for anonymous binds. The tool detects this on the first query and automatically falls back to unpaged searches for the rest of the session. *wildcard doesn't return attributes — ForgeRock with restrictive ACIs often ignores the*return-all-attributes request for anonymous binds, silently returning only RDN attributes. The tool probes a sample entry to detect this and switches to explicitly naming every attribute it wants.- Server size limits — Without paging, servers often cap results (e.g., 1000 per query). The wildcard enumeration automatically drills deeper (
a*→aa*,ab*, …) when it detects truncated results. - Base DN discovery — Automatically discovers the base DN from the Root DSE
namingContextsif you don't provide one, filtering out internal ForgeRock contexts (cn=config,cn=schema, etc.).
- Root DSE — Server info, vendor, naming contexts
- Attribute probing — Discovers which attributes are actually readable by anonymous binds
- Directory tree mapping — Recursive OU/container walk
- Schema enumeration — Discovers all attribute type definitions
- Full subtree dump — Attempts
(objectClass=*)with collected attribute list - ObjectClass sweep — Searches by common objectClasses (inetOrgPerson, posixAccount, groups, etc.)
- Wildcard brute-force —
uidandcnwildcards acrossa-z,0-9, and special characters (. _ - + @ $ ! # & ' ~and space), with RFC 4515 filter escaping and adaptive depth - Interesting attribute hunt — Searches for entries with high-value fields populated (
userPassword,sshPublicKey,description,info,ds-privilege-name, etc.) - Summary — Object class distribution, attribute population stats, high-value findings flagged
# System deps (required to build python-ldap)
sudo apt install -y libldap2-dev libsasl2-dev
# Option 1: venv (recommended)
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
# Option 2: system-wide (Kali / PEP 668 systems)
pip install -r requirements.txt --break-system-packages
# Make executable
chmod +x ldapdigger.py# Base DN auto-discovered
./ldapdigger.py -H ldap://10.10.10.1:389 --full -v -o loot.json
# Explicit base DN
./ldapdigger.py -H ldap://10.10.10.1:1389 -b "dc=corp,dc=local" --full -o loot.json
# All export formats at once
./ldapdigger.py -H ldap://10.10.10.1:389 --full \
-o results.json \
--ldif full_dump.ldif \
--csv users.csv \
--userlist uids.txtCreate a target file with one host per line — full URIs, host:port, or bare hostnames (defaults to port 389):
# targets.txt
ldap://10.82.148.32:1389
10.82.148.33:389
10.82.148.34
# comments and blank lines are ignored
./ldapdigger.py -L targets.txt --full -o results.json --userlist uids.txt
# Non-standard port for bare hostnames
./ldapdigger.py -L targets.txt -p 1389 --full -o results.jsonOutput files are automatically tagged per host to avoid clobbering, e.g. results_10.82.148.32_1389.json, results_10.82.148.33_389.json. Failed hosts are skipped and the run continues.
./ldapdigger.py -H ldap://10.10.10.1:389 -iInteractive commands:
| Command | Description |
|---|---|
search <filter> [base] |
Raw LDAP filter search, e.g. search (uid=admin*) |
read <dn> |
Dump all attributes on a specific DN |
children [dn] |
List immediate children of a DN |
users [prefix] |
Quick user listing, e.g. users adm |
groups |
Enumerate all groups with membership |
find <attr> <pattern> |
Hunt for values, e.g. find description *password* |
tree [depth] |
Show directory tree structure |
schema [term] |
Browse schema attribute types |
dse |
Show Root DSE |
base [new_dn] |
Show or change search base |
run |
Execute full automated pipeline |
dump <fmt> <file> |
Export: dump json results.json |
count |
Show collected entry count |
quit |
Exit |
# ObjectClass sweep only
./ldapdigger.py -H ldap://10.10.10.1:389 --oc-sweep -o results.json
# Wildcard enumeration only
./ldapdigger.py -H ldap://10.10.10.1:389 --wildcard -o results.json
# Tree structure only
./ldapdigger.py -H ldap://10.10.10.1:389 --dump-tree| Flag | Description |
|---|---|
-H, --uri |
LDAP URI (e.g., ldap://host:port) |
-L, --target-list |
File with LDAP targets, one per line (URI, host:port, or hostname) |
-p, --port |
Default port for bare hostnames in target list (default: 389) |
-b, --base-dn |
Base DN. Auto-discovered if omitted |
-i, --interactive |
Launch interactive shell |
--full |
Run full enumeration pipeline |
--oc-sweep |
ObjectClass sweep only |
--wildcard |
Wildcard uid/cn enumeration only |
--dump-tree |
Directory tree structure only |
-v, --verbose |
Verbose output |
-t, --timeout |
LDAP timeout in seconds (default: 10) |
--page-size |
Paged results page size (default: 500) |
-o, --output |
Output file (format from extension: .json, .ldif, .csv) |
--json |
Export JSON to file |
--ldif |
Export LDIF to file |
--csv |
Export user-centric CSV |
--userlist |
Export plain uid list (one per line) |
Standalone terminal viewer for the JSON output. No dependencies beyond Python 3.
# Browse with color
./ldapdigger_view.py loot.json | less -R
# Entries with "password" anywhere
./ldapdigger_view.py loot.json -s password
# Only entries with description, show specific fields
./ldapdigger_view.py loot.json -f description -a uid,description
# Attribute population stats
./ldapdigger_view.py loot.json --stats
# Dump unique emails for a list
./ldapdigger_view.py loot.json --dump mail > emails.txtldapdomaindump and most LDAP enumeration tools are built for Active Directory. They expect AD-specific attributes (sAMAccountName, userAccountControl, servicePrincipalName, etc.) and AD schema structure. Against ForgeRock/OpenDJ they'll either error out or produce mostly empty output.
ldapdigger handles ForgeRock's specific access control behavior, attribute return quirks, and paging restrictions that AD-focused tools don't account for.
Do whatever you want with it.