Skip to main content
Synced from an Obsidian vault

For graph and advanced features, download the full Intel Codex Vault and open it in Obsidian.

Active Directory Pentesting SOP (Authorized)

Authorized environments only. This SOP covers defensive assessment of Active Directory environments.


Table of Contents


1. Engagement Setup

Pre-Engagement

  • Obtain written authorization (signed Rules of Engagement)
  • Define scope: domains, forests, trusts, target OUs/hosts
  • Identify test accounts vs production accounts
  • Set time windows and blackout periods (avoid business-critical hours)
  • Establish emergency contacts (IT, security team, change management)
  • Confirm rollback procedures exist
  • Determine if testing lab environment or limited production scope

Objectives (Examples)

  • Identify misconfigurations enabling lateral movement and privilege escalation
  • Validate detection/monitoring efficacy for AD attack paths
  • Test privileged group memberships and delegation
  • Review tiering model implementation
  • Assess Kerberos security (Kerberoasting, AS-REP roasting)
  • Evaluate GPO security and deployment

2. Domain Enumeration (Read-Only)

Basic Domain Information

# Domain information
Get-ADDomain
Get-ADForest

# Domain Controllers
Get-ADDomainController -Filter *

# Domain trusts
Get-ADTrust -Filter *
nltest /domain_trusts

# Forest trusts
Get-ADForest | Select-Object -ExpandProperty Domains

User Enumeration

# All domain users
Get-ADUser -Filter * -Properties *

# Enabled users only
Get-ADUser -Filter {Enabled -eq $true} -Properties *

# Users with AdminCount=1 (protected accounts)
Get-ADUser -Filter {AdminCount -eq 1} -Properties AdminCount

# Users with password not required
Get-ADUser -Filter {PasswordNotRequired -eq $true}

# Users with password never expires
Get-ADUser -Filter {PasswordNeverExpires -eq $true}

# Users with no password expiration and enabled
Get-ADUser -Filter {(PasswordNeverExpires -eq $true) -and (Enabled -eq $true)}

# Service Principal Names (for Kerberoasting)
Get-ADUser -Filter {ServicePrincipalName -ne "$null"} -Properties ServicePrincipalName

# Pre-Windows 2000 compatible access
Get-ADUser -Filter * -Properties PrimaryGroupID | Where-Object {$_.PrimaryGroupID -eq 515}

Group Enumeration

# All domain groups
Get-ADGroup -Filter * -Properties *

# Privileged groups
Get-ADGroupMember "Domain Admins"
Get-ADGroupMember "Enterprise Admins"
Get-ADGroupMember "Schema Admins"
Get-ADGroupMember "Administrators"
Get-ADGroupMember "Account Operators"
Get-ADGroupMember "Backup Operators"
Get-ADGroupMember "Print Operators"
Get-ADGroupMember "Server Operators"

# Nested group memberships (recursive)
Get-ADGroupMember "Domain Admins" -Recursive

# Groups with AdminCount=1
Get-ADGroup -Filter {AdminCount -eq 1}

Computer Enumeration

# All domain computers
Get-ADComputer -Filter * -Properties *

# Domain Controllers
Get-ADComputer -Filter {PrimaryGroupID -eq 516} -Properties OperatingSystem

# Servers
Get-ADComputer -Filter {OperatingSystem -like "*Server*"} -Properties OperatingSystem

# Workstations
Get-ADComputer -Filter {OperatingSystem -like "*Windows 10*" -or OperatingSystem -like "*Windows 11*"}

# Computers with unconstrained delegation
Get-ADComputer -Filter {TrustedForDelegation -eq $true} -Properties TrustedForDelegation

# Computers with constrained delegation
Get-ADComputer -Filter {msDS-AllowedToDelegateTo -ne "$null"} -Properties msDS-AllowedToDelegateTo

OU Structure

# List all OUs
Get-ADOrganizationalUnit -Filter * | Select-Object Name,DistinguishedName

# Check GPO links per OU
Get-ADOrganizationalUnit -Filter * | Select-Object Name,LinkedGroupPolicyObjects

3. BloodHound Analysis

Data Collection

Using SharpHound (Windows):

# Download SharpHound
# https://github.com/BloodHoundAD/BloodHound/tree/master/Collectors

# Run collection (all methods)
.\SharpHound.exe -c All

