Install
npx skillscat add blacklanternsecurity/red-run/ad-discovery Install via the SkillsCat registry.
AD Attack Discovery
You are helping a penetration tester enumerate an Active Directory domain and
identify attack paths. All testing is under explicit written authorization.
This skill works at three access levels:
- No credentials — network-level recon, poisoning, RID cycling
- Username only — AS-REP roasting, Kerberos user validation
- Valid credentials — full enumeration, BloodHound, ADCS, ACLs
Engagement Logging
Check for ./engagement/ directory. If absent, proceed without logging.
When an engagement directory exists:
- Print
[ad-discovery] Activated → <target>to the screen on activation. - Evidence → save significant output to
engagement/evidence/with
descriptive filenames (e.g.,sqli-users-dump.txt,ssrf-aws-creds.json).
Do NOT write to engagement/activity.md, engagement/findings.md, or
engagement state. The orchestrator maintains these files. Report all findings
in your return summary.
Scope Boundary
This skill covers Active Directory discovery — enumerating domain objects,
identifying misconfigurations, and routing to technique skills. When you reach
the boundary of this scope — whether through a routing instruction ("Route to
skill-name") or by discovering findings outside your domain — STOP.
Do not load or execute another skill. Do not continue past your scope boundary.
Instead, return to the orchestrator with:
- What was found (vulns, credentials, access gained)
- Recommended next skill (the bold skill-name from routing instructions)
- Context to pass (injection point, target, working payloads, etc.)
The orchestrator decides what runs next. Your job is to execute this skill
thoroughly and return clean findings.
Stay in methodology. Only use techniques documented in this skill. If you
encounter a scenario not covered here, note it and return — do not improvise
attacks, write custom exploit code, or apply techniques from other domains.
The orchestrator will provide specific guidance or route to a different skill.
You MUST NOT:
- Perform Kerberoasting or AS-REP roasting beyond identifying targets — route
to kerberos-roasting - Exploit delegation misconfigurations — route to kerberos-delegation
- Exploit ACL misconfigurations — route to acl-abuse
- Perform credential dumping — route to credential-dumping
- Forge tickets — route to kerberos-ticket-forging
- Perform coercion or relay attacks — route to auth-coercion-relay
- Exploit ADCS beyond enumeration — route to adcs-template-abuse or
adcs-access-and-relay
When you find exploitable attack paths: update state.md, log to activity.md,
and present routing recommendations. Do not continue past enumeration.
State Management
Call get_state_summary() from the state-interim MCP server to read current
engagement state. Use it to:
- Skip re-testing targets, parameters, or vulns already confirmed
- Leverage existing credentials or access for this technique
- Understand what's been tried and failed (check Blocked section)
Interim Writes
Write actionable findings immediately via state-interim so the orchestrator
can react in real time (via event watcher) instead of waiting for your full
return summary. Use these tools as you discover findings:
add_credential()— valid credentials (pre-created computer accounts, gMSA readable, cleartext in descriptions/GPP/shares)add_vuln()— ADCS misconfigs (ESC1-ESC8), Kerberoastable accounts, coercion vectors, SMB signing disabled, LDAP signing not requiredadd_pivot()— delegation paths, ACL abuse chains, trust relationships, new subnets from AD Sitesadd_blocked()— techniques attempted and failed (so orchestrator doesn't re-route)
Do NOT write to activity.md, findings.md, or modify targets/ports/access.
The orchestrator manages those. Still report all findings in your return summary —
interim writes supplement it, they don't replace it.
Your return summary must include:
- New targets/hosts discovered (with ports and services)
- New credentials or tokens found
- Access gained or changed (user, privilege level, method)
- Vulnerabilities confirmed (with status and severity)
- Pivot paths identified (what leads where)
- Blocked items (what failed and why, whether retryable)
Prerequisites
- Network access to the target domain (ports 88, 135, 389, 445, 636)
- For unauthenticated enumeration: just network access
- For authenticated enumeration: valid domain credentials (any privilege level)
- Tools:
netexec(nxc),bloodhound-pythonorrusthound-ce,certipy,bloodyAD,kerbrute, Impacket suite (GetUserSPNs.py,GetNPUsers.py,lookupsid.py)
Kerberos-first authentication (when credentials are available):
This skill may start unauthenticated. Once credentials are obtained, switch
to Kerberos authentication for all subsequent enumeration:
# Get a TGT (password, hash, or AES key)
# Use getTGT.py or impacket-getTGT — both are the same tool (see Troubleshooting)
getTGT.py DOMAIN/user:'Password123'@dc.domain.local
# or with NTLM hash
getTGT.py DOMAIN/user@dc.domain.local -hashes :NTHASH
export KRB5CCNAME=user.ccache
# Then use -k -no-pass on all Impacket tools
# Use --use-kcache on NetExec
# Use -k on Certipy and bloodyADStep 1: Initial Reconnaissance
Identify domain controllers and assess the network posture.
Find Domain Controllers
# DNS SRV records
nslookup -type=srv _ldap._tcp.dc._msdcs.DOMAIN.LOCAL
nslookup -type=srv _kerberos._tcp.DOMAIN.LOCAL
# NetExec SMB scan — shows OS, signing, SMBv1
nxc smb 10.10.10.0/24
# NetExec generate /etc/hosts entries
nxc smb 10.10.10.0/24 --generate-hosts-file hostsCheck Signing and Relay Posture
# SMB signing — signing:False = relay target
nxc smb 10.10.10.0/24 | grep -i "signing:False"
# LDAP signing — signing:None = relay to LDAP viable
nxc ldap DC01.DOMAIN.LOCAL
# Determine if LDAPS is available
nxc ldap DC01.DOMAIN.LOCAL --port 636Findings:
- SMB signing disabled on non-DCs -> note for auth-coercion-relay
- LDAP signing not required -> note for auth-coercion-relay (relay to LDAP)
- Domain name, DC hostnames, OS versions -> record in the engagement state
Interim writes:
- SMB signing disabled →
add_vuln(title="SMB signing disabled on <host>", host="<host>", vuln_type="smb-signing", severity="medium") - LDAP signing not required →
add_vuln(title="LDAP signing not required on <host>", host="<host>", vuln_type="ldap-signing", severity="medium") - Domain name/hostnames discovered →
add_pivot(source="AD discovery", destination="<domain>/<hostname>", method="DNS/SMB enumeration")
Step 2: Unauthenticated Enumeration
Use when no valid credentials are available yet.
Null Session / Guest Access
# SMB null session
nxc smb DC01.DOMAIN.LOCAL -u '' -p ''
nxc smb DC01.DOMAIN.LOCAL -u 'guest' -p ''
# enum4linux
enum4linux -a -u "" -p "" DC01.DOMAIN.LOCAL
# rpcclient
rpcclient -U "" -N DC01.DOMAIN.LOCAL -c "enumdomusers;enumdomgroups;querydominfo"RID Cycling (Unauthenticated User Enumeration)
# NetExec — enumerate users via RID brute force
nxc smb DC01.DOMAIN.LOCAL -u 'guest' -p '' --rid-brute 10000
# Impacket
lookupsid.py -no-pass 'guest@DC01.DOMAIN.LOCAL' 20000
# Extract just usernames
nxc smb DC01.DOMAIN.LOCAL -u '' -p '' --rid-brute \
| awk -F'\\\\| ' '/SidTypeUser/ {print $3}' > users.txtKerberos Username Enumeration
# kerbrute — validates usernames via Kerberos pre-auth responses
# Generates Event 4771, NOT 4625 (often less monitored)
kerbrute userenum -d DOMAIN.LOCAL --dc DC01.DOMAIN.LOCAL usernames.txtUse output as username list for password-spraying and AS-REP roasting checks.
Unauthenticated ADCS CA Enumeration
# Enumerate Certificate Authorities via RPC — no credentials needed
nxc smb DC01.DOMAIN.LOCAL -M enum_caIf CAs found, note for authenticated ADCS enumeration in Step 3 (certipy).
LLMNR/NBT-NS/mDNS Poisoning Check
If network position allows, note LLMNR/NBT-NS traffic for Responder-based
hash capture. → STOP. Return to orchestrator recommending auth-coercion-relay.
Pass: DC IP, domain name, network position, LLMNR/NBT-NS traffic details.
Do not execute poisoning or relay commands inline.
Step 3: BloodHound Collection
The single highest-value enumeration step. Requires valid domain credentials.
Linux (Remote Collection)
# bloodhound-python — LDAP-based, remote
bloodhound-python -d DOMAIN.LOCAL -u 'user' -p 'Password123' \
-gc DC01.DOMAIN.LOCAL -c all -ns DC_IP
# rusthound-ce — faster, includes ADCS data
rusthound-ce -d DOMAIN.LOCAL -u 'user@DOMAIN.LOCAL' -p 'Password123' \
-o /tmp/bloodhound -z --adcs
# With Kerberos auth
export KRB5CCNAME=user.ccache
bloodhound-python -d DOMAIN.LOCAL -u 'user' -k -no-pass \
-gc DC01.DOMAIN.LOCAL -c allWindows (On-Host Collection)
# SharpHound — full collection
.\SharpHound.exe -c all -d DOMAIN.LOCAL --searchforest
# Stealthier — DC-only mode (no host enumeration)
.\SharpHound.exe --CollectionMethod DCOnly
# OPSEC — throttle and randomize
.\SharpHound.exe -c all,GPOLocalGroup --throttle 10000 --jitter 23
# SOAPHound — uses ADWS instead of LDAP (avoids LDAP monitoring)
SOAPHound.exe --buildcache -c c:\temp\cache.txt
SOAPHound.exe -c c:\temp\cache.txt --bhdump -o c:\temp\bh-output
SOAPHound.exe -c c:\temp\cache.txt --certdump -o c:\temp\bh-outputADCS Certificate Data
# Certipy — full certificate template enumeration
certipy find 'DOMAIN/user:Password123@DC01.DOMAIN.LOCAL' \
-output engagement/evidence/certipy-full-DOMAIN
# Find vulnerable templates only
certipy find 'DOMAIN/user:Password123@DC01.DOMAIN.LOCAL' -vulnerable -hide-admins \
-output engagement/evidence/certipy-vulnerable-DOMAIN
# With Kerberos
certipy find 'DOMAIN/user@DC01.DOMAIN.LOCAL' -k \
-output engagement/evidence/certipy-full-DOMAINInterim writes: Vulnerable ADCS templates found →add_vuln(title="ADCS <ESC_type> on <template>", host="<CA_host>", vuln_type="adcs", severity="high").
Certipy output: Always use -output engagement/evidence/certipy-<label>
to write results to the evidence directory. Without -output, certipy writes{timestamp}_Certipy.{json,txt} to CWD, polluting the working directory.
Certipy version notes:
- Certipy v5.0+ removed the
-bloodhoundflag. Runcertipy findwithout it
— v5 outputs JSON by default. Import the JSON into BloodHound CE manually. - If
-vulnerablereturns 0 results, re-run without it to get the full
template list. Some ESC variants (ESC9-15) require manual analysis of the
full output rather than certipy's built-in vulnerability checks.
BloodHound Analysis Priorities
After importing data, run these queries first:
- Shortest Paths to Domain Admins — identify the quickest win
- Kerberoastable Users — prioritize by blast radius and pwdLastSet age
- AS-REP Roastable Users — free hashes, no special access needed
- Unconstrained Delegation — TGT harvesting opportunities
- Dangerous ACLs — GenericAll/WriteDACL/WriteOwner on high-value targets
- ADCS Attack Paths — ESC1-ESC15 (requires certipy data import)
- Owned -> Domain Admins — mark owned principals and find chains
Step 4: Targeted Enumeration
Deeper enumeration beyond BloodHound. Run these based on what BloodHound reveals.
Password Policy
# NetExec
nxc smb DC01.DOMAIN.LOCAL -u 'user' -p 'Password123' --pass-pol
# enum4linux
enum4linux -u 'user' -p 'Password123' -P DC01.DOMAIN.LOCAL
# PowerView
(Get-DomainPolicy)."SystemAccess"Record lockout threshold, observation window, complexity requirements. Pass
to password-spraying skill.
Fine-Grained Password Policies (PSOs)
# Fine-grained password policies — different groups may have different lockout rules
nxc ldap DC01.DOMAIN.LOCAL -u 'user' -p 'Password123' -M psoPSOs override default domain policy for specific groups. A service account
group may have no lockout while user accounts lock at 5 attempts. Report any
PSOs found — they affect password-spraying decisions.
Pre-Windows 2000 Computer Accounts
High-value quick win. Pre-created computer accounts (created via "Pre-Windows
2000 Compatible" checkbox in ADUC or New-ADComputer) often have their password
set to the sAMAccountName in lowercase, minus the trailing $. For example,MS01$ has password ms01. This is a common administrative oversight that
yields machine account credentials with zero noise.
# Identify pre-created computer accounts and test default passwords
# The module checks for accounts and attempts TGT with default password
nxc ldap DC01.DOMAIN.LOCAL -u 'user' -p 'Password123' -M pre2kWhat pre2k checks:
- Finds computer accounts in the "Pre-Windows 2000 Compatible Access" group
or withuserAccountControlflags indicating pre-creation - Tests each account with
sAMAccountName.rstrip('$').lower()as the password - Attempts to obtain a TGT — if successful, the password is confirmed
Why this matters:
- Machine accounts often have broad read rights (BloodHound "Owned" marking)
- Machine accounts in groups like "Domain Secure Servers" can read gMSA passwords
- Machine accounts may have constrained delegation, RBCD, or other privileges
- A pre2k computer account is functionally equivalent to a domain user credential
but with a machine account's group memberships and trust level
If pre2k finds valid machine credentials → write immediately:add_credential(username="MACHINE$", secret="machine", source="pre2k module on <DC>").
Also record in your return summary: account name, confirmed password, and any
group memberships or privileges visible from LDAP. The orchestrator will route
to appropriate technique skills (pass-the-hash, kerberos-delegation, etc.).
NetExec Module Sweep
Run these modules as a batch during authenticated enumeration. They are all
non-destructive and low-privilege — any domain user can run them.
Quick-Win Credential Checks
# User descriptions — frequently contain cleartext passwords
nxc ldap DC01.DOMAIN.LOCAL -u 'user' -p 'Password123' -M get-desc-users
# GPP cpassword in SYSVOL (MS14-025)
nxc smb DC01.DOMAIN.LOCAL -u 'user' -p 'Password123' -M gpp_password
# Autologon credentials from registry.xml in SYSVOL
nxc smb DC01.DOMAIN.LOCAL -u 'user' -p 'Password123' -M gpp_autologinUser descriptions are a common source of cleartext passwords — admins often
document initial passwords or service account passwords in the AD description
field. Any result containing password-like strings is a credential finding.
Write immediately: add_credential(username=..., secret=..., source="AD description field").
Coercion & Relay Surface
# WebClient service (WebDAV) — enables HTTP-based NTLM coercion
# Critical: if WebDAV is running, coercion can use HTTP instead of SMB
# which bypasses SMB signing and enables relay to LDAP/ADCS
nxc smb DC01.DOMAIN.LOCAL -u 'user' -p 'Password123' -M webdav
# Print Spooler — enables PrinterBug/SpoolSample coercion
nxc smb DC01.DOMAIN.LOCAL -u 'user' -p 'Password123' -M spooler
# Broad coercion vulnerability check (check-only mode — no LISTENER set)
# Tests for PetitPotam, PrinterBug, DFSCoerce, ShadowCoerce, MSEven, etc.
nxc smb DC01.DOMAIN.LOCAL -u 'user' -p 'Password123' -M coerce_plusNote all coercion-eligible hosts for auth-coercion-relay. WebDAV is
especially valuable — it enables HTTP-based coercion that works even when SMB
signing is enforced.
Interim writes: Coercion-eligible hosts →add_vuln(title="Coercion: <type> on <host>", host="<host>", vuln_type="coercion", severity="medium").
Attack Surface Mapping
# AV/EDR detection — identifies endpoint security products
nxc smb DC01.DOMAIN.LOCAL -u 'user' -p 'Password123' -M enum_av
# MachineAccountQuota — can current user add computer accounts?
# MAQ > 0 enables resource-based constrained delegation (RBCD) attacks
nxc ldap DC01.DOMAIN.LOCAL -u 'user' -p 'Password123' -M maq
# Obsolete/EOL operating systems — unpatched, vulnerable to known CVEs
nxc ldap DC01.DOMAIN.LOCAL -u 'user' -p 'Password123' -M obsolete
# BadSuccessor (dMSA) — CVE-2025-21293, privilege escalation via
# delegated Managed Service Accounts
nxc ldap DC01.DOMAIN.LOCAL -u 'user' -p 'Password123' -M badsuccessorNetwork Topology
# DNS records from AD — all A/AAAA/CNAME/SRV records in the domain
nxc ldap DC01.DOMAIN.LOCAL -u 'user' -p 'Password123' -M get-network
# AD Sites and Subnets — reveals internal network segmentation
nxc ldap DC01.DOMAIN.LOCAL -u 'user' -p 'Password123' -M subnets
# Additional network interfaces on hosts (multi-homed pivot targets)
nxc smb DC01.DOMAIN.LOCAL -u 'user' -p 'Password123' -M ioxidresolverSCCM and Infrastructure
# SCCM discovery via LDAP
nxc ldap DC01.DOMAIN.LOCAL -u 'user' -p 'Password123' -M sccm
# Entra ID (Azure AD Connect) sync server
nxc ldap DC01.DOMAIN.LOCAL -u 'user' -p 'Password123' -M entra-id
# DNS zones allowing nonsecure dynamic updates (ADIDNS poisoning)
nxc ldap DC01.DOMAIN.LOCAL -u 'user' -p 'Password123' -M dns-nonsecureIf SCCM found → note for sccm-exploitation. If Entra ID Connect server
found → high-value target (stores cleartext AD sync credentials). If
nonsecure DNS updates allowed → note for auth-coercion-relay (ADIDNS
poisoning enables MITM/coercion without LLMNR).
SPN Enumeration (Kerberoasting Targets)
# Impacket — list accounts with SPNs
GetUserSPNs.py DOMAIN/user:'Password123' -dc-ip DC_IP
# NetExec
nxc ldap DC01.DOMAIN.LOCAL -u 'user' -p 'Password123' --kerberoasting output.txt
# Rubeus — stats only (no ticket requests)
.\Rubeus.exe kerberoast /statsIf SPNs found on user accounts → STOP. Return to orchestrator recommending
kerberos-roasting. Pass: DC IP, domain name, SPN list, current credentials.
Do not request or crack service tickets inline.
AS-REP Roastable Accounts
# Impacket — enumerate users without pre-auth
GetNPUsers.py DOMAIN/user:'Password123' -dc-ip DC_IP
# bloodyAD — LDAP filter for DONT_REQ_PREAUTH
bloodyAD -u user -p 'Password123' -d DOMAIN.LOCAL --host DC_IP \
get search --filter '(&(userAccountControl:1.2.840.113556.1.4.803:=4194304)(!(UserAccountControl:1.2.840.113556.1.4.803:=2)))' \
--attr sAMAccountNameIf found → STOP. Return to orchestrator recommending kerberos-roasting
(AS-REP section). Pass: DC IP, domain name, AS-REP roastable user list, current
mode. Do not request or crack AS-REP hashes inline.
Delegation Enumeration
# Unconstrained delegation
bloodyAD -u user -p 'Password123' -d DOMAIN.LOCAL --host DC_IP \
get search --filter '(userAccountControl:1.2.840.113556.1.4.803:=524288)' \
--attr sAMAccountName,dNSHostName
# Constrained delegation
bloodyAD -u user -p 'Password123' -d DOMAIN.LOCAL --host DC_IP \
get search --filter '(msDS-AllowedToDelegateTo=*)' \
--attr sAMAccountName,msDS-AllowedToDelegateTo
# RBCD
bloodyAD -u user -p 'Password123' -d DOMAIN.LOCAL --host DC_IP \
get search --filter '(msDS-AllowedToActOnBehalfOfOtherIdentity=*)' \
--attr sAMAccountName
# PowerView
Get-DomainComputer -Unconstrained
Get-DomainUser -TrustedToAuth
Get-DomainComputer -TrustedToAuthInterim writes: Delegation paths found →add_pivot(source="<account>", destination="<target_service>", method="<unconstrained|constrained|RBCD> delegation").
If found → STOP. Return to orchestrator recommending kerberos-delegation.
Pass: DC IP, domain name, delegation type and targets, current credentials.
Do not exploit delegation inline.
Privileged Group Membership
# AdminCount=1 (privileged group members, may have stale perms)
nxc ldap DC01.DOMAIN.LOCAL -u 'user' -p 'Password123' --admin-count
# Specific dangerous groups
bloodyAD -u user -p 'Password123' -d DOMAIN.LOCAL --host DC_IP \
get object "DNSAdmins" --attr msds-memberTransitive
bloodyAD -u user -p 'Password123' -d DOMAIN.LOCAL --host DC_IP \
get object "Backup Operators" --attr msds-memberTransitiveLAPS / gMSA / dMSA
# LAPS — check if current user can read local admin passwords
nxc ldap DC01.DOMAIN.LOCAL -u 'user' -p 'Password123' -M laps
# gMSA — readable managed service account passwords
nxc ldap DC01.DOMAIN.LOCAL -u 'user' -p 'Password123' --gmsaIf readable → STOP. Return to orchestrator recommending credential-dumping.
Pass: DC IP, domain name, LAPS/gMSA target details, current credentials.
Do not extract managed passwords inline.
Trust Enumeration
# NetExec
nxc ldap DC01.DOMAIN.LOCAL -u 'user' -p 'Password123' -M enum_trust
# Impacket
nltest /domain_trusts /all_trusts /v
# PowerView
Get-DomainTrust
Get-NetForestDomain
Get-DomainForeignUser
Get-DomainForeignGroupMemberIf trusts found → STOP. Return to orchestrator recommending trust-attacks.
Pass: DC IP, domain name, trust relationships enumerated, trust types and
directions, current credentials. Do not exploit trust relationships inline.
Share Enumeration
# NetExec — find accessible shares
nxc smb 10.10.10.0/24 -u 'user' -p 'Password123' --shares
# Spider shares for sensitive files — use manspider for keyword/regex content search
# manspider runs from the attackbox via Bash (quick pass — orchestrator may task deeper review)
manspider DC01.DOMAIN.LOCAL -u 'user' -p 'Password123' -d DOMAIN \
-c password passwd cred secret connectionstring
manspider DC01.DOMAIN.LOCAL -u 'user' -p 'Password123' -d DOMAIN \
-e '(password|passwd|pwd)\s*[=:]\s*\S+' -f xml conf config ini txt ps1 bat vbs kdbxCheck SYSVOL/NETLOGON for Group Policy Preferences (GPP) passwords, scripts
with embedded credentials, and configuration files.
High-value file patterns in shares — when spidering user home directories,
SYSVOL, or custom shares, look for:
| Pattern | Why |
|---|---|
*.xml (especially azure.xml, gpp.xml, *.runconfig.xml) |
Azure AD credential exports (PSADPasswordCredential), GPP cpassword, deployment configs |
Groups.xml, Services.xml, Scheduledtasks.xml, DataSources.xml |
GPP passwords (MS14-025) — in SYSVOL Policies/ subdirectories |
web.config, *.config |
.NET connection strings, API keys |
*.ps1, *.bat, *.cmd, *.vbs |
Scripts with hardcoded credentials |
*.kdbx, *.key |
KeePass databases and key files |
*.pfx, *.p12, *.pem |
Certificates and private keys |
unattend.xml, sysprep.xml |
Deployment credentials |
Download and inspect any XML files found in user home directories — Azure AD
credential exports are a common source of cleartext domain passwords.
Session Enumeration
# Where are high-value users logged in?
nxc smb 10.10.10.0/24 -u 'user' -p 'Password123' --sessions
nxc smb 10.10.10.0/24 -u 'user' -p 'Password123' --loggedon-users
# PowerView
Invoke-UserHunter -Stealth
Find-DomainUserLocationLocal Admin Access
# Where does the current user have local admin?
nxc smb 10.10.10.0/24 -u 'user' -p 'Password123'
# Look for (Pwn3d!) in output
# PowerView
Find-LocalAdminAccess -VerboseIf local admin found → STOP. Return to orchestrator recommending
credential-dumping (SAM/LSASS). Pass: target hostname, local admin
credentials, DC IP, domain name. Do not dump credentials inline.
SCCM / Deployment
# SCCM discovery
python3 sccmhunter.py find -u 'user' -p 'Password123' -d DOMAIN.LOCAL -dc-ip DC_IPIf SCCM found → STOP. Return to orchestrator recommending
sccm-exploitation. Pass: DC IP, domain name, SCCM server details, current
credentials. Do not exploit SCCM inline.
Step 5: Attack Surface Routing
Map enumeration findings to technique skills. This is the core routing table.
When a match below is found, STOP — return to the orchestrator recommending
the matched skill. Do not execute attack techniques inline.
| Finding | Indicator | Route To |
|---|---|---|
| Pre-2k computer account creds | nxc -M pre2k (TGT obtained) | pass-the-hash (machine account) |
| User accounts with SPNs | GetUserSPNs output shows SPNs | kerberos-roasting |
| Users without pre-auth | GetNPUsers / DONT_REQ_PREAUTH flag | kerberos-roasting (AS-REP section) |
| Valid username list obtained | RID cycling / kerbrute / LDAP | password-spraying |
| Cleartext password in description | nxc -M get-desc-users | pass-the-hash or deeper enum |
| GPP cpassword found | nxc -M gpp_password / gpp_autologin | pass-the-hash or deeper enum |
| NTLM hash obtained | SAM dump / LSASS / secretsdump | pass-the-hash |
| AES keys obtained | DCSync / secretsdump / LSASS | pass-the-hash (Pass-the-Key) |
| Kerberos ticket captured | Delegation / ticket dump | pass-the-hash (Pass-the-Ticket) |
| Unconstrained delegation host | TRUSTED_FOR_DELEGATION flag | kerberos-delegation |
| Constrained delegation | msDS-AllowedToDelegateTo set | kerberos-delegation |
| RBCD writable | Write to msDS-AllowedToActOnBehalf | kerberos-delegation |
| MAQ > 0 + write target | nxc -M maq + ACL check | kerberos-delegation (RBCD) |
| krbtgt hash obtained | DCSync of krbtgt | kerberos-ticket-forging |
| Service account hash obtained | Kerberoast / DCSync | kerberos-ticket-forging (Silver) |
| GenericAll on user/group | BloodHound / ACL scan | acl-abuse |
| WriteDACL / WriteOwner | BloodHound / ACL scan | acl-abuse |
| ForceChangePassword | BloodHound | acl-abuse |
| msDS-KeyCredentialLink writable | BloodHound | acl-abuse (Shadow Credentials) |
| BadSuccessor (dMSA) vulnerable | nxc -M badsuccessor | acl-abuse (dMSA) |
| Vulnerable ADCS templates (ESC1-3,6) | certipy find -vulnerable | adcs-template-abuse |
| CA/template ACL abuse (ESC4-5,7) | certipy / BloodHound ADCS | adcs-access-and-relay |
| HTTP/RPC enrollment (ESC8,11) | certipy / nmap web enrollment | adcs-access-and-relay |
| Weak cert mapping (ESC9-15) | certipy find | adcs-persistence |
| SMB signing disabled | nxc smb signing:False | auth-coercion-relay |
| LDAP signing not required | nxc ldap signing:None | auth-coercion-relay |
| WebDAV enabled on target | nxc -M webdav | auth-coercion-relay (HTTP coercion) |
| Spooler service running | nxc -M spooler | auth-coercion-relay |
| Coercion vulns confirmed | nxc -M coerce_plus | auth-coercion-relay |
| LLMNR/NBT-NS traffic | Responder analysis mode | auth-coercion-relay |
| DCSync rights (Replication perms) | BloodHound | credential-dumping |
| Local admin on DC | BloodHound / Pwn3d! | credential-dumping |
| LAPS readable | nxc -M laps output | credential-dumping |
| gMSA/dMSA readable | nxc --gmsa output | credential-dumping |
| GPO write access | BloodHound | gpo-abuse |
| Domain/forest trusts | Trust enumeration | trust-attacks |
| SCCM infrastructure | nxc -M sccm / sccmhunter | sccm-exploitation |
| Entra ID Connect server | nxc -M entra-id | credential-dumping (sync creds) |
| EOL operating systems | nxc -M obsolete | Note for CVE targeting |
| AV/EDR products detected | nxc -M enum_av | Note for evasion planning |
| Post-DA compromise | Full domain control | ad-persistence |
Priority Order
When multiple attack paths exist, prioritize by OPSEC and reliability:
- Pre-2k computer accounts / GPP passwords / description creds — instant
credentials, zero noise, no cracking needed - Kerberos roasting / AS-REP roasting — offline cracking, low detection
- ADCS template abuse — certificate-based, stealthy, persistent
- ACL abuse — targeted, often unmonitored
- Delegation abuse — Kerberos-based, moderate detection
- Password spraying — risk of lockout, use as last resort for initial access
- Coercion/relay — requires network position, noisy
- Credential dumping — requires existing admin access
Step 6: Escalate or Pivot
After mapping the attack surface:
- Multiple paths identified: Present the top 3 paths ranked by OPSEC and reliability.
- No clear path: Expand enumeration scope (additional subnets, different
protocols), try password spraying, or check for relay opportunities. - Credentials found in shares/GPP: Route to pass-the-hash or use for
deeper authenticated enumeration.
When routing to a technique skill, pass along:
- Target user/host/service
- Current credentials and access level
- Domain name and DC hostname
- Relevant enumeration output
Troubleshooting
BloodHound Collection Fails
- LDAP connection refused: Try port 636 (LDAPS) with
--sslflag - Access denied: Verify credentials; any domain user can run BloodHound
- Timeout: Use
--CollectionMethod DCOnlyfor stealthier, faster collection - Missing ADCS data: Run
certipy findseparately and import JSON into BH CE
Kerberos Errors
- KRB_AP_ERR_SKEW: Clock out of sync (> 5 minutes from DC). This is a
Clock Skew Interrupt — stop immediately and return to the orchestrator.
Do not retry or fall back to NTLM. Fix requires root:sudo ntpdate DC_IP - KDC cannot find the name: Use FQDN hostnames, not IP addresses. Ensure
DNS resolves to the DC or add entries to/etc/hosts
NetExec Connection Issues
- SMB SessionError STATUS_NOT_SUPPORTED: Target may require SMBv3 or
NTLMv2. Try--smb2flag - Connection timed out: Host may be down or firewalled. Try different
protocols (LDAP, WinRM, RDP)
bloodyAD LDAP Filter Errors
LDAP filters with ! (NOT operator) can fail due to bash history expansion.
Always use single quotes around filters, not double quotes:
# CORRECT — single quotes prevent ! expansion
bloodyAD ... get search --filter '(!(userAccountControl:1.2.840.113556.1.4.803:=2))'
# WRONG — double quotes cause bash to interpret ! as history expansion
bloodyAD ... get search --filter "(!(userAccountControl...))"If filters still fail, simplify by removing the NOT clause and filtering the
output with grep -v instead.
Impacket Tool Naming
Impacket tools may be installed under different names depending on the system:
| Packaged (pip/apt) | Script name | Both work |
|---|---|---|
impacket-getTGT |
getTGT.py |
Same tool |
impacket-GetUserSPNs |
GetUserSPNs.py |
Same tool |
impacket-GetNPUsers |
GetNPUsers.py |
Same tool |
impacket-secretsdump |
secretsdump.py |
Same tool |
If one form is not found, try the other. The .py form is more common on
manually-installed Impacket; the impacket- prefix form comes from pip/apt
package installations.
No Credentials Available
Start with:
- RID cycling for username list
- AS-REP roasting against discovered usernames
- LLMNR/NBT-NS poisoning (if on-network)
- Password spraying with common passwords
- Check for anonymous LDAP bind (
nxc ldap DC -u '' -p '')