Post

LDAPHunter - LDAP Enumeration Tool for Pentesters

A Python tool for automating LDAP enumeration against Active Directory during offensive engagements.

LDAPHunter - LDAP Enumeration Tool for Pentesters

Why I Built It

If you have run a few Active Directory engagements, you already know the rhythm. You land on the internal network, you fire up a handful of enumeration commands, and ten minutes later you are staring at five terminal windows, pasting filters into ldapsearch, re-running crackmapexec with slightly different flags, and copying output into a notes file that grows scarier by the hour.

Most of that is mechanical. Same queries, same attributes, same tables. I got tired of doing it by hand, so I built LDAPHunter: a Python tool that runs the common LDAP enumeration checks against Active Directory and prints the results as clean tables you can paste straight into a report.

ldaphunter Repository: https://github.com/GhnimiWael/LDAPHunter


What It Does

LDAPHunter targets the information you actually care about on a pentest:

  • Users: SAM account names, display names, description fields, UAC flags, last logon timestamps, password-never-expires flags.
  • Groups and privileged memberships: Domain Admins, Enterprise Admins, Schema Admins, Backup Operators, and anything else that lets you pivot.
  • Organizational Units (OUs): the shape of the directory, useful when you need to target a specific business unit.
  • Password policies: length, lockout threshold, age. These are the values you need before you even think about password spraying.
  • Delegation flags: unconstrained delegation in particular, because those accounts are gifts.
  • Non-standard attributes: sometimes admins drop credentials or connection strings into description or custom fields. The tool surfaces those so you can skim them quickly.

It is not meant to replace BloodHound or PowerView. It runs before them, gives you a snapshot of what is in the directory, and feeds the next steps of the engagement.


Installation

Requirements are light. Python 3 plus two libraries:

1
pip install ldap3 prettytable

Then clone the repo:

1
2
git clone https://github.com/GhnimiWael/LDAPHunter.git
cd LDAPHunter

That is it. No Docker, no virtualenv gymnastics. It runs on Kali, on a WSL shell, on a jumpbox.


Usage

LDAPHunter supports three authentication modes. Pick the one that matches what you have.

Authenticated bind

If you already have creds (phished, sprayed, found in a file share), pass them in:

1
python ldap_hunter.py -s 10.10.10.100 -d domain.lab -u 'domain\user' -P 'Password123!'

The -u flag accepts both DOMAIN\user and [email protected] formats. If one fails, try the other. Some DCs prefer one style over the other depending on how they are configured.

Anonymous bind

Not every DC allows this, but when it does, it can save you an hour during the first phase of an internal pentest:

1
python ldap_hunter.py -s 10.10.10.100 -d domain.lab --no-auth

If the server refuses the bind, you will see it quickly and move on to credential acquisition.

LDAPS (encrypted)

When port 389 is filtered but 636 is open, use LDAPS:

1
python ldap_hunter.py -s 10.10.10.100 -d domain.lab -u 'domain\user' -P 'Password123!' --ssl

What You Get

Output is tabular. Users, groups, OUs, password policies, and delegation findings are printed as readable tables. A few notes on what the tool highlights:

  • Accounts with PasswordNeverExpires get flagged. These are usually service accounts, and service accounts are usually interesting.
  • LastLogon timestamps help you pick targets that are actively used versus stale accounts that may not be monitored.
  • When a description or custom attribute contains something suspicious (long strings, what looks like credentials, connection URIs), the tool calls it out so you do not miss it while scrolling through.

Troubleshooting

Common issues I have hit, and what to check:

  • Connection refused on 389: verify the host is actually a DC and the port is open. Try --ssl to fall back to 636.
  • Attribute errors on custom schemas: some environments extend the schema with attributes that break generic lookups. The tool tries to auto-detect, but if you see one specific attribute failing, open an issue and paste the schema line.
  • Anonymous bind rejected: expected on most hardened DCs. Grab creds and retry with -u / -P.
  • Auth fails with a password you know is correct: try the other username format (user@domain vs DOMAIN\user). Also confirm the account is not locked out from prior tooling.

Roadmap

Things on the backlog that I want to ship:

  • Kerberoasting output built in (currently you can find SPN-bearing accounts, but you still have to run Rubeus or GetUserSPNs.py separately).
  • AS-REP roasting identification (DONT_REQ_PREAUTH flag).
  • SID bruteforce mode for when only anonymous LDAP is allowed but RID-cycle is worth a shot.
  • JSON and CSV output so the results can be fed into BloodHound ingestion or report automation.

If you hit a bug or want a feature, the issue tracker is open.


Get It

If it saves you five minutes on your next engagement, it has paid for itself.

This post is licensed under CC BY 4.0 by the author.