# Stealthy collection (avoid DCOnly)
.\SharpHound.exe -c Session,Trusts,ACL,Container,Group,LocalAdmin,RDP,DCOM,PSRemote

# Specify domain
.\SharpHound.exe -c All -d domain.local

# Exclude Domain Controllers from session enumeration (less noisy)
.\SharpHound.exe -c All --ExcludeDCs

Using BloodHound.py (Linux):

# Install
pip install bloodhound

# Run collection
bloodhound-python -u username -p password -d domain.local -dc dc01.domain.local -c All

# With NTLM hash
bloodhound-python -u username --hashes :NTLMhash -d domain.local -dc dc01.domain.local -c All

Import & Analysis

  1. Start Neo4j database:
sudo neo4j console
# Navigate to http://localhost:7474
# Default creds: neo4j/neo4j (change on first login)
  1. Start BloodHound GUI:
./BloodHound --no-sandbox
  1. Import collected data (drag .json files into BloodHound)

Pre-Built Queries to Run

Shortest Paths:

  • Shortest Paths to Domain Admins
  • Shortest Paths to High Value Targets
  • Shortest Paths from Owned Principals
  • Shortest Paths from Kerberoastable Users

Domain Information:

  • Find all Domain Admins
  • Find Workstations where Domain Users can RDP
  • Find Servers where Domain Users can RDP
  • Find Computers where Domain Users are Local Admin

Kerberos:

  • List all Kerberoastable Accounts
  • AS-REP Roastable Users (Do not require Pre-Authentication)

Delegation:

  • Find Computers with Unconstrained Delegation
  • Find Computers with Constrained Delegation
  • Shortest Paths from Computers with Unconstrained Delegation

ACLs:

  • Find Principals with DCSync Rights
  • Users with Foreign Domain Group Membership
  • Groups with Foreign Domain Group Membership

Custom Cypher Queries

// Users with path to Domain Admins (excluding direct members)
MATCH (u:User),(g:Group {name:"DOMAIN ADMINS@DOMAIN.LOCAL"}),
p=shortestPath((u)-[*1..]->(g))
WHERE NOT (u)-[:MemberOf]->(g)
RETURN p

// Computers with sessions from privileged users
MATCH (c:Computer)-[:HasSession]->(u:User)-[:MemberOf*1..]->(g:Group)
WHERE g.highvalue=true
RETURN c.name, u.name, g.name

// Users with GenericAll on computers
MATCH (u:User)-[:GenericAll]->(c:Computer)
RETURN u.name, c.name

// Find owned users with paths to high value targets
MATCH (u:User {owned:true}),(g:Group {highvalue:true}),
p=shortestPath((u)-[*1..]->(g))
RETURN p

4. Privilege Escalation Paths

Kerberoasting

Identify targets:

# PowerShell
Get-ADUser -Filter {ServicePrincipalName -ne "$null"} -Properties ServicePrincipalName,MemberOf

Request service tickets (for offline cracking):

# Using Rubeus
.\Rubeus.exe kerberoast /outfile:kerberoast_hashes.txt

# Using Invoke-Kerberoast (PowerView)
Invoke-Kerberoast -OutputFormat Hashcat | fl

Crack with hashcat:

hashcat -m 13100 kerberoast_hashes.txt wordlist.txt

Remediation recommendations:

  • Use strong passwords for service accounts (25+ characters)
  • Use Group Managed Service Accounts (gMSA)
  • Monitor for unusual TGS requests

AS-REP Roasting

Identify targets:

# Users with "Do not require Kerberos preauthentication"
Get-ADUser -Filter {DoesNotRequirePreAuth -eq $true} -Properties DoesNotRequirePreAuth

Request AS-REP hashes:

# Using Rubeus
.\Rubeus.exe asreproast /outfile:asrep_hashes.txt

# Using Impacket (Linux)
GetNPUsers.py domain.local/ -usersfile users.txt -dc-ip 10.0.0.1

Crack with hashcat:

hashcat -m 18200 asrep_hashes.txt wordlist.txt

Remediation:

  • Enable Kerberos pre-authentication for all accounts
  • Monitor for AS-REP requests without pre-auth

Unconstrained Delegation

Find computers/users with unconstrained delegation:

# Computers
Get-ADComputer -Filter {TrustedForDelegation -eq $true} -Properties TrustedForDelegation

# Users
Get-ADUser -Filter {TrustedForDelegation -eq $true} -Properties TrustedForDelegation

