Active Directory Security Event Monitoring: Enterprise Domain Protection and Threat Detection

Active Directory Security Event Monitoring: Enterprise Domain Protection and Threat Detection
4 October, 2025

Executive Summary

Active Directory (AD) serves as the identity backbone for 90% of Fortune 1000 companies, making it the crown jewel target for advanced persistent threats (APTs). A single compromise of AD can provide attackers with complete control over an entire enterprise network, making robust security monitoring not just important, but absolutely critical for organizational survival.

This comprehensive guide explores advanced Active Directory security event monitoring techniques, from understanding the underlying authentication protocols to detecting sophisticated attacks like Golden Ticket, DCSync, and Kerberoasting. We’ll implement real-world detection strategies that security teams need to identify and respond to the most dangerous threats targeting enterprise domains.

Understanding Active Directory Security Architecture

Domain Controller Security Event Flow

Active Directory’s security event architecture involves complex interactions between multiple components:

Screenshot 2025 10 04 at 11.24.42

Critical AD Security Event Categories

Domain Controller event logs requiring monitoring:

Log SourceEvent TypesSecurity RelevanceDefault LocationSecurity LogAuthentication, AuthorizationUser logons, privilege changes%SystemRoot%\System32\Winevt\Logs\Security.evtxDirectory ServiceAD replication, LDAP queriesDatabase modifications, replication issues%SystemRoot%\System32\Winevt\Logs\Directory Service.evtxDNS ServerDNS queries, zone transfersDNS poisoning, reconnaissance%SystemRoot%\System32\Winevt\Logs\DNS Server.evtxKey Management ServiceCertificate operationsCertificate abuse, PKI attacks%SystemRoot%\System32\Winevt\Logs\Key Management Service.evtxAD Web ServicesPowerShell AD cmdletsRemote AD enumerationApplications and Services Logs\Microsoft\Windows\Active Directory Web ServicesNTFRS/DFSRSYSVOL replicationGPO tampering%SystemRoot%\System32\Winevt\Logs\File Replication Service.evtx

Critical Active Directory Security Events

Authentication and Kerberos Events

Understanding Kerberos authentication flow is essential for threat detection:

powershell

# Advanced Kerberos monitoring script
function Monitor-KerberosAuthentication {
    param(
        [string[]]$DomainControllers = (Get-ADDomainController -Filter *).HostName,
        [int]$Hours = 24,
        [switch]$DetectAnomalies
    )
    
    $StartTime = (Get-Date).AddHours(-$Hours)
    $KerberosEvents = @{
        # TGT Operations
        4768 = @{
            Name = "Kerberos TGT Request"
            Severity = "Info"
            Fields = @{
                Account = 0
                SourceIP = 9
                ErrorCode = 6
            }
        }
        4771 = @{
            Name = "Kerberos Pre-Auth Failed"
            Severity = "Warning"
            Fields = @{
                Account = 0
                SourceIP = 6
                FailureCode = 4
            }
        }
        4770 = @{
            Name = "Kerberos TGT Renewed"
            Severity = "Info"
            Fields = @{
                Account = 0
                SourceIP = 9
            }
        }
        
        # Service Ticket Operations
        4769 = @{
            Name = "Kerberos Service Ticket Request"
            Severity = "Info"
            Fields = @{
                Account = 0
                Service = 2
                SourceIP = 10
                TicketOptions = 6
                EncryptionType = 7
            }
        }
        4773 = @{
            Name = "Kerberos Service Ticket Failed"
            Severity = "Warning"
            Fields = @{
                Account = 0
                Service = 2
                FailureCode = 4
            }
        }
    }
    
    $Results = @{
        TotalEvents = 0
        Anomalies = @()
        SuspiciousPatterns = @()
        Statistics = @{}
    }
    
    foreach ($DC in $DomainControllers) {
        Write-Host "Analyzing Domain Controller: $DC" -ForegroundColor Cyan
        
        foreach ($EventID in $KerberosEvents.Keys) {
            try {
                $Events = Get-WinEvent -ComputerName $DC -FilterHashtable @{
                    LogName = 'Security'
                    ID = $EventID
                    StartTime = $StartTime
                } -ErrorAction SilentlyContinue
                
                if ($Events) {
                    $Results.TotalEvents += $Events.Count
                    $Results.Statistics[$EventID] = $Events.Count
                    
                    # Detect anomalies
                    if ($DetectAnomalies) {
                        # Check for RC4 encryption (potential downgrade attack)
                        if ($EventID -eq 4769) {
                            $RC4Usage = $Events | Where-Object {
                                $_.Properties[7].Value -eq 0x17  # RC4-HMAC
                            }
                            if ($RC4Usage) {
                                $Results.Anomalies += [PSCustomObject]@{
                                    Type = "RC4 Encryption Detected"
                                    Severity = "High"
                                    Count = $RC4Usage.Count
                                    DC = $DC
                                    Accounts = ($RC4Usage | ForEach-Object {
                                        $_.Properties[0].Value
                                    } | Select-Object -Unique)
                                }
                            }
                        }
                        
                        # Check for TGT requests from non-standard hours
                        if ($EventID -eq 4768) {
                            $AfterHours = $Events | Where-Object {
                                $Hour = $_.TimeCreated.Hour
                                $Hour -lt 6 -or $Hour -gt 22
                            }
                            if ($AfterHours.Count -gt 10) {
                                $Results.SuspiciousPatterns += [PSCustomObject]@{
                                    Pattern = "Unusual Hour Authentication"
                                    Count = $AfterHours.Count
                                    DC = $DC
                                    TimeRange = "Outside 6AM-10PM"
                                }
                            }
                        }
                        
                        # Check for failed pre-authentication (password spraying)
                        if ($EventID -eq 4771) {
                            $FailedAuth = $Events | Group-Object -Property {
                                $_.Properties[6].Value  # Source IP
                            } | Where-Object { $_.Count -gt 10 }
                            
                            if ($FailedAuth) {
                                $Results.Anomalies += [PSCustomObject]@{
                                    Type = "Potential Password Spray"
                                    Severity = "Critical"
                                    DC = $DC
                                    SourceIPs = $FailedAuth.Name
                                    AttemptCounts = $FailedAuth.Count
                                }
                            }
                        }
                    }
                }
            }
            catch {
                Write-Warning "Error processing $EventID on $DC : $_"
            }
        }
    }
    
    # Generate report
    Write-Host "`n=== KERBEROS MONITORING REPORT ===" -ForegroundColor Yellow
    Write-Host "Total Kerberos Events: $($Results.TotalEvents)"
    
    if ($Results.Anomalies) {
        Write-Host "`nSECURITY ANOMALIES DETECTED:" -ForegroundColor Red
        $Results.Anomalies | Format-Table -AutoSize
    }
    
    if ($Results.SuspiciousPatterns) {
        Write-Host "`nSUSPICIOUS PATTERNS:" -ForegroundColor Magenta
        $Results.SuspiciousPatterns | Format-Table -AutoSize
    }
    
    return $Results
}

