Constrained Delegation
In 2003, Microsoft released an updated and safer version
of Kerberos delegation known as constrained delegation.
The main goal of Kerberos delegation is to solve the double-hop issue.
While unconstrained delegation allowed the service
to perform authentication to anything in the domain,
constrained delegation limits the delegation scope.
Since the Kerberos protocol
does not natively support constrained delegation by default,
Microsoft released two extensions for this feature:
S4U2Self, and S4U2Proxy.
Together, these extensions solve the double-hop issue
and limit access to only the desired backend service.
Constrained delegation is configured on the computer or user object.
It is set through the msds-allowedtodelegateto property,
by specifying the SPNs the current object is allowed constrained delegation against.
Before we delve into the details of how these extensions work,
we will locate any instances of constrained delegation
in our lab environment.
To do so, once again, we’ll turn to PowerView and use Get-DomainUser
together with the -TrustedToAuth flag,
which will enumerate constrained delegation.
We’ll focus on three important aspects of the output.
First, constrained delegation is configured for the IISSvc account.
Its name indicates that it is likely
a service account for a web server running IIS.
Next, notice that the msds-allowedtodelegateto property
contains the SPN of the MS SQL server on CDC01.
This tells us that constrained delegation is only allowed to that SQL server.
Finally, the TRUSTED_TO_AUTH_FOR_DELEGATION value
in the useraccountcontrol property is set.
This value is used to indicate whether constrained delegation
can be used if the authentication between the user and the service
uses a different authentication mechanism like NTLM.
This is the scenerio that we are going to explore.
Before continuing, let’s discuss these extensions beginning with S4U2Self.
If a frontend service does not use Kerberos authentication and
the backend service does, it needs to be able to request a TGS to the frontend
service from a KDC on behalf of the user who is authenticating against it.
The S4U2Self extension enables this if the TRUSTED_TO_AUTH_FOR_DELEGATION
value is present in the useraccountcontrol property
Additionally, the frontend service can do this without requiring the password
or the hash of the user.
In our specific case, this means that if we compromise the _IISSvc_ account,
we can request a service ticket to IIS for any user in the domain,
including a domain administrator.
Similar to S4U2Self, the S4U2proxy extension
requests a service ticket for the backend service on behalf of a user.
This extension depends on the service ticket obtained either through S4U2Self
or directly from an user authentication via Kerberos
In our case, this extension allows IISSvc
to request a service ticket to any of the services given as SPNs
in the msds-allowedtodelegateto field.
More specifically it would use the TGS obtained through the S4U2Self extension
and submit it as part as the S4U2Proxy request for the backend service
Once this service ticket request is made and the ticket is returned by the KDC,
IISSvc can perform authentication to that specific service on that specific host.
Again, assuming that we are able to compromise the IISSvc account,
we can request a service ticket for the services listed
in the msds-allowedtodelegateto field as any user in the domain.
Depending on the type of service, this may lead to code execution.
Constrained delegation yields a more difficult compromise path
than unconstrained delegation, but it is still exploitable.
To demonstrate this, we’ll simulate a compromise of the IISSvc account
and abuse that to gain access to the MSSQL instance on CDC01.
We’ll once again turn to Rubeus, which includes S4U extension support.
Note that we do not need to execute in the context of the IISSvc account
in order to exploit the account.
We only need the password hash.
However, if we only have the clear text password,
we can use the hash command in Rubeus to generate the NTLM hash.
Next, we’ll use Rubeus to generate a TGT for IISSvc with the asktgt command,
by supplying the username,
domain,
and NTLM hash.
Armed with the Base64-encoded TGT for IISSvc,
we are ready to invoke the SU4 extensions.
We can do this with Rubeus by first specifying the s4u command,
and then providing the Base64-encoded TGT,
and the username we want to impersonate,
in our case, the administrator account of the domain.
This will make use of S4U2Self.
We’ll also supply the SPN of the service, which is used with S4U2Proxy,
and finally the /ptt flag to directly inject it into memory.
The first request is made by S4U2Self,
and the second by S4U2Proxy.
This attempt was successful
and we obtained a usable service ticket for the MSSQL service instance
on CDC01.
Since the TGS for MSSQL on CDC01 was injected into memory,
we can verify that it worked
by turning to the MSSQL attacks we developed in a previous module.
The Tools folder contains a compiled version of the MSSQL login application.
We’ll use this to validate that we are authenticated to MSSQL
as the impersonated user.
The output reveals that we have logged in to the MSSQL instance
as the domain administrator.
Excellent!
By compromising an account that has constrained delegation enabled,
we can gain access to all the services configured
through the msDS-AllowedToDelegateTo property.
If the TRUSTED_TO_AUTH_FOR_DELEGATION value is set,
we can do this without user interaction.
In this section’s example, we obtained a TGS for the MSSQLSvc service name
on the CDC01.PROD.CORP1.COM server.
Interestingly, when the TGS is returned from the KDC,
the server name is encrypted, but not the service name.
This means we can modify the service name within the TGS in memory
and obtain access to a different service on the same host.
We can do this through Rubeus with the /altservice option.
In this case, we’ll attempt to gain access to the CIFS service.
This TGS should yield access to the file system
and potentially direct code execution.
Unfortunately, the SPN for the MSSQL server ends with “:1433”,
which is not usable for CIFS
since it requires an SPN with a specific format.
If we were to modify the SPN by removing the port number from the command,
Rubeus would generate an error,
indicating that the modified SPN is not registered.
On the other hand, if the SPN configured for constrained delegation
only uses the service and host name,
we could modify the TGS to access any service on the system.
In the next section, we’ll cover the newest iteration of Kerberos delegation
and demonstrate how it can be exploited.