Risk:

  • Any service on these systems can impersonate any user
  • If admin connects, attacker can extract TGT and impersonate them

Remediation:

  • Remove unconstrained delegation (use constrained instead)
  • Protect sensitive accounts with "Account is sensitive and cannot be delegated"
  • Monitor TGT requests from delegation-enabled systems

Constrained Delegation

Find accounts with constrained delegation:

Get-ADComputer -Filter {msDS-AllowedToDelegateTo -ne "$null"} -Properties msDS-AllowedToDelegateTo
Get-ADUser -Filter {msDS-AllowedToDelegateTo -ne "$null"} -Properties msDS-AllowedToDelegateTo

Risk:

  • Can impersonate any user to specific services
  • With protocol transition, can request tickets on behalf of any user

Remediation:

  • Use Resource-Based Constrained Delegation (RBCD) instead
  • Monitor for S4U2Self/S4U2Proxy requests

5. ACL Abuse & Dangerous Permissions

Common ACL Attack Paths

GenericAll:

  • Full control over object
  • Can reset passwords, modify group membership, etc.

WriteDACL:

  • Can modify permissions on object
  • Grant yourself GenericAll, then exploit

WriteOwner:

  • Can take ownership of object
  • Then grant permissions

GenericWrite:

  • Can write to most attributes
  • For users: modify scriptPath, servicePrincipalName
  • For computers: can perform RBCD attack

ForceChangePassword:

  • Can reset user password without knowing current password

Find Dangerous ACLs

Using PowerView:

# Download PowerView
# https://github.com/PowerShellMafia/PowerSploit/blob/master/Recon/PowerView.ps1

# Find ACLs where non-standard principals have control
Find-InterestingDomainAcl -ResolveGUIDs

# Find ACLs for specific user
Get-DomainObjectAcl -Identity "Domain Admins" -ResolveGUIDs

# Find users with WriteDACL on Domain Admins
Get-DomainObjectAcl -Identity "Domain Admins" -ResolveGUIDs | Where-Object {$_.ActiveDirectoryRights -match "WriteDacl"}

Using BloodHound:

  • Pre-built queries under "Dangerous Privileges"
  • Review edges: GenericAll, WriteDacl, WriteOwner, GenericWrite

DCSync Rights

Find principals with DCSync rights:

# PowerView
Get-DomainObjectAcl "DC=domain,DC=local" -ResolveGUIDs | Where-Object {
($_.ObjectType -match 'replication') -or
($_.ActiveDirectoryRights -match 'GenericAll')
}

Risk:

  • Allows replication of AD data (including password hashes)
  • Equivalent to Domain Admin

Remediation:

  • Only Domain Controllers and specific backup systems should have this right
  • Monitor for DS-Replication-Get-Changes events (4662)

6. Group Policy Object (GPO) Review

Enumerate GPOs

# List all GPOs
Get-GPO -All

# GPOs linked to specific OU
Get-GPInheritance -Target "OU=Servers,DC=domain,DC=local"

# Find GPOs with specific settings
Get-GPOReport -All -ReportType HTML -Path C:\GPOReport.html

GPO Security Issues

Check for:

  • Authenticated Users with edit rights on GPOs
  • GPOs with password/credential settings
  • Unrestricted software installation policies
  • Weak LAPS configuration
  • Disabled security settings (Windows Firewall, Defender)

Find GPOs modifiable by non-admins:

# Using PowerView
Get-DomainGPO | Get-DomainObjectAcl -ResolveGUIDs | Where-Object {
($_.ActiveDirectoryRights -match "WriteProperty|GenericAll|GenericWrite|WriteDacl|WriteOwner") -and
($_.SecurityIdentifier -match "S-1-5-21-.*-[0-9]{4,}")
}

LAPS (Local Administrator Password Solution)

Check if LAPS is deployed:

Get-ADComputer -Filter * -Properties ms-Mcs-AdmPwd | Where-Object {$_."ms-Mcs-AdmPwd" -ne $null}

Check who can read LAPS passwords:

# Using PowerView
Get-DomainComputer | Get-DomainObjectAcl -ResolveGUIDs | Where-Object {
$_.ObjectType -like "ms-Mcs-AdmPwd"
} | Select-Object ObjectDN,SecurityIdentifier

7. Password Policy & Account Security

Domain Password Policy

Get-ADDefaultDomainPasswordPolicy

