Another Word on Delegation

Every time I think I start to understand Active Directory and Kerberos, a new topic pops up to mess with my head.

A few weeks ago, @elad_shamir contacted @tifkin_ and myself with some ideas about resource-based Kerberos constrained delegation. Thanks to Elad’s ideas, the great back and forth, and his awesome pull request to Rubeus, we now understand this attack vector and have a tool to abuse it. We also now have something @_wald0, @cptjesus, and I have wanted for a long while- an ACL-based computer object takeover primitive!

But first, some background on delegation and a dive into its resource-based flavor.

Delegation Background

Say you have a server (or service account) that needs to impersonate another user for some reason. One common scenario is when a user authenticates to a web server, using Kerberos or other protocols, and the server wants to nicely integrate with a SQL backend. This is the classic example of why delegation is needed.

Unconstrained Delegation

Unconstrained delegation used to be the only option available in Windows 2000, and the functionality has been kept (presumably for backwards compatibility reasons). We’ll only briefly cover this delegation type as Sean Metcalf has a great post that covers it in depth. In that article Sean states, “When Kerberos Unconstrained Delegation is enabled on the server hosting the service specified in the Service Principal Name referenced in the TGS-REQ (step 3), the Domain Controller the DC places a copy of the user’s TGT into the service ticket. When the user’s service ticket (TGS) is provided to the server for service access, the server opens the TGS and places the user’s TGT into LSASS for later use. The Application Server can now impersonate that user without limitation!“.

Translation: if a user not in the “Protected Users” group who also doesn’t have their account set with “Account is sensitive and cannot be delegated” requests a service ticket for a service on a server set with unconstrained delegation, the user’s ticket-granting-ticket (TGT) is stuffed into the service ticket that’s presented to the server. The server can extract the user’s TGT and cache it in memory for later reuse. I.e. the server can pretend to be that user to any resource on the domain.

This is dangerous for a number of reasons. One scenario that my workmates and I covered at DerbyCon this year is highlighted in our presentation.

Traditional Constrained Delegation

Obviously unconstrained delegation can be quite dangerous in the hands of a careless admin. Microsoft realized this early on and released ‘constrained’ delegation with Windows 2003. This included a set of Kerberos protocol extensions called S4U2Self and S4U2Proxy. I covered this process in depth in the S4U2Pwnage post and covered some new Rubeus weaponizations against constrained delegation in the s4u section of the From Kekeo to Rubeus post.

Operationally, without getting into the implementation details of S4U2Self/S4U2Proxy, any accounts (user or computer) that have service principal names (SPNs) set in their msDS-AllowedToDelegateTo property can pretend to be any user in the domain (they can “delegate”) to those specific SPNs. Additionally, Alberto Solino discovered that service name (sname) is not protected in the KRB-CRED file, only the server name is. This means that any service name can be substituted and we’re not restricted just to the specified SPN!

So while delegation has been “constrained” to specific targets, this is still dangerous. If you could modify the msDS-AllowedToDelegateTo contents for an account you control to include, say, ldap/DC.domain.com, then that account could DCSync the current domain! Luckily for us, Microsoft anticipated this attack. You need a right called SeEnableDelegationPrivilege on a domain controller to modify any of the previously described delegation settings. By default just elevated accounts like Domain/Enterprise admins will have this right on DCs, which is actually one of the main motivations for our next type of delegation. I talked more about this right in the “The Most Dangerous User Right You (Probably) Have Never Heard Of” post.

Resource-based Constrained Delegation

Windows Server 2012 implemented a new type of delegation, resource-based constrained delegation, in response to some of the downsides of traditional constrained delegation. Specifically, resource-based constrained delegation allows for delegation settings to be configured on the target service/resource instead of on the “front-end” account (i.e. the account configured with msDS-AllowedToDelegateTo settings in the traditional constrained delegation example.) This Microsoft document contains some excellent resources on this topic:

Resource-based constrained delegation is implemented with a security descriptor on the target resource, instead of a list of SPNs on the “frontend” account that the frontend account is allowed to delegate to. This security descriptor is stored as a series of binary bytes in the msDS-AllowedToActOnBehalfOfOtherIdentity property on a target computer object. This field is supported on Windows 8.1+ and Windows Server 2012+ computer objects assuming there is at least one Server 2012 domain controller in the environment. Of note, domain admin/equivalent rights are not needed to modify this field, as opposed to previous forms of delegation. The only right needed is the ability to edit this property on a computer object in Active Directory, so rights like GenericAll/GenericWrite/WriteDacl/etc. against the target computer object all apply here.

In order to execute this, a user needs to be able to execute the S4U2Self process (the TRUSTED_TO_AUTH_FOR_DELEGATION UserAccountControl setting, bit 16777216). The user executes the S4U2Self process to a special forwardable service ticket to itself on behalf of a particular user. The user then executes the rest of the S4U2Proxy process as they would with traditional constrained delegation (with one small exception, described below). The DC checks if the user is allowed to delegate to the target system based on the msDS-AllowedToActOnBehalfOfOtherIdentity security descriptor, allowing the process to continue if the requesting user is in the DACL.

Rubeus Additions

In order to properly abuse resource-based constrained delegation, Elad realized that one modification to the process was needed, and submitted an awesome pull request to Rubeus (that’s now merged to master.) Specifically, in the preauthentication data, the PA-PAC-OPTIONS structure needs to be present with the resource-based constrained delegation bit set. Thanks to Elad’s commit, Rubeus can now effectively abuse any RBCD configurations with its s4u command!

A Computer Object Takeover Primitive

Astute readers might have noticed two specific sentences in the resource-based constrained delegation explanation section:

Of note, domain admin/equivalent rights to modified this field are not needed, as opposed to previous forms of delegation. The only right needed is the ability to edit this property on a computer object in Active Directory, so rights like GenericAll/GenericWrite/WriteDacl/etc. against the target computer object all apply here.

This means that, assuming we control an account with S4U2Self enabled, and another account that had edit rights over a computer object we want to target, we can modify the target computer object’s msDS-AllowedToActOnBehalfOfOtherIdentity property to include the S4U2Self account as the principal and execute the Rubeus s4u process to gain access to any Kerberos supporting service on the system! We finally have a (somewhat limited, but still useful) ACL-based computer takeover primitive!

For a scenario, let’s say that the domain user TESTLAB\constraineduser has S4U2Self enabled, and the TESTLAB\attacker user has generic write access over the TESTLAB\PRIMARY$ domain controller object.

Note: the gist containing all these commands is here.

First let’s confirm everything I stated in the scenario above:

To execute this attack, let’s first use TESTLAB\attacker to modify the TESTLAB\PRIMARY$ computer object’s msDS-AllowedToActOnBehalfOfOtherIdentity security descriptor to allow the TESTLAB\constraineduser user delegation rights:

Then let’s use Rubeus with the compromised hash of the TESTLAB\constraineduser account context to execute s4u, requesting a ticket for the cifs service on PRIMARY. Note that we could use any of the service name combinations described by Sean Metcalf (see the “Service to Silver Ticket Reference” here.)

After we finish our business, we can reset the msDS-AllowedToActOnBehalfOfOtherIdentity field on the TESTLAB\PRIMARY computer object with:

Success \m/ ! Reminder that the gist containing all these commands is here. Also, a few times I had to had to execute the s4u process twice (when combined with /ptt).

Wrapup

All forms of delegation are potentially dangerous if not configured correctly:

Unconstrained Delegation – compromise of a server with unconstrained delegation can result in domain elevation.

(Traditional) Constrained Delegation – introduces attack paths from any user/computer account to any server configured in msDS-AllowedToDelegateTo property on the account.

Resource-based Constrained Delegation – in some situations introduces an ACL-based computer object takeover primitive.

Thanks again to Elad Shamir for the idea, awesome back and forth, and a killer Rubeus pull request to enable this new attack primitive!

Also published on Medium.