Privileged Group Monitoring

Critical groups requiring continuous monitoring:

GroupSecurity ImpactMonitor Event IDsAlert PriorityDomain AdminsFull domain control4728, 4729, 4756, 4757CRITICALEnterprise AdminsForest-wide control4728, 4729, 4756, 4757CRITICALSchema AdminsSchema modifications4728, 4729, 4756, 4757CRITICALAdministratorsDC local admin4732, 4733HIGHAccount OperatorsUser/group management4728, 4729, 4732, 4733HIGHBackup OperatorsFile system access4732, 4733MEDIUMDNSAdminsDNS service control4732, 4733HIGHGroup Policy Creator OwnersGPO creation4728, 4729HIGH

Advanced Attack Detection Patterns

Golden Ticket Detection

Detecting Golden Ticket attacks through behavioral analysis:

powershell

# Golden Ticket detection framework
function Detect-GoldenTicket {
    param(
        [string[]]$DomainControllers = (Get-ADDomainController -Filter *).HostName,
        [int]$MaxTicketLifetimeHours = 10,
        [switch]$EnableRealTimeAlerts
    )
    
    $Indicators = @{
        GoldenTicket = @()
        SilverTicket = @()
        TicketAnomalies = @()
    }
    
    foreach ($DC in $DomainControllers) {
        Write-Host "Scanning $DC for ticket anomalies..." -ForegroundColor Yellow
        
        # Event 4769 - Service ticket operations
        $ServiceTickets = Get-WinEvent -ComputerName $DC -FilterHashtable @{
            LogName = 'Security'
            ID = 4769
            StartTime = (Get-Date).AddHours(-24)
        } -ErrorAction SilentlyContinue
        
        foreach ($Event in $ServiceTickets) {
            $EventXML = [xml]$Event.ToXml()
            
            # Extract ticket properties
            $TicketInfo = @{
                Account = $Event.Properties[0].Value
                Domain = $Event.Properties[1].Value
                ServiceName = $Event.Properties[2].Value
                ServiceID = $Event.Properties[3].Value
                TicketOptions = $Event.Properties[6].Value
                EncryptionType = $Event.Properties[7].Value
                ClientAddress = $Event.Properties[10].Value
                TimeCreated = $Event.TimeCreated
            }
            
            # Indicator 1: Service ticket without prior TGT request
            $TGTSearch = Get-WinEvent -ComputerName $DC -FilterHashtable @{
                LogName = 'Security'
                ID = 4768
                StartTime = $TicketInfo.TimeCreated.AddMinutes(-5)
                EndTime = $TicketInfo.TimeCreated
            } -ErrorAction SilentlyContinue |
            Where-Object { $_.Properties[0].Value -eq $TicketInfo.Account }
            
            if (-not $TGTSearch) {
                $Indicators.GoldenTicket += [PSCustomObject]@{
                    Indicator = "Service Ticket without TGT"
                    Account = $TicketInfo.Account
                    Service = $TicketInfo.ServiceName
                    Time = $TicketInfo.TimeCreated
                    DC = $DC
                    Severity = "CRITICAL"
                }
            }
            
            # Indicator 2: Ticket with unusual encryption type for krbtgt
            if ($TicketInfo.ServiceName -eq 'krbtgt' -and 
                $TicketInfo.EncryptionType -notin @(0x12, 0x17)) {  # AES256, AES128
                $Indicators.GoldenTicket += [PSCustomObject]@{
                    Indicator = "Unusual krbtgt Encryption"
                    Account = $TicketInfo.Account
                    EncType = "0x{0:X}" -f $TicketInfo.EncryptionType
                    Time = $TicketInfo.TimeCreated
                    DC = $DC
                    Severity = "HIGH"
                }
            }
            
            # Indicator 3: Ticket lifetime anomaly
            if ($TicketInfo.ServiceName -eq 'krbtgt') {
                # Check for tickets with lifetime > default (10 hours)
                $RenewalEvents = Get-WinEvent -ComputerName $DC -FilterHashtable @{
                    LogName = 'Security'
                    ID = 4770
                    StartTime = $TicketInfo.TimeCreated
                } -ErrorAction SilentlyContinue |
                Where-Object { 
                    $_.Properties[0].Value -eq $TicketInfo.Account -and
                    ($_.TimeCreated - $TicketInfo.TimeCreated).TotalHours -gt $MaxTicketLifetimeHours
                }
                
                if ($RenewalEvents) {
                    $Indicators.TicketAnomalies += [PSCustomObject]@{
                        Indicator = "Extended Ticket Lifetime"
                        Account = $TicketInfo.Account
                        LifetimeHours = [math]::Round(($RenewalEvents[0].TimeCreated - $TicketInfo.TimeCreated).TotalHours, 2)
                        Time = $TicketInfo.TimeCreated
                        DC = $DC
                        Severity = "MEDIUM"
                    }
                }
            }
        }
        
        # Event 4624 - Logon events with suspicious ticket use
        $LogonEvents = Get-WinEvent -ComputerName $DC -FilterHashtable @{
            LogName = 'Security'
            ID = 4624
            StartTime = (Get-Date).AddHours(-24)
        } -ErrorAction SilentlyContinue |
        Where-Object { $_.Properties[8].Value -eq 3 }  # Network logon
        
        foreach ($Logon in $LogonEvents) {
            # Check for logons with administratively created tickets
            if ($Logon.Properties[5].Value -match "krbtgt" -or
                $Logon.Properties[11].Value -eq "-") {  # No workstation name
                
                $Indicators.GoldenTicket += [PSCustomObject]@{
                    Indicator = "Suspicious Network Logon"
                    Account = $Logon.Properties[5].Value
                    SourceIP = $Logon.Properties[18].Value
                    Time = $Logon.TimeCreated
                    DC = $DC
                    Severity = "HIGH"
                }
            }
        }
    }
    
    # Alert on critical findings
    if ($EnableRealTimeAlerts -and $Indicators.GoldenTicket) {
        Send-SecurityAlert -Type "Golden Ticket Attack" -Details $Indicators.GoldenTicket
    }
    
    # Generate detection report
    Write-Host "`n=== GOLDEN TICKET DETECTION REPORT ===" -ForegroundColor Red
    
    if ($Indicators.GoldenTicket) {
        Write-Host "`nGOLDEN TICKET INDICATORS DETECTED:" -ForegroundColor Red
        $Indicators.GoldenTicket | Format-Table -AutoSize
    }
    
    if ($Indicators.TicketAnomalies) {
        Write-Host "`nTICKET ANOMALIES:" -ForegroundColor Yellow
        $Indicators.TicketAnomalies | Format-Table -AutoSize
    }
    
    return $Indicators
}

# Helper function for security alerts
function Send-SecurityAlert {
    param($Type, $Details)
    # Implement your alert mechanism here (email, SIEM, webhook, etc.)
    Write-Host "SECURITY ALERT: $Type" -ForegroundColor Red -BackgroundColor Yellow
}

DCSync Attack Detection

Monitoring for replication abuse and DCSync attacks:

powershell

# DCSync detection and monitoring
function Detect-DCSyncAttack {
    param(
        [string[]]$DomainControllers = (Get-ADDomainController -Filter *).HostName,
        [switch]$CheckHistoricalData,
        [int]$DaysBack = 7
    )
    
    $DCReplicationRights = @{
        "DS-Replication-Get-Changes" = "1131f6aa-9c07-11d1-f79f-00c04fc2dcd2"
        "DS-Replication-Get-Changes-All" = "1131f6ad-9c07-11d1-f79f-00c04fc2dcd2"
        "DS-Replication-Get-Changes-In-Filtered-Set" = "89e95b76-444d-4c62-991a-0facbeda640c"
    }
    
    $DetectedThreats = @{
        DCSync = @()
        UnauthorizedReplication = @()
        PermissionChanges = @()
    }
    
    foreach ($DC in $DomainControllers) {
        Write-Host "Analyzing replication events on $DC..." -ForegroundColor Cyan
        
        # Event 4662 - Directory Service Access
        $DSAccessEvents = Get-WinEvent -ComputerName $DC -FilterHashtable @{
            LogName = 'Security'
            ID = 4662
            StartTime = if ($CheckHistoricalData) {
                (Get-Date).AddDays(-$DaysBack)
            } else {
                (Get-Date).AddHours(-4)
            }
        } -ErrorAction SilentlyContinue
        
        foreach ($Event in $DSAccessEvents) {
            $EventData = @{
                Account = $Event.Properties[1].Value
                ObjectDN = $Event.Properties[6].Value
                AccessMask = $Event.Properties[9].Value
                Properties = $Event.Properties[10].Value
                Time = $Event.TimeCreated
            }
            
            # Check for replication rights usage
            foreach ($Right in $DCReplicationRights.Values) {
                if ($EventData.Properties -match $Right) {
                    # Verify if account is authorized DC
                    $AuthorizedDCs = (Get-ADDomainController -Filter *).ComputerObjectDN
                    
                    if ($EventData.Account -notin $AuthorizedDCs -and
                        $EventData.Account -notmatch "SYSTEM|LOCAL SERVICE") {
                        
                        $DetectedThreats.DCSync += [PSCustomObject]@{
                            Type = "DCSync Attack Detected"
                            Account = $EventData.Account
                            TargetDC = $DC
                            ObjectAccessed = $EventData.ObjectDN
                            Time = $EventData.Time
                            ReplicationRight = ($DCReplicationRights.GetEnumerator() | 
                                Where-Object { $_.Value -eq $Right }).Name
                        }
                    }
                }
            }
        }
        
        # Event 4929 - Active Directory replica source naming context removed
        $ReplicationEvents = Get-WinEvent -ComputerName $DC -FilterHashtable @{
            LogName = 'Security'
            ID = @(4928, 4929, 4930, 4931, 4932, 4933, 4934, 4935, 4936, 4937)
            StartTime = (Get-Date).AddHours(-4)
        } -ErrorAction SilentlyContinue
        
        foreach ($ReplEvent in $ReplicationEvents) {
            $SourceDC = $ReplEvent.Properties[3].Value
            $DestDC = $ReplEvent.Properties[4].Value
            
            # Check for non-DC replication attempts
            if ($SourceDC -notmatch "CN=NTDS Settings" -or 
                $DestDC -notmatch "CN=NTDS Settings") {
                
                $DetectedThreats.UnauthorizedReplication += [PSCustomObject]@{
                    EventID = $ReplEvent.Id
                    Description = Switch ($ReplEvent.Id) {
                        4928 { "AD Replica Source Naming Context Established" }
                        4929 { "AD Replica Source Naming Context Removed" }
                        4932 { "Synchronization of AD Naming Context Started" }
                        4933 { "Synchronization of AD Naming Context Failed" }
                        default { "AD Replication Event" }
                    }
                    Source = $SourceDC
                    Destination = $DestDC
                    Time = $ReplEvent.TimeCreated
                    DC = $DC
                }
            }
        }
    }
    
    # Check for permission changes that enable DCSync
    $PermissionAudits = Get-WinEvent -FilterHashtable @{
        LogName = 'Security'
        ID = 5136  # Directory Service Changes
        StartTime = (Get-Date).AddHours(-24)
    } -ErrorAction SilentlyContinue |
    Where-Object {
        $_.Message -match "1131f6aa-9c07-11d1-f79f-00c04fc2dcd2|1131f6ad-9c07-11d1-f79f-00c04fc2dcd2"
    }
    
    foreach ($Audit in $PermissionAudits) {
        $DetectedThreats.PermissionChanges += [PSCustomObject]@{
            Type = "Replication Rights Granted"
            ModifiedBy = ($Audit.Message | Select-String "Account Name:\s+(\S+)" -AllMatches).Matches[1].Groups[1].Value
            TargetObject = ($Audit.Message | Select-String "Object DN:\s+(.+)" -AllMatches).Matches[0].Groups[1].Value
            Time = $Audit.TimeCreated
        }
    }
    
    # Generate report
    Write-Host "`n=== DCSYNC DETECTION REPORT ===" -ForegroundColor Red
    
    if ($DetectedThreats.DCSync) {
        Write-Host "`nDCSYNC ATTACKS DETECTED:" -ForegroundColor Red
        $DetectedThreats.DCSync | Format-Table -AutoSize
    }
    
    if ($DetectedThreats.UnauthorizedReplication) {
        Write-Host "`nUNAUTHORIZED REPLICATION:" -ForegroundColor Yellow
        $DetectedThreats.UnauthorizedReplication | Format-Table -AutoSize
    }
    
    if ($DetectedThreats.PermissionChanges) {
        Write-Host "`nPERMISSION CHANGES:" -ForegroundColor Magenta
        $DetectedThreats.PermissionChanges | Format-Table -AutoSize
    }
    
    return $DetectedThreats
}

Kerberoasting Detection

Identifying service account credential harvesting:

powershell