# Fine-Grained Password Policies
Get-ADFineGrainedPasswordPolicy -Filter *

Check for weak policies:

  • Minimum password length < 14 characters
  • Password history < 24
  • Maximum password age > 60 days
  • Lockout threshold disabled or > 5 attempts

Stale Accounts

# Users not logged in for 90+ days
$90days = (Get-Date).AddDays(-90)
Get-ADUser -Filter {LastLogonDate -lt $90days} -Properties LastLogonDate

# Computers not logged in for 90+ days
Get-ADComputer -Filter {LastLogonDate -lt $90days} -Properties LastLogonDate

# Disabled accounts still in privileged groups
Get-ADGroupMember "Domain Admins" | Get-ADUser | Where-Object {$_.Enabled -eq $false}

8. Service Accounts & Credentials

Service Account Checks

# Accounts with SPNs (service accounts)
Get-ADUser -Filter {ServicePrincipalName -ne "$null"} -Properties ServicePrincipalName,PasswordLastSet,PasswordNeverExpires

# Check for old password last set dates
Get-ADUser -Filter {ServicePrincipalName -ne "$null"} -Properties PasswordLastSet |
Where-Object {$_.PasswordLastSet -lt (Get-Date).AddYears(-1)}

Red flags:

  • Service accounts in Domain Admins
  • Service accounts with PasswordNeverExpires
  • Service accounts with interactive logon rights
  • SPNs on privileged accounts

Credentials in SYSVOL/Scripts

Check for passwords in Group Policy Preferences (cpassword):

# Search SYSVOL for cpassword attribute (Groups.xml)
findstr /S /I cpassword \\domain.local\sysvol\domain.local\policies\*.xml

Check scripts for hardcoded credentials:

Get-ChildItem \\domain.local\SYSVOL\domain.local\scripts -Recurse -Include *.ps1,*.bat,*.vbs |
Select-String -Pattern "password","pwd","pass"

9. Monitoring & Detection Review

Event Log Analysis

Check if important events are logged:

# Audit policy
auditpol /get /category:*

# Check for PowerShell logging
Get-ItemProperty HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging
Get-ItemProperty HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\Transcription

Key events to monitor:

  • 4624 (Successful logon)
  • 4625 (Failed logon)
  • 4672 (Special privileges assigned)
  • 4768/4769 (Kerberos TGT/TGS requests)
  • 4776 (NTLM authentication)
  • 4662 (DCSync - replication operation)
  • 7045 (Service installed)

Protected Users Group

# Check if high-value accounts are in Protected Users
Get-ADGroupMember "Protected Users"

Benefits:

  • No NTLM authentication
  • No DES or RC4 in Kerberos
  • No delegation
  • TGT max lifetime 4 hours

10. Attack Simulation (Controlled Testing)

Red Team TTPs to Test Detection For

Initial Access:

  • Password spraying (low-volume, controlled)
  • AS-REP roasting
  • Kerberoasting

Lateral Movement:

  • Pass-the-Hash (in test environment)
  • Pass-the-Ticket
  • Overpass-the-Hash

Privilege Escalation:

  • ACL abuse (WriteDACL → GenericAll)
  • Unconstrained delegation exploitation
  • GPO modification

Persistence:

  • Golden Ticket (test environment only)
  • Silver Ticket
  • DCSync

Safety:

  • Coordinate with SOC/detection team
  • Use test accounts and canary systems
  • Monitor for alerts during tests
  • Document all actions with timestamps

11. Common Misconfigurations Checklist

  • Domain/Enterprise Admins with more members than necessary
  • Service accounts in privileged groups
  • Computers with unconstrained delegation
  • Users with "Password never expires" enabled
  • Weak password policy (< 14 chars, no complexity)
  • LAPS not deployed or improperly configured
  • Authenticated Users can modify GPOs
  • No Protected Users group usage for VIPs
  • AdminSDHolder not monitored for modifications
  • Stale accounts (90+ days inactive) not disabled
  • Pre-Windows 2000 Compatible Access group populated
  • Service accounts with interactive logon rights
  • Credentials in SYSVOL scripts/GPP
  • PowerShell logging disabled
  • No monitoring for DCSync (4662 events)

12. Evidence Collection

For each finding, document:

  • Object path (DN)
  • Exact PowerShell/tool command used
  • Full output (sanitize if needed)
  • Timestamp (UTC)
  • Screenshot for BloodHound paths
  • Risk level and business impact

