ldapdomaindump is a Python-based Active Directory enumeration tool that connects to a domain controller over LDAP and dumps comprehensive information about domain users, groups, computers, trusts, and policies into both human-readable HTML reports and machine-readable JSON/greppable files. Written by Dirk-jan Mollema as part of the “dirkjanm” toolset (the same author behind mitm6 and pywerview), it is widely used during the internal reconnaissance phase of Active Directory penetration tests because it requires nothing more than valid (even low-privileged) domain credentials, or in some misconfigured environments, an anonymous/null LDAP bind. The output gives an attacker (or auditor) a fast, structured overview of the domain’s user base, privileged group memberships, password policy, and computer inventory — all without needing to run noisy tools against every host individually.
Lightweight Directory Access Protocol (LDAP) is the primary protocol Active Directory uses to store and query directory information — users, groups, computers, organizational units, group policies, and trust relationships. Any authenticated domain user (by default) can query a significant portion of this data, making LDAP enumeration one of the highest-value, lowest-noise reconnaissance techniques in an AD environment.
ldapdomaindump automates this process. It performs an LDAP bind to a target domain controller and systematically enumerates:
- Domain users, including attributes like last logon, password last set, and account flags (disabled, locked out, “password never expires,” etc.)
- Domain groups and their memberships, especially privileged groups (Domain Admins, Enterprise Admins)
- Computer accounts (workstations and servers) with OS version information
- Domain trusts
- Domain password and lockout policy
- Group Policy Object (GPO) metadata
It produces output in several formats simultaneously: styled HTML pages (for easy browsing), JSON (for scripting/parsing), and grep-friendly plaintext, making it equally useful for manual review and downstream automation (e.g., feeding data into BloodHound-style analysis or custom scripts).
Installation
ldapdomaindump is written in Python 3 and distributed via pip, and is also packaged directly in Kali’s repositories.
Installing via apt (Kali)
sudo apt update
sudo apt install ldapdomaindump -y
Verify:
ldapdomaindump --help
Installing via pip
pip3 install ldapdomaindump --break-system-packages
Installing from source (GitHub)
git clone https://github.com/dirkjanm/ldapdomaindump.git
cd ldapdomaindump
pip3 install . --break-system-packages
Verifying dependencies
ldapdomaindump depends on ldap3 and dnspython:
pip3 install ldap3 dnspython --break-system-packages
Confirm the version installed:
ldapdomaindump --version
Expected output:
ldapdomaindump 0.10.0
Syntax
General syntax:
ldapdomaindump [OPTIONS] <HOSTNAME_OR_IP>
Basic authenticated connection:
ldapdomaindump -u 'CORP\jsmith' -p 'Summer2026!' ldap://10.10.10.5
Anonymous/null bind attempt (only works if the DC allows it):
ldapdomaindump ldap://10.10.10.5
Command Line Options
| Flag | Description |
|---|---|
-u, --user USER | Username for LDAP bind, in DOMAIN\user or user@domain format |
-p, --password PASS | Password for the bind account (prompted securely if omitted) |
-at, --authtype TYPE | Authentication type: NTLM (default) or SIMPLE |
-o, --outdir DIR | Output directory for generated report files (default: current directory) |
-n, --dns-server SERVER | Alternate DNS server to use for resolving the domain controller |
-r, --resolve | Resolve computer hostnames to IP addresses in the output |
--no-json | Disable JSON output generation |
--no-html | Disable HTML output generation |
--no-grep | Disable grepable output generation |
-d, --delimiter CHAR | Delimiter character used in grepable output files (default tab) |
-m, --minimal | Only dump minimal object attributes, for faster runs against large domains |
-C, --no-cache | Disable caching, forcing a full attribute lookup for every object |
--port PORT | Specify a custom LDAP port (default 389, or 636 for LDAPS) |
-s, --ssl | Force an LDAPS (SSL/TLS) connection |
-gc, --gc | Query the Global Catalog port (3268) instead of standard LDAP |
--user-file FILE | Only dump attributes for usernames listed in this file |
Basic Usage
Running a standard authenticated dump against a domain controller:
ldapdomaindump -u 'CORP\jsmith' -p 'Summer2026!' -o /home/kali/loot/corp_dump ldap://10.10.10.5
Expected output:
[*] Connecting to host...
[*] Binding to host
[+] Bind OK
[*] Starting domain dump
[+] Domain dump finished
The specified output directory will then contain:
ls /home/kali/loot/corp_dump
domain_computers.html domain_computers.json domain_computers.grep
domain_groups.html domain_groups.json domain_groups.grep
domain_policy.html domain_policy.json domain_policy.grep
domain_trusts.html domain_trusts.json domain_trusts.grep
domain_users.html domain_users.json domain_users.grep
domain_users_by_group.html
index.html
Practical Examples with Output
Example 1 — Basic authenticated dump
ldapdomaindump -u 'CORP\jsmith' -p 'Summer2026!' ldap://10.10.10.5
[*] Connecting to host...
[*] Binding to host
[+] Bind OK
[*] Starting domain dump
[+] Domain dump finished
Example 2 — Dump using NTLM hash instead of password (via ldap3 pass-the-hash string)
ldapdomaindump -u 'CORP\jsmith' -p 'aad3b435b51404eeaad3b435b51404ee:8846f7eaee8fb117ad06bd6bb76e3fdd' ldap://10.10.10.5
[*] Connecting to host...
[*] Binding to host
[+] Bind OK
[*] Starting domain dump
[+] Domain dump finished
Example 3 — Specifying an output directory
ldapdomaindump -u 'CORP\jsmith' -p 'Summer2026!' -o /home/kali/loot/corp_ldap ldap://10.10.10.5
[*] Connecting to host...
[*] Binding to host
[+] Bind OK
[*] Starting domain dump
[+] Domain dump finished
Example 4 — Forcing an LDAPS (SSL) connection on port 636
ldapdomaindump -u 'CORP\jsmith' -p 'Summer2026!' -s --port 636 ldap://10.10.10.5
[*] Connecting to host...
[*] Binding to host
[+] Bind OK (SSL)
[*] Starting domain dump
[+] Domain dump finished
Example 5 — Resolving computer hostnames to IPs
ldapdomaindump -u 'CORP\jsmith' -p 'Summer2026!' -r -o /home/kali/loot/resolved ldap://10.10.10.5
[*] Connecting to host...
[*] Binding to host
[+] Bind OK
[*] Starting domain dump
[*] Resolving computer hostnames...
[+] Domain dump finished
Example 6 — Minimal dump for large/slow domains
ldapdomaindump -u 'CORP\jsmith' -p 'Summer2026!' -m -o /home/kali/loot/minimal ldap://10.10.10.5
[*] Connecting to host...
[*] Binding to host
[+] Bind OK
[*] Starting domain dump (minimal mode)
[+] Domain dump finished
Example 7 — Disabling HTML output, keeping only JSON/grep
ldapdomaindump -u 'CORP\jsmith' -p 'Summer2026!' --no-html -o /home/kali/loot/json_only ldap://10.10.10.5
[*] Connecting to host...
[*] Binding to host
[+] Bind OK
[*] Starting domain dump
[+] Domain dump finished
Example 8 — Inspecting the domain password policy output
cat /home/kali/loot/corp_ldap/domain_policy.grep
Domain Min password length Password history size Lockout threshold Min password age Max password age
CORP.LOCAL 8 24 5 1 day 90 days
Example 9 — Grepping for disabled accounts in the user dump
grep -i "ACCOUNTDISABLE" /home/kali/loot/corp_ldap/domain_users.grep | wc -l
14
Example 10 — Grepping for Domain Admins group membership
grep -A5 "Domain Admins" /home/kali/loot/corp_ldap/domain_groups.grep
Domain Admins
CORP\Administrator
CORP\svc_backup
CORP\jdoe
Example 11 — Querying the Global Catalog port for a forest-wide view
ldapdomaindump -u 'CORP\jsmith' -p 'Summer2026!' -gc --port 3268 -o /home/kali/loot/gc_dump ldap://10.10.10.5
[*] Connecting to host...
[*] Binding to host
[+] Bind OK (Global Catalog)
[*] Starting domain dump
[+] Domain dump finished
Example 12 — Attempting an anonymous/null bind
ldapdomaindump -o /home/kali/loot/anon_dump ldap://10.10.10.5
[*] Connecting to host...
[*] Binding to host
[+] Anonymous bind OK
[*] Starting domain dump
[+] Domain dump finished
Common Use Cases
- Initial internal reconnaissance — as soon as any valid domain credentials (even a low-privileged user) are obtained, run ldapdomaindump to get a full picture of the domain structure.
- Identifying privileged accounts and groups — quickly locating Domain Admins, Enterprise Admins, and other high-value group memberships for targeting.
- Password policy assessment — checking minimum password length, lockout threshold, and complexity requirements to plan safe password-spraying attacks that avoid account lockout.
- Stale/misconfigured account discovery — identifying accounts with “password never expires,” disabled accounts still in privileged groups, or accounts with old
pwdLastSetvalues. - Computer inventory and OS fingerprinting — reviewing
operatingSystemattributes acrossdomain_computersoutput to find outdated/unsupported OS versions (e.g., Windows Server 2008, Windows 7). - Feeding downstream tooling — using the JSON output as input for custom scripts, or cross-referencing with BloodHound data for a fuller attack-path picture.
- Trust relationship mapping — reviewing
domain_trustsoutput to identify cross-domain or cross-forest trusts that could be leveraged for lateral movement.
Automation with Bash
Bash script to run a full dump and organize output by date
#!/bin/bash
# run_ldapdomaindump.sh - automate a dated domain dump
DC_IP="10.10.10.5"
USER='CORP\jsmith'
PASS='Summer2026!'
DATESTAMP=$(date +%Y-%m-%d)
OUTDIR="/home/kali/loot/ldapdump_${DATESTAMP}"
mkdir -p "$OUTDIR"
echo "[*] Running ldapdomaindump against $DC_IP"
ldapdomaindump -u "$USER" -p "$PASS" -o "$OUTDIR" -r "ldap://${DC_IP}"
echo "[+] Dump complete. Output stored in $OUTDIR"
Bash script to auto-extract Domain Admins from the grep output
#!/bin/bash
# extract_domain_admins.sh - pull domain admin usernames from an existing dump
DUMPDIR="$1"
if [ -z "$DUMPDIR" ]; then
echo "Usage: $0 <path_to_dump_dir>"
exit 1
fi
echo "[*] Domain Admins found:"
grep -A20 "^Domain Admins" "${DUMPDIR}/domain_groups.grep" | grep -E "CORP\\\\"
Bash script to loop the dump across multiple discovered domain controllers
#!/bin/bash
# multi_dc_dump.sh - run ldapdomaindump against every DC in a list
DC_LIST="dc_ips.txt"
USER='CORP\jsmith'
PASS='Summer2026!'
while read -r dc; do
echo "[*] Dumping $dc"
ldapdomaindump -u "$USER" -p "$PASS" -o "/home/kali/loot/dc_${dc//./_}" "ldap://${dc}"
done < "$DC_LIST"
echo "[+] All DC dumps complete."
Tips and Best Practices
- Always attempt with valid low-privileged credentials first; domain-wide LDAP read access rarely requires elevated rights.
- Test an anonymous bind (
ldapdomaindump ldap://<target>with no-u/-p) early — some legacy or misconfigured DCs still permit it and require zero credentials. - Use
-rsparingly on large domains; hostname resolution significantly increases run time. - Review
domain_policyoutput before running any password spraying attack, to calculate a safe number of guesses under the lockout threshold. - Cross-reference
domain_users_by_group.htmlfor a fast visual view of nested group membership, especially for privileged groups. - Store dump output securely; it contains a full inventory of the organization’s users, computers, and security policy, which is sensitive reconnaissance data.
- Combine ldapdomaindump’s fast overview with BloodHound/SharpHound for deeper attack-path graph analysis; they complement rather than replace each other.
- Use
--no-htmlon engagements where you only need machine-parseable data, to save disk space and processing time.
Troubleshooting
| Issue | Likely Cause | Resolution |
|---|---|---|
ldap3.core.exceptions.LDAPBindError | Invalid credentials or wrong auth type | Verify username format (DOMAIN\user); try -at SIMPLE if NTLM bind fails |
| Connection refused | LDAP port closed or filtered | Confirm with nmap -p389,636,3268 <target>; check network path/firewall rules |
| Anonymous bind fails | DC does not permit anonymous LDAP (default on modern AD) | Use valid credentials instead; anonymous bind is increasingly rare on hardened domains |
| Dump completes but files are nearly empty | Bind account has extremely restricted read permissions | Confirm account isn’t in a restricted OU; test with a different low-privileged account if available |
SSL handshake failure with -s | Target requires a specific TLS version or valid certificate chain | Try without -s on port 389 first, or verify DC’s LDAPS certificate configuration |
| Script hangs on large domains | Full (non-minimal) dump against a very large AD environment | Use -m for a minimal/faster dump, or --no-json/--no-html to reduce processing overhead |
dns.resolver.NXDOMAIN errors with -r | Internal DNS not reachable from Kali | Specify the domain’s internal DNS server explicitly with -n <dns_ip> |
References
- Official ldapdomaindump repository: https://github.com/dirkjanm/ldapdomaindump
- Kali Linux tool page: https://www.kali.org/tools/ldapdomaindump/
- Dirk-jan Mollema’s blog: https://dirkjanm.io/
- Microsoft LDAP documentation: https://learn.microsoft.com/en-us/windows/win32/adschema/lightweight-directory-access-protocol-ldap-api
- MITRE ATT&CK — Account Discovery: Domain Account (T1087.002): https://attack.mitre.org/techniques/T1087/002/