# Kerberoasting detection system
function Detect-Kerberoasting {
    param(
        [string[]]$DomainControllers = (Get-ADDomainController -Filter *).HostName,
        [int]$ThresholdPerHour = 10,
        [switch]$AnalyzeServiceAccounts
    )
    
    $KerberoastIndicators = @{
        SuspiciousRequests = @()
        VulnerableAccounts = @()
        AnomalousPatterns = @()
    }
    
    foreach ($DC in $DomainControllers) {
        Write-Host "Analyzing Kerberoasting indicators on $DC..." -ForegroundColor Yellow
        
        # Event 4769 - Service Ticket Requests
        $ServiceTickets = Get-WinEvent -ComputerName $DC -FilterHashtable @{
            LogName = 'Security'
            ID = 4769
            StartTime = (Get-Date).AddHours(-24)
        } -ErrorAction SilentlyContinue
        
        # Group by requesting account and time window
        $RequestsByAccount = $ServiceTickets | Group-Object -Property {
            $_.Properties[0].Value  # Account name
        }
        
        foreach ($AccountGroup in $RequestsByAccount) {
            # Analyze request patterns
            $TimeWindows = $AccountGroup.Group | Group-Object -Property {
                [Math]::Floor(($_.TimeCreated - (Get-Date).Date).TotalHours)
            }
            
            foreach ($Window in $TimeWindows) {
                # Check for high-volume requests (potential Kerberoasting)
                if ($Window.Count -gt $ThresholdPerHour) {
                    # Get unique services requested
                    $Services = $Window.Group | ForEach-Object {
                        $_.Properties[2].Value  # Service name
                    } | Select-Object -Unique
                    
                    # Check for RC4 encryption requests (easier to crack)
                    $RC4Requests = $Window.Group | Where-Object {
                        $_.Properties[7].Value -eq 0x17  # RC4-HMAC
                    }
                    
                    $KerberoastIndicators.SuspiciousRequests += [PSCustomObject]@{
                        Account = $AccountGroup.Name
                        RequestCount = $Window.Count
                        TimeWindow = "Hour $($Window.Name)"
                        UniqueServices = $Services.Count
                        RC4Requests = $RC4Requests.Count
                        DC = $DC
                        Severity = if ($Window.Count -gt 50) { "CRITICAL" } 
                                  elseif ($Window.Count -gt 25) { "HIGH" } 
                                  else { "MEDIUM" }
                    }
                }
            }
            
            # Check for requests to service accounts with weak encryption
            $ServiceAccountRequests = $AccountGroup.Group | Where-Object {
                $ServiceName = $_.Properties[2].Value
                $ServiceName -notmatch "krbtgt|HTTP|CIFS|LDAP|HOST" -and
                $ServiceName -match "^[\w\-]+\/[\w\.\-]+(@[\w\.\-]+)?$"
            }
            
            if ($ServiceAccountRequests.Count -gt 5) {
                $KerberoastIndicators.AnomalousPatterns += [PSCustomObject]@{
                    Pattern = "Multiple Service Account Requests"
                    RequestingAccount = $AccountGroup.Name
                    ServiceAccountsTargeted = ($ServiceAccountRequests | ForEach-Object {
                        $_.Properties[2].Value
                    } | Select-Object -Unique).Count
                    TotalRequests = $ServiceAccountRequests.Count
                    Time = $ServiceAccountRequests[0].TimeCreated
                    DC = $DC
                }
            }
        }
    }
    
    # Analyze vulnerable service accounts if requested
    if ($AnalyzeServiceAccounts) {
        Write-Host "Analyzing vulnerable service accounts..." -ForegroundColor Cyan
        
        # Get all service accounts with SPNs
        $ServiceAccounts = Get-ADUser -Filter {ServicePrincipalName -like "*"} -Properties ServicePrincipalName, PasswordLastSet, LastLogonDate |
            Where-Object { $_.Enabled -eq $true }
        
        foreach ($Account in $ServiceAccounts) {
            # Check for weak configurations
            $Vulnerabilities = @()
            
            # Old password
            if ($Account.PasswordLastSet -lt (Get-Date).AddDays(-365)) {
                $Vulnerabilities += "Password older than 365 days"
            }
            
            # Check if using RC4 encryption
            $UserAccountControl = (Get-ADUser $Account -Properties msDS-SupportedEncryptionTypes).'msDS-SupportedEncryptionTypes'
            if ($null -eq $UserAccountControl -or ($UserAccountControl -band 0x4) -eq 0) {
                $Vulnerabilities += "RC4 encryption enabled"
            }
            
            # High-privilege service account
            $Groups = Get-ADPrincipalGroupMembership $Account | Select-Object -ExpandProperty Name
            if ($Groups -match "Domain Admins|Enterprise Admins|Administrators") {
                $Vulnerabilities += "High privilege account"
            }
            
            if ($Vulnerabilities) {
                $KerberoastIndicators.VulnerableAccounts += [PSCustomObject]@{
                    Account = $Account.SamAccountName
                    SPNs = ($Account.ServicePrincipalName -join ", ")
                    Vulnerabilities = ($Vulnerabilities -join "; ")
                    PasswordAge = [Math]::Round(((Get-Date) - $Account.PasswordLastSet).TotalDays)
                    LastLogon = $Account.LastLogonDate
                }
            }
        }
    }
    
    # Generate detection report
    Write-Host "`n=== KERBEROASTING DETECTION REPORT ===" -ForegroundColor Red
    
    if ($KerberoastIndicators.SuspiciousRequests) {
        Write-Host "`nSUSPICIOUS SERVICE TICKET REQUESTS:" -ForegroundColor Red
        $KerberoastIndicators.SuspiciousRequests | 
            Sort-Object RequestCount -Descending | 
            Format-Table -AutoSize
    }
    
    if ($KerberoastIndicators.AnomalousPatterns) {
        Write-Host "`nANOMALOUS PATTERNS DETECTED:" -ForegroundColor Yellow
        $KerberoastIndicators.AnomalousPatterns | Format-Table -AutoSize
    }
    
    if ($KerberoastIndicators.VulnerableAccounts) {
        Write-Host "`nVULNERABLE SERVICE ACCOUNTS:" -ForegroundColor Magenta
        $KerberoastIndicators.VulnerableAccounts | 
            Sort-Object PasswordAge -Descending | 
            Format-Table -AutoSize
    }
    
    return $KerberoastIndicators
}

LDAP and Directory Service Monitoring

LDAP Attack Detection

Monitoring LDAP operations for enumeration and attacks:

powershell