File structure:

/Evidence/{engagement_id}/AD/
├── bloodhound/
│ ├── 20251005_bloodhound_data.zip
│ └── screenshots/
├── enumeration/
│ ├── 20251005_domain_admins.txt
│ ├── 20251005_kerberoastable_users.txt
│ └── 20251005_unconstrained_delegation.txt
├── gpo/
│ ├── 20251005_gpo_report.html
│ └── 20251005_sysvol_creds.txt
├── acls/
│ └── 20251005_dangerous_acls.txt
└── hashes/
└── evidence_hashes.txt

Hash all files:

Get-FileHash *.txt,*.html,*.zip | Export-Csv hashes.csv

13. Reporting

Finding Format

Title: Service Accounts with Unconstrained Delegation
Severity: Critical
Affected Objects:
- SQLSVC@domain.local (CN=SQLSVC,OU=Service Accounts,DC=domain,DC=local)
- WEBSVC@domain.local (CN=WEBSVC,OU=Service Accounts,DC=domain,DC=local)

Description:
Service accounts configured with unconstrained delegation can be abused to
impersonate any domain user, including Domain Admins, if they authenticate
to the compromised system.

Impact:
If an attacker compromises the SQL or Web servers, they can extract TGTs
from memory for any user who authenticates, leading to full domain compromise.

Evidence:
Get-ADUser -Filter {TrustedForDelegation -eq $true} -Properties TrustedForDelegation
Output: [screenshot/paste]

Attack Path (BloodHound):
[Screenshot showing path from SQLSVC to Domain Admins]

Remediation:
1. Remove unconstrained delegation from service accounts
2. Implement constrained or resource-based constrained delegation instead
3. Add sensitive accounts to Protected Users group
4. Enable "Account is sensitive and cannot be delegated" for VIP accounts

Verification:
1. Re-run: Get-ADUser -Filter {TrustedForDelegation -eq $true}
2. Verify no service accounts have TrustedForDelegation=True
3. Confirm Protected Users group contains Domain/Enterprise Admins

Remediation Priority

  1. Critical: Unconstrained delegation, DCSync rights to non-DCs, DA credentials in SYSVOL
  2. High: Kerberoastable privileged accounts, weak ACLs on admin groups, no LAPS
  3. Medium: Stale privileged accounts, weak password policy, missing audit logging
  4. Low: Informational findings, hardening recommendations

  • Read-only enumeration first: Gather data before testing exploitability
  • Coordinate with stakeholders before password attacks or GPO modifications
  • Use test accounts for exploitation testing (not production accounts)
  • Monitor for impact: Watch for service disruptions, lockouts, replication issues
  • Stop immediately if Domain Controllers show instability
  • Document everything for audit trail and legal defensibility
  • Respect scope: Do not pivot to out-of-scope domains/forests without approval

15. Tools Reference

ToolPurposeLink
BloodHoundAD relationship mappinggithub.com/BloodHoundAD/BloodHound
SharpHoundBloodHound data collector (Windows)github.com/BloodHoundAD/BloodHound
BloodHound.pyBloodHound collector (Linux)github.com/fox-it/BloodHound.py
PowerViewAD enumeration (PowerShell)github.com/PowerShellMafia/PowerSploit
RubeusKerberos abuse toolkitgithub.com/GhostPack/Rubeus
ImpacketPython AD toolkitgithub.com/SecureAuthCorp/impacket
ADReconAD data aggregationgithub.com/adrecon/ADRecon
PingCastleAD security auditpingcastle.com
Purple KnightAD security assessmentpurple-knight.com

16. Reference Resources

Comprehensive Knowledge Bases

Attack Technique Deep Dives

Defense & Hardening

Cheat Sheets & Quick References


17. Common Pitfalls

  • ❌ Running SharpHound with DCOnly in production (generates excessive traffic)
  • ❌ Not coordinating with SOC before testing (causes alert fatigue)
  • ❌ Using production admin accounts for testing (contaminates evidence)
  • ❌ Requesting too many Kerberos tickets at once (triggers detections)
  • ❌ Not checking scope before enumerating trusts (cross-domain pivots)
  • ❌ Forgetting to sanitize credentials in reports/screenshots
  • ❌ Relying only on BloodHound (manual validation is critical)
  • ❌ Not testing detection coverage (pentest should validate monitoring)

Analysis:

Pentesting & Security: