DCSync is the most impactful single credential compromise operation possible against an AD domain — one command gives the attacker every credential in the forest.
DCSync Detection
# Detect DCSync activity — Event 4662 on Domain Controllers
# DCSync requires replication rights; non-DC accounts using them = alert
# CRITICAL: This query must run on the DC, not a member server
Get-WinEvent -FilterHashtable @{
LogName = 'Security'
Id = 4662
StartTime = (Get-Date).AddDays(-7)
} | ForEach-Object {
$xml = [xml]$_.ToXml()
$account = ($xml.Event.EventData.Data | Where-Object {$_.Name -eq 'SubjectUserName'}).'#text'
$properties = ($xml.Event.EventData.Data | Where-Object {$_.Name -eq 'Properties'}).'#text'
# DS-Replication-Get-Changes-All GUID = {1131f6aa-9c07-11d1-f79f-00c04fc2dcd2}
if ($properties -like '*1131f6aa*' -and $account -notlike '*$') {
[PSCustomObject]@{
Time = $_.TimeCreated
Account = $account
Properties = $properties.Substring(0, [Math]::Min(100, $properties.Length))
}
}
}
# Check who has DCSync rights (should only be DCs and Domain/Enterprise Admins)
# Using PowerView (or RSAT)
$acl = Get-ObjectAcl -DistinguishedName "DC=company,DC=local" -ResolveGUIDs |
Where-Object {$_.ActiveDirectoryRights -match "DS-Replication-Get-Changes"}
$acl | Select-Object IdentityReference, ActiveDirectoryRights |
Where-Object {$_.IdentityReference -notmatch "Domain Controllers|Enterprise Domain Controllers|Administrators"}
NTDS.dit Access Detection
# Event 4656/4663: File access audit on DC — detects VSS-based NTDS theft
# Requires File System auditing enabled on the DC
# Look for ntds.dit access by non-system processes
Get-WinEvent -FilterHashtable @{
LogName = 'Security'
Id = 4663
StartTime = (Get-Date).AddDays(-30)
} | Where-Object {
$xml = [xml]$_.ToXml()
$file = ($xml.Event.EventData.Data | Where-Object {$_.Name -eq 'ObjectName'}).'#text'
$file -like '*ntds.dit*' -or $file -like '*NTDS\*'
} | ForEach-Object {
$xml = [xml]$_.ToXml()
[PSCustomObject]@{
Time = $_.TimeCreated
Account = ($xml.Event.EventData.Data | Where-Object {$_.Name -eq 'SubjectUserName'}).'#text'
Process = ($xml.Event.EventData.Data | Where-Object {$_.Name -eq 'ProcessName'}).'#text'
File = ($xml.Event.EventData.Data | Where-Object {$_.Name -eq 'ObjectName'}).'#text'
}
}
# Detect NTDSUtil IFM creation (Event 325: AD database backup created)
Get-WinEvent -FilterHashtable @{
LogName = 'Directory Service'
Id = 325
} | Select-Object TimeCreated, Message | Format-List
# Detect VSS snapshot creation that may precede NTDS theft
Get-WinEvent -FilterHashtable @{
LogName = 'Application'
Id = 8222 # VSS snapshot created
} -ErrorAction SilentlyContinue | Select-Object TimeCreated, Message
Pass-the-Hash Detection and Scope
# Detect NTLM lateral movement (PtH pattern)
# Event 4624 Logon Type 3 using NTLM from unexpected sources
Get-WinEvent -FilterHashtable @{
LogName = 'Security'
Id = 4624
StartTime = (Get-Date).AddDays(-7)
} | ForEach-Object {
$xml = [xml]$_.ToXml()
$logonType = ($xml.Event.EventData.Data | Where-Object {$_.Name -eq 'LogonType'}).'#text'
$authPkg = ($xml.Event.EventData.Data | Where-Object {$_.Name -eq 'AuthenticationPackageName'}).'#text'
$logonProc = ($xml.Event.EventData.Data | Where-Object {$_.Name -eq 'LogonProcessName'}).'#text'
# Type 3 + NTLM authentication = potential PtH
if ($logonType -eq '3' -and $authPkg -eq 'NTLM') {
[PSCustomObject]@{
Time = $_.TimeCreated
Account = ($xml.Event.EventData.Data | Where-Object {$_.Name -eq 'TargetUserName'}).'#text'
SourceIP = ($xml.Event.EventData.Data | Where-Object {$_.Name -eq 'IpAddress'}).'#text'
LogonProcess = $logonProc
AuthPkg = $authPkg
}
}
} | Where-Object {$_.Account -ne 'ANONYMOUS LOGON'} |
Sort-Object Time | Format-Table -AutoSize
# Map lateral movement — build connection graph
# Group by SourceIP to see which system the attacker moved from
$lateral_moves = @{} # SourceIP -> [list of destination accounts]
# Run in SIEM: correlate 4624 Logon Type 3 events across all systems, not just one
BloodHound Scope Assessment
# Run SharpHound to collect AD attack paths (run from attacker's perspective)
# In IR context: run SharpHound yourself to understand what the attacker could see
# SharpHound collection (requires domain user context)
.\SharpHound.exe --CollectionMethods All --Domain company.local --ZipFilename ir-collection.zip
# After importing to BloodHound, key queries for IR scope:
# 1. "Find all Domain Admins" — full list of high-value accounts
# 2. "Shortest Paths to Domain Admin from Compromised Account"
# 3. "Find Principals with DCSync Rights" — who can do DCSync legitimately vs. attacker
# 4. "Computers Where Domain Users Can RDP" — all systems accessible to any domain user
# PowerShell alternative to identify attack paths without BloodHound:
# Find all accounts with AdminSDHolder protection (high-privilege protected accounts)
Get-ADUser -Filter {AdminCount -eq 1} `
-Properties AdminCount, MemberOf, PasswordLastSet |
Select-Object SamAccountName, PasswordLastSet |
Sort-Object PasswordLastSet
# Find all members of privileged groups
$privileged_groups = @('Domain Admins', 'Enterprise Admins', 'Schema Admins',
'Account Operators', 'Backup Operators', 'Print Operators',
'Server Operators', 'Group Policy Creator Owners')
$privileged_groups | ForEach-Object {
$group = $_
Get-ADGroupMember -Identity $group -Recursive |
Where-Object {$_.objectClass -eq 'user'} |
ForEach-Object {
[PSCustomObject]@{Group = $group; Member = $_.SamAccountName}
}
} | Format-Table -AutoSize