# LDAP monitoring and attack detection
function Monitor-LDAPActivity {
    param(
        [string[]]$DomainControllers = (Get-ADDomainController -Filter *).HostName,
        [int]$Hours = 4,
        [switch]$DetectEnumeration
    )
    
    $LDAPAnalysis = @{
        Statistics = @{}
        EnumerationAttempts = @()
        SuspiciousQueries = @()
        PerformanceIssues = @()
    }
    
    foreach ($DC in $DomainControllers) {
        Write-Host "Analyzing LDAP activity on $DC..." -ForegroundColor Cyan
        
        # Directory Service event log
        try {
            $DSEvents = Get-WinEvent -ComputerName $DC -LogName "Directory Service" -MaxEvents 10000 |
                Where-Object { 
                    $_.TimeCreated -gt (Get-Date).AddHours(-$Hours) -and
                    $_.Id -in @(1644, 1139, 2889, 2887, 2886)
                }
            
            foreach ($Event in $DSEvents) {
                switch ($Event.Id) {
                    1644 {  # LDAP searches
                        if ($Event.Message -match "Client:\s+([^\s]+)") {
                            $Client = $Matches[1]
                            
                            # Track LDAP search statistics
                            if (-not $LDAPAnalysis.Statistics.ContainsKey($Client)) {
                                $LDAPAnalysis.Statistics[$Client] = 0
                            }
                            $LDAPAnalysis.Statistics[$Client]++
                            
                            # Detect enumeration patterns
                            if ($DetectEnumeration) {
                                # Check for sensitive attribute queries
                                if ($Event.Message -match "userPassword|unixUserPassword|unicodePwd|ms-Mcs-AdmPwd") {
                                    $LDAPAnalysis.SuspiciousQueries += [PSCustomObject]@{
                                        Type = "Sensitive Attribute Query"
                                        Client = $Client
                                        Attribute = $Matches[0]
                                        Time = $Event.TimeCreated
                                        DC = $DC
                                    }
                                }
                                
                                # Check for large result sets (enumeration)
                                if ($Event.Message -match "Entries Returned:\s+(\d+)" -and [int]$Matches[1] -gt 1000) {
                                    $LDAPAnalysis.EnumerationAttempts += [PSCustomObject]@{
                                        Type = "Large LDAP Query"
                                        Client = $Client
                                        EntriesReturned = $Matches[1]
                                        Time = $Event.TimeCreated
                                        DC = $DC
                                    }
                                }
                            }
                        }
                    }
                    
                    2889 {  # Unsigned LDAP bind
                        $LDAPAnalysis.SuspiciousQueries += [PSCustomObject]@{
                            Type = "Unsigned LDAP Bind"
                            Details = "Potential MITM vulnerability"
                            Message = $Event.Message
                            Time = $Event.TimeCreated
                            DC = $DC
                        }
                    }
                    
                    2887 {  # LDAP signing requirement bypassed
                        $LDAPAnalysis.SuspiciousQueries += [PSCustomObject]@{
                            Type = "LDAP Signing Bypassed"
                            Details = "Security configuration issue"
                            Time = $Event.TimeCreated
                            DC = $DC
                        }
                    }
                    
                    1139 {  # LDAP performance issue
                        if ($Event.Message -match "expensive|inefficient") {
                            $LDAPAnalysis.PerformanceIssues += [PSCustomObject]@{
                                Type = "Expensive LDAP Query"
                                Details = $Event.Message.Substring(0, [Math]::Min(200, $Event.Message.Length))
                                Time = $Event.TimeCreated
                                DC = $DC
                            }
                        }
                    }
                }
            }
        }
        catch {
            Write-Warning "Could not access Directory Service log on $DC: $_"
        }
        
        # Check Security log for LDAP-related events
        $SecurityEvents = Get-WinEvent -ComputerName $DC -FilterHashtable @{
            LogName = 'Security'
            ID = @(4662, 5136, 5137, 5138, 5139, 5141)
            StartTime = (Get-Date).AddHours(-$Hours)
        } -ErrorAction SilentlyContinue
        
        # Analyze directory service modifications
        $ModificationEvents = $SecurityEvents | Where-Object { $_.Id -in @(5136, 5137, 5138, 5139, 5141) }
        
        if ($ModificationEvents) {
            $ModsByUser = $ModificationEvents | Group-Object -Property {
                ($_.Message | Select-String "Account Name:\s+(\S+)" -AllMatches).Matches[0].Groups[1].Value
            }
            
            foreach ($UserMods in $ModsByUser) {
                if ($UserMods.Count -gt 50) {
                    $LDAPAnalysis.SuspiciousQueries += [PSCustomObject]@{
                        Type = "Bulk Directory Modifications"
                        Account = $UserMods.Name
                        ModificationCount = $UserMods.Count
                        Time = $UserMods.Group[0].TimeCreated
                        DC = $DC
                    }
                }
            }
        }
    }
    
    # Generate LDAP monitoring report
    Write-Host "`n=== LDAP ACTIVITY ANALYSIS ===" -ForegroundColor Yellow
    
    if ($LDAPAnalysis.Statistics.Count -gt 0) {
        Write-Host "`nLDAP Client Statistics:" -ForegroundColor Cyan
        $LDAPAnalysis.Statistics.GetEnumerator() | 
            Sort-Object Value -Descending |
            Select-Object -First 10 |
            ForEach-Object {
                Write-Host "  $($_.Key): $($_.Value) queries"
            }
    }
    
    if ($LDAPAnalysis.EnumerationAttempts) {
        Write-Host "`nPOTENTIAL ENUMERATION ATTEMPTS:" -ForegroundColor Red
        $LDAPAnalysis.EnumerationAttempts | Format-Table -AutoSize
    }
    
    if ($LDAPAnalysis.SuspiciousQueries) {
        Write-Host "`nSUSPICIOUS LDAP QUERIES:" -ForegroundColor Yellow
        $LDAPAnalysis.SuspiciousQueries | Format-Table -AutoSize
    }
    
    return $LDAPAnalysis
}

Group Policy and SYSVOL Monitoring

GPO Modification Detection

Monitoring Group Policy changes for backdoors and persistence:

powershell

# GPO security monitoring system
function Monitor-GroupPolicyChanges {
    param(
        [string]$DomainName = (Get-ADDomain).DNSRoot,
        [int]$Hours = 24,
        [switch]$CheckSYSVOLIntegrity
    )
    
    $GPOMonitoring = @{
        ModifiedGPOs = @()
        NewGPOs = @()
        DeletedGPOs = @()
        SYSVOLChanges = @()
        SecurityConcerns = @()
    }
    
    # Get all GPO modification events
    $DomainControllers = (Get-ADDomainController -Filter *).HostName
    
    foreach ($DC in $DomainControllers) {
        Write-Host "Checking GPO changes on $DC..." -ForegroundColor Cyan
        
        # Event 5136 - Directory Service Changes (GPO modifications)
        $GPOEvents = Get-WinEvent -ComputerName $DC -FilterHashtable @{
            LogName = 'Security'
            ID = @(5136, 5137, 5141)
            StartTime = (Get-Date).AddHours(-$Hours)
        } -ErrorAction SilentlyContinue |
        Where-Object { $_.Message -match "CN=Policies,CN=System" }
        
        foreach ($Event in $GPOEvents) {
            $GPOInfo = @{
                EventType = switch ($Event.Id) {
                    5136 { "GPO Modified" }
                    5137 { "GPO Created" }
                    5141 { "GPO Deleted" }
                }
                ModifiedBy = ($Event.Message | Select-String "Account Name:\s+(\S+)" -AllMatches).Matches[1].Groups[1].Value
                ObjectDN = ($Event.Message | Select-String "Object DN:\s+(.+)" -AllMatches).Matches[0].Groups[1].Value
                Time = $Event.TimeCreated
                DC = $DC
            }
            
            # Extract GPO GUID
            if ($GPOInfo.ObjectDN -match "\{([A-F0-9\-]+)\}") {
                $GPOInfo.GPOID = $Matches[1]
                
                # Try to get GPO name
                try {
                    $GPO = Get-GPO -Guid $GPOInfo.GPOID -ErrorAction SilentlyContinue
                    $GPOInfo.GPOName = $GPO.DisplayName
                }
                catch {
                    $GPOInfo.GPOName = "Unknown (possibly deleted)"
                }
            }
            
            # Categorize the change
            switch ($Event.Id) {
                5136 { $GPOMonitoring.ModifiedGPOs += [PSCustomObject]$GPOInfo }
                5137 { $GPOMonitoring.NewGPOs += [PSCustomObject]$GPOInfo }
                5141 { $GPOMonitoring.DeletedGPOs += [PSCustomObject]$GPOInfo }
            }
            
            # Check for suspicious GPO names or patterns
            if ($GPOInfo.GPOName -match "temp|test|debug|backdoor" -or 
                $GPOInfo.ModifiedBy -notmatch "Domain Admins|Group Policy Creator Owners") {
                $GPOMonitoring.SecurityConcerns += [PSCustomObject]@{
                    Concern = "Suspicious GPO Activity"
                    GPOName = $GPOInfo.GPOName
                    ModifiedBy = $GPOInfo.ModifiedBy
                    Action = $GPOInfo.EventType
                    Time = $GPOInfo.Time
                }
            }
        }
    }
    
    # Check SYSVOL integrity if requested
    if ($CheckSYSVOLIntegrity) {
        Write-Host "Checking SYSVOL integrity..." -ForegroundColor Yellow
        
        $SYSVOLPath = "\\$DomainName\SYSVOL\$DomainName\Policies"
        
        # Get all GPO folders in SYSVOL
        $SYSVOLGPOs = Get-ChildItem -Path $SYSVOLPath -Directory |
            Where-Object { $_.Name -match "\{[A-F0-9\-]+\}" }
        
        foreach ($GPOFolder in $SYSVOLGPOs) {
            # Check for suspicious files
            $SuspiciousFiles = Get-ChildItem -Path $GPOFolder.FullName -Recurse -File |
                Where-Object { 
                    $_.Extension -in @('.exe', '.dll', '.ps1', '.bat', '.cmd', '.vbs', '.js') -or
                    $_.Name -match 'backdoor|malware|payload|shell'
                }
            
            if ($SuspiciousFiles) {
                foreach ($File in $SuspiciousFiles) {
                    $GPOMonitoring.SecurityConcerns += [PSCustomObject]@{
                        Concern = "Suspicious File in GPO"
                        GPOPath = $GPOFolder.Name
                        FileName = $File.Name
                        FilePath = $File.FullName
                        LastModified = $File.LastWriteTime
                    }
                }
            }
            
            # Check for recent modifications
            $RecentChanges = Get-ChildItem -Path $GPOFolder.FullName -Recurse |
                Where-Object { $_.LastWriteTime -gt (Get-Date).AddHours(-$Hours) }
            
            if ($RecentChanges) {
                $GPOMonitoring.SYSVOLChanges += [PSCustomObject]@{
                    GPO = $GPOFolder.Name
                    ChangedFiles = $RecentChanges.Count
                    LastChange = ($RecentChanges | Sort-Object LastWriteTime -Descending | Select-Object -First 1).LastWriteTime
                }
            }
        }
    }
    
    # Generate monitoring report
    Write-Host "`n=== GROUP POLICY MONITORING REPORT ===" -ForegroundColor Yellow
    
    if ($GPOMonitoring.NewGPOs) {
        Write-Host "`nNEW GPOs CREATED:" -ForegroundColor Green
        $GPOMonitoring.NewGPOs | Format-Table -AutoSize
    }
    
    if ($GPOMonitoring.ModifiedGPOs) {
        Write-Host "`nMODIFIED GPOs:" -ForegroundColor Yellow
        $GPOMonitoring.ModifiedGPOs | Format-Table -AutoSize
    }
    
    if ($GPOMonitoring.DeletedGPOs) {
        Write-Host "`nDELETED GPOs:" -ForegroundColor Red
        $GPOMonitoring.DeletedGPOs | Format-Table -AutoSize
    }
    
    if ($GPOMonitoring.SecurityConcerns) {
        Write-Host "`nSECURITY CONCERNS DETECTED:" -ForegroundColor Red -BackgroundColor Yellow
        $GPOMonitoring.SecurityConcerns | Format-Table -AutoSize
    }
    
    return $GPOMonitoring
}

Automated Threat Hunting and Response

Machine Learning-Based Anomaly Detection

Implementing ML for advanced AD threat detection:

python

# Python script for ML-based AD anomaly detection
import pandas as pd
import numpy as np
from sklearn.ensemble import IsolationForest
from sklearn.preprocessing import StandardScaler
from datetime import datetime, timedelta
import win32evtlog
import win32evtlogutil
import json

class ADSecurityAnalyzer:
    def __init__(self, domain_controllers):
        self.dcs = domain_controllers
        self.model = IsolationForest(contamination=0.05, random_state=42)
        self.scaler = StandardScaler()
        self.baseline_data = None
        
    def extract_features(self, events_df):
        """Extract behavioral features from AD events"""
        features = pd.DataFrame()
        
        # Time-based features
        features['hour'] = pd.to_datetime(events_df['TimeGenerated']).dt.hour
        features['day_of_week'] = pd.to_datetime(events_df['TimeGenerated']).dt.dayofweek
        features['is_weekend'] = features['day_of_week'].isin([5, 6]).astype(int)
        features['is_business_hours'] = features['hour'].between(8, 18).astype(int)
        
        # Authentication features
        auth_events = events_df[events_df['EventID'].isin([4624, 4625, 4768, 4771])]
        features['auth_failure_rate'] = (
            auth_events[auth_events['EventID'].isin([4625, 4771])].shape[0] /
            max(auth_events.shape[0], 1)
        )
        
        # Kerberos features
        kerb_events = events_df[events_df['EventID'].isin([4768, 4769, 4770, 4771])]
        features['tgt_requests'] = kerb_events[kerb_events['EventID'] == 4768].shape[0]
        features['service_tickets'] = kerb_events[kerb_events['EventID'] == 4769].shape[0]
        features['ticket_renewals'] = kerb_events[kerb_events['EventID'] == 4770].shape[0]
        
        # Privilege escalation indicators
        priv_events = events_df[events_df['EventID'].isin([4672, 4673, 4674])]
        features['privilege_events'] = priv_events.shape[0]
        
        # Group membership changes
        group_events = events_df[events_df['EventID'].isin([4728, 4729, 4732, 4733, 4756, 4757])]
        features['group_changes'] = group_events.shape[0]
        
        # Account management
        account_events = events_df[events_df['EventID'].isin([4720, 4722, 4723, 4724, 4725, 4726])]
        features['account_changes'] = account_events.shape[0]
        
        # Calculate entropy of source IPs
        if 'SourceIP' in events_df.columns:
            ip_counts = events_df['SourceIP'].value_counts()
            ip_probs = ip_counts / ip_counts.sum()
            features['ip_entropy'] = -sum(ip_probs * np.log2(ip_probs + 1e-10))
        
        # Unique accounts accessing the system
        if 'AccountName' in events_df.columns:
            features['unique_accounts'] = events_df['AccountName'].nunique()
            
            # Check for service account anomalies
            service_accounts = events_df[events_df['AccountName'].str.endswith('$')]
            features['service_account_activity'] = service_accounts.shape[0]
        
        return features
    
    def train_baseline(self, historical_events):
        """Train the anomaly detection model on historical data"""
        print("Training baseline model on historical data...")
        
        # Extract features from historical data
        features = self.extract_features(historical_events)
        
        # Scale features
        scaled_features = self.scaler.fit_transform(features.fillna(0))
        
        # Train isolation forest
        self.model.fit(scaled_features)
        self.baseline_data = features
        
        print(f"Baseline trained on {len(historical_events)} events")
        
    def detect_anomalies(self, current_events):
        """Detect anomalies in current events"""
        if self.baseline_data is None:
            raise ValueError("Model not trained. Run train_baseline first.")
        
        # Extract features
        features = self.extract_features(current_events)
        
        # Scale features
        scaled_features = self.scaler.transform(features.fillna(0))
        
        # Predict anomalies
        predictions = self.model.predict(scaled_features)
        anomaly_scores = self.model.score_samples(scaled_features)
        
        # Create anomaly report
        anomalies = []
        for i, (pred, score) in enumerate(zip(predictions, anomaly_scores)):
            if pred == -1:  # Anomaly detected
                anomaly_detail = {
                    'timestamp': datetime.now().isoformat(),
                    'anomaly_score': float(score),
                    'features': features.iloc[i].to_dict(),
                    'severity': self.calculate_severity(score, features.iloc[i])
                }
                anomalies.append(anomaly_detail)
        
        return anomalies
    
    def calculate_severity(self, score, features):
        """Calculate anomaly severity based on score and features"""
        severity = "LOW"
        
        # High-risk indicators
        if features.get('privilege_events', 0) > 5:
            severity = "HIGH"
        elif features.get('group_changes', 0) > 3:
            severity = "HIGH"
        elif features.get('auth_failure_rate', 0) > 0.5:
            severity = "MEDIUM"
        elif score < -0.5:
            severity = "CRITICAL"
        elif score < -0.3:
            severity = "HIGH"
        elif score < -0.1:
            severity = "MEDIUM"
            
        return severity
    
    def generate_threat_report(self, anomalies):
        """Generate comprehensive threat report"""
        report = {
            'timestamp': datetime.now().isoformat(),
            'total_anomalies': len(anomalies),
            'critical_count': sum(1 for a in anomalies if a['severity'] == 'CRITICAL'),
            'high_count': sum(1 for a in anomalies if a['severity'] == 'HIGH'),
            'threat_categories': {},
            'recommendations': []
        }
        
        # Categorize threats
        for anomaly in anomalies:
            features = anomaly['features']
            
            # Determine threat category
            if features.get('privilege_events', 0) > 5:
                category = 'Privilege Escalation'
            elif features.get('auth_failure_rate', 0) > 0.5:
                category = 'Brute Force/Password Spray'
            elif features.get('group_changes', 0) > 3:
                category = 'Unauthorized Group Modification'
            elif features.get('service_tickets', 0) > 100:
                category = 'Potential Kerberoasting'
            elif not features.get('is_business_hours', 1):
                category = 'After-Hours Activity'
            else:
                category = 'Uncategorized Anomaly'
            
            if category not in report['threat_categories']:
                report['threat_categories'][category] = []
            
            report['threat_categories'][category].append({
                'severity': anomaly['severity'],
                'score': anomaly['anomaly_score'],
                'details': anomaly['features']
            })
        
        # Generate recommendations
        if 'Privilege Escalation' in report['threat_categories']:
            report['recommendations'].append(
                "Review privileged account usage and verify all privilege assignments"
            )
        if 'Brute Force/Password Spray' in report['threat_categories']:
            report['recommendations'].append(
                "Investigate source IPs for authentication failures and consider blocking"
            )
        if 'Potential Kerberoasting' in report['threat_categories']:
            report['recommendations'].append(
                "Review service account configurations and reset passwords for high-value accounts"
            )
        
        return report

# Usage example
analyzer = ADSecurityAnalyzer(['DC01', 'DC02'])
# analyzer.train_baseline(historical_events_df)
# anomalies = analyzer.detect_anomalies(current_events_df)
# report = analyzer.generate_threat_report(anomalies)

SIEM Integration and Correlation Rules

Splunk Correlation Rules for AD Security

conf

# Splunk correlation searches for AD security monitoring

# Golden Ticket Detection
[Golden Ticket - Service Ticket without TGT]
search = index=wineventlog sourcetype=WinEventLog:Security EventCode=4769 
| eval ticket_time=_time 
| join type=left Account_Name 
    [search index=wineventlog sourcetype=WinEventLog:Security EventCode=4768 earliest=-5m@m 
    | eval tgt_time=_time] 
| where isnull(tgt_time) 
| table _time, ComputerName, Account_Name, Service_Name, Client_Address
alert.track = 1
alert.severity = 3
cron_schedule = */5 * * * *
dispatch.earliest_time = -5m
dispatch.latest_time = now

# DCSync Attack Detection
[DCSync - Replication Rights Usage by Non-DC]
search = index=wineventlog sourcetype=WinEventLog:Security EventCode=4662 
| rex field=Properties "%%(?<Properties>\d+)" 
| where Properties IN ("1131f6aa-9c07-11d1-f79f-00c04fc2dcd2", 
                       "1131f6ad-9c07-11d1-f79f-00c04fc2dcd2",
                       "89e95b76-444d-4c62-991a-0facbeda640c")
| where NOT match(Account_Name, ".*\$$") 
| stats count by Account_Name, ComputerName, Object_Name, _time
alert.track = 1
alert.severity = 1
cron_schedule = */15 * * * *

# Kerberoasting Detection
[Kerberoasting - Excessive Service Ticket Requests]
search = index=wineventlog sourcetype=WinEventLog:Security EventCode=4769 
| where Ticket_Encryption_Type=0x17 
| bucket _time span=1h 
| stats count as ticket_count, dc(Service_Name) as unique_services by Account_Name, _time 
| where ticket_count > 20 AND unique_services > 5
alert.track = 1
alert.severity = 2
cron_schedule = 0 * * * *

# Password Spray Detection
[Password Spray - Multiple Failed Authentications]
search = index=wineventlog sourcetype=WinEventLog:Security (EventCode=4625 OR EventCode=4771)
| bucket _time span=5m
| stats dc(Account_Name) as unique_accounts, count as failures by Source_Network_Address, _time
| where unique_accounts > 10 AND failures > 20
alert.track = 1
alert.severity = 2
cron_schedule = */5 * * * *

# Privileged Group Changes
[Critical Group Membership Changes]
search = index=wineventlog sourcetype=WinEventLog:Security EventCode IN (4728,4729,4732,4733,4756,4757)
| rex field=Group_Name "(?<Critical_Group>Domain Admins|Enterprise Admins|Schema Admins|Administrators)"
| where isnotnull(Critical_Group)
| table _time, Subject_Account_Name, Member_Name, Group_Name, Operation
alert.track = 1
alert.severity = 1
cron_schedule = */10 * * * *

ElasticSearch Detection Queries

json

// Elasticsearch Watcher for AD security monitoring

{
  "trigger": {
    "schedule": {
      "interval": "5m"
    }
  },
  "input": {
    "search": {
      "request": {
        "search_type": "query_then_fetch",
        "indices": ["winlogbeat-*"],
        "body": {
          "query": {
            "bool": {
              "must": [
                {
                  "term": {
                    "event.code": "4769"
                  }
                },
                {
                  "range": {
                    "@timestamp": {
                      "gte": "now-1h"
                    }
                  }
                }
              ]
            }
          },
          "aggs": {
            "by_account": {
              "terms": {
                "field": "user.name",
                "size": 100
              },
              "aggs": {
                "unique_services": {
                  "cardinality": {
                    "field": "winlog.event_data.ServiceName"
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "condition": {
    "script": {
      "source": """
        return ctx.payload.aggregations.by_account.buckets.stream()
          .anyMatch(bucket -> bucket.doc_count > 50 && bucket.unique_services.value > 10)
      """
    }
  },
  "actions": {
    "send_alert": {
      "webhook": {
        "scheme": "https",
        "host": "security.example.com",
        "port": 443,
        "method": "post",
        "path": "/api/alerts",
        "body": """
        {
          "alert": "Potential Kerberoasting Attack",
          "severity": "HIGH",
          "details": "{{ctx.payload.aggregations.by_account.buckets}}"
        }
        """
      }
    }
  }
}

Best Practices and Security Hardening

AD Security Monitoring Checklist

Essential monitoring requirements for enterprise AD environments:

Authentication Monitoring

  • Monitor all Kerberos authentication events (4768, 4769, 4770, 4771)
  • Track NTLM authentication usage (4776)
  • Alert on authentication from unusual locations
  • Monitor service account authentication patterns

Privilege Monitoring

  • Track all changes to privileged groups
  • Monitor AdminSDHolder modifications
  • Alert on privilege escalation events
  • Audit delegation changes

Replication Monitoring

  • Monitor DCSync indicators
  • Track replication metadata changes
  • Alert on non-DC replication attempts
  • Monitor DRS protocol usage

Object Monitoring

  • Track critical object modifications
  • Monitor schema changes
  • Alert on security descriptor changes
  • Audit GPO modifications

Service Account Security

  • Monitor SPN modifications
  • Track Kerberoasting indicators
  • Alert on service account privilege changes
  • Monitor delegation settings

Security Configuration Scripts

powershell

# Comprehensive AD security hardening script
function Harden-ADSecurity {
    param(
        [switch]$EnableAdvancedAuditing,
        [switch]$ConfigureSysmon,
        [switch]$HardenKerberos
    )
    
    Write-Host "Starting Active Directory Security Hardening..." -ForegroundColor Green
    
    if ($EnableAdvancedAuditing) {
        # Configure advanced audit policies
        Write-Host "Configuring Advanced Audit Policies..." -ForegroundColor Yellow
        
        $AuditPolicies = @(
            "Account Logon,Credential Validation,Success,Failure",
            "Account Logon,Kerberos Authentication Service,Success,Failure",
            "Account Logon,Kerberos Service Ticket Operations,Success,Failure",
            "Account Management,Security Group Management,Success,Failure",
            "Account Management,User Account Management,Success,Failure",
            "DS Access,Directory Service Access,Success,Failure",
            "DS Access,Directory Service Changes,Success,Failure",
            "Logon/Logoff,Logon,Success,Failure",
            "Logon/Logoff,Special Logon,Success,Failure",
            "Object Access,Central Policy Staging,Success,Failure",
            "Policy Change,Authentication Policy Change,Success,Failure",
            "Policy Change,Authorization Policy Change,Success,Failure",
            "Privilege Use,Sensitive Privilege Use,Success,Failure"
        )
        
        foreach ($Policy in $AuditPolicies) {
            $Parts = $Policy -split ','
            auditpol /set /subcategory:"$($Parts[1])" /success:enable /failure:enable
        }
        
        # Enable command line process auditing
        $RegPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Audit"
        New-Item -Path $RegPath -Force | Out-Null
        Set-ItemProperty -Path $RegPath -Name "ProcessCreationIncludeCmdLine_Enabled" -Value 1
    }
    
    if ($HardenKerberos) {
        # Kerberos hardening
        Write-Host "Hardening Kerberos Configuration..." -ForegroundColor Yellow
        
        # Set Kerberos policies
        $KerberosPolicies = @{
            "MaxTicketAge" = 10  # Hours
            "MaxRenewAge" = 7    # Days
            "MaxServiceAge" = 600 # Minutes
            "MaxClockSkew" = 5   # Minutes
        }
        
        foreach ($Policy in $KerberosPolicies.GetEnumerator()) {
            Set-ADDefaultDomainPasswordPolicy -$($Policy.Key) $($Policy.Value)
        }
        
        # Disable weak encryption types
        Set-ADAccountControl -UseDESKeyOnly $false
        
        # Configure SPN validation
        Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\Kdc" `
                         -Name "ValidateKdcPacSignature" -Value 1
    }
    
    # Configure Protected Users group
    Write-Host "Configuring Protected Users..." -ForegroundColor Yellow
    $ProtectedUsers = Get-ADGroup -Filter {Name -eq "Protected Users"} -ErrorAction SilentlyContinue
    if ($ProtectedUsers) {
        $HighValueAccounts = Get-ADUser -Filter {
            (memberof -recursiveMatch "CN=Domain Admins,CN=Users,DC=*") -or
            (memberof -recursiveMatch "CN=Enterprise Admins,CN=Users,DC=*")
        }
        
        foreach ($Account in $HighValueAccounts) {
            Add-ADGroupMember -Identity "Protected Users" -Members $Account -ErrorAction SilentlyContinue
        }
    }
    
    Write-Host "Active Directory Security Hardening Complete!" -ForegroundColor Green
}

# Run hardening
Harden-ADSecurity -EnableAdvancedAuditing -HardenKerberos

Performance and Scalability Considerations

Event volume estimation for AD monitoring:

Environment SizeDCsDaily Event VolumeStorage (30 days)SIEM RequirementsSmall (< 1000 users)250-100 GB3 TBSplunk/ELKMedium (1000-5000)4200-500 GB15 TBSplunk EnterpriseLarge (5000-25000)8+1-2 TB60 TBSplunk/QRadarEnterprise (25000+)20+5+ TB150+ TBSplunk/Sentinel

Related Articles and Resources

Need Professional Active Directory Security Implementation?

Our security experts specialize in designing and implementing comprehensive Active Directory security monitoring solutions, from architecture design to threat detection and incident response. Contact our team for enterprise AD security assessment and monitoring implementation.

This technical guide was prepared by the security operations team at Secure Debug, specializing in Active Directory security, enterprise threat detection, and identity management for complex domain environments.

top
SEND US A MAIL

Let’s Talk Cybersecurity Solutions!

Let us help you get your project started.

Securedebug offers 360 degree protection services to keep your company safe in the cyber world!

Contact:

Unit 18, Innovation Centre Cranfield Technology Park, Cranfield, Bedfordshire, England, MK43 0BT

Follow Us: