🐶🐶🐶 Credential theft made easy with Kerberos delegation

Yes it takes just 2 lines of PowerShell to impersonate whoever you want... A small preamble: things discussed here are not hacking techniques, nor innovative ways to impersonate a user. These are intended behaviors, and they all have been around for a very long time. Why talk about it now? Because as a part of my job, I deliver security assessments for Premier customers. And when it comes to Kerberos delegations risks, it is rare to have the appropriate attention. "Kerberos S4U2Proxy is a risk" sounds probably too geeky to be worried about 🤓.

Si tu parles français, ce billet est inspiré de ce celui-ci: Kerberos, déléguerais-tu vraiment tes credentials à un chien ?

What is Kerberos delegation?

It is important to note that it has nothing to do with the right-click Delegate in the Users and Computers MMC. It has nothing to do with permissions on objects. In fact, it is way more powerful than that. Kerberos delegation is giving an account the permission to impersonate another account. Well, just reading this should help to foreseen how we can abuse it.

A necessary evil

Well it is not really evil, but we easily see what could be used for bad things. So how did all that stuff started? Kerberos delegation is actually solving an ancestral problem with multi-tiers applications. When you have a front-end server, like a web server, using back-end services like a database, or a SQL reporting, the application running on the front-end is accessing those back-end services on behalf a service account. It isn't fantastic from an accountability perspective because every access is always using the service account.  And from a permission perspective you have to give permissions to the service account and not the end-user. If we want to provide the context of the user to the back-end services, we'll need to request for the user's credentials again. This is the "double-hop" effect. And this can cause an ugly pop-up in which a disgruntle user will have to type its password again. But if we allow the front-end server (or rather its service account) to do Kerberos delegation, then the service will ask for tickets on behalf the user and the context of the user will be provided end-to-end.

3 ways to do Kerberos delegation

In the following example, I am looking at the Delegation tab of the computer account of VSRV01. Note that the delegation tab is not present on a user account unless it has a servicePrincipalName attribute defined (no SPN = no delegation).

  1. Windows 2000 Server delegation aka Old school delegation
  2. Then there is the Windows Server 2003 using Kerberos end-to-end
  3. And the Windows Server 2003 with protocol transition

Back in the Windows 2000 Server days, we just had the Trust this computer for any service (Kerberos only). From a risk perspective, it means that if Norma the attacker 👧 controls VSRV01, she can impersonate any users connected to the service running under local-system. So for if VSRV01 is running a web-service in local system, and Adam 👨 is browsing it, Norma can use his identity to access any Kerberos service in the domain (like his mailbox, his personal data...), without even Adam's knowledge. Pretty scary eh? We should do something about it...

Then arrive the two other options. They aims at correcting the risk mentioned above. When we configure it, we are asked to specify what service the account can impersonate the user to. This is called constrained delegation. So with Trust this computer for delegation to specified services only if VSRV01 can just do delegation to the SQL server VSQL01, then Norma 👧 can just impersonate Adam to VSQLo1. No more access to his emails... Less fun. Still a risk though.

The last option is the more interesting one: Use any authentication protocol. So why do we even have this options? It is to fix a truism. Kerberos delegation works only when we do Kerberos. So what if Adam authenticates against the VSRV01 using another protocol than Kerberos? Like NTLM 😱 or any other ways like a web form with some custom authentication provider. No Kerberos = No delegation. So the protocol transition kicks in. If the application has the privileges Act as part of the operating system as well as Impersonate a client after and the account set with the appropriate Kerberos delegation then the application will transform the user's authentication into Kerberos. In other words, it gives to the application the permission to impersonate any users. And that is fun.

Practical example

Still not convinced of the risks, or it is still not clear why you should care? Let's put it in practice. Here is my current delegation settings on VSRV01:

I connect to my server VSRV01 with an local account member of the local administrators group. And I try to access the C$ administrative share of VFILE01:

So I open a PowerShell console in the local system context (why? because the delegation permissions are given to the computer account VSRV01). Let's use PSEXEC:

 PSEXEC -i -s -d PowerShell

Then I just decide to change my identity to... Hum. Let's pick the domain admin account. For my lab it is piaudonnmsdn@vereantex.com:

 $u = New-Object System.Security.Principal.WindowsIdentity("piaudonnmsdn@verenatex.com")
$u.Impersonate()

And let's try again to access VFILE01 C$ share:

What does it look like on the cable? We see the TGT request (no password required for protocol transition) followed by a service ticket request for CIFS/VFILE01:

You can see the flag S4U2Proxy flag. It means that we are using that protocol transition here.

I chosed to impersonate the domain admin. I could have picked up any other account. If I try to access VSQL01 SQL service, I could do it with the admin of the service or even the service account. The PSEXEC here is just to switch to the machine's context. If the delegation was set on a service account, I could retrieve the credential of the service account with any credential theft tool and then use it to request the ticket.

OMG! We're all gonna die! We need to disable delegation!

Hehe, no .

The delegation and even the protocol transition are great features! They even help to strengthen application's security by providing accountability for each access and providing the user's context end-to-end. So we need them! But we need to be careful. Rigor is the way to go. Here is a to-do list when you are facing an account with delegation.

  1. Make sure than only domain admins can configure delegation. It is a privilege on domain controller. You can control it with a group policy linked to the Domain Controllers OU, it is called Enable computer and user accounts to be trusted for delegation:
  2. Make sure that all accounts allowed for delegation are actually requiring the settings. Configuring Kerberos delegation can be tricky and we rarely get it right in the first place (unless your initials are AM 🤐). So it wouldn't be surprising that you have some bribes of delegations set here and there. If Kerberos delegation is not expected. It should not be configured.
  3. If you need delegation, use the constrained delegation! It's been around for a while now. So no more excuses for the old school delegation to be around... Well unless there is a supportability issue for your application... Then you have an application to upgrade 😜
  4. Make sure that the accounts allowed for protocol transition are actually requiring the settings! Like for point 2, it is not rare to see multiples attempts to set it right. So maybe you have it set but you don't need it. It's time to RTFM of the application!
  5. This one is not specific for Kerberos delegation risk mitigation, it's general guidance, some of us would even say common sense. Make sure you lock down the local administrators groups of your servers for which is account is allowed for delegation. And if you have delegation enabled on a service account, well all the local administrators of the machines where is account is used. But really, you should already be doing this.
  6. Make sure that accounts which are not using delegation cannot be delegated. It's the case of your admins accounts. They do not access LOB apps. Therefore you can prevent them from being delegated. It is the option called: The account is sensitive and cannot be delegated.

    Well this or any other way to delegate Kerberos delegation like with Windows Server 2012 R2 Authentication Policies and Silos. If I had this checked in my practical example, the local admin of VSRV01 couldn't have impersonate the account. There is actually one situation where AD admin accounts are using Kerberos delegation. It is when you are moving a user from one domain to another within the same forest using MOVETREE of ADMT. But you are not doing this everyday. So you can easily get around this by unchecking the option, doing the move and re-checking the option.

For the finicky Kerberos aficionados, I know, I completely skipped (purposely?) the Resource Based Delegation feature of Windows Server 2012. If you want to blog about it, and explain how that affect things, let me know I link you up here!

Alright, I feel better now. How do I get the list of accounts to check?

There are tons of articles and posts giving examples of query and stuff. I will let you find them and give you a quick and easy way n the mean time:

  1. List all machine accounts enabled for old school delegation:

     Get-ADObject -LDAPFilter:"(&(objectCategory=computer)(objectClass=computer)(userAccountControl:1.2.840.113556.1.4.803:=524288))"
    

    Note that this also returns the domain controllers. This is an expected configuration and does not need to be corrected.

  2. List all user accounts enabled for old school delegation:

     Get-ADObject -LDAPFilter:"(&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=524288))"
    
  3. List all machine accounts enabled for protocol transition:

     Get-ADObject -LDAPFilter:"(&(objectCategory=computer)(objectClass=computer)(userAccountControl:1.2.840.113556.1.4.803:=16777216))"
    
  4. List all user accounts enabled for protocol transition:

     Get-ADObject -LDAPFilter:"(&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=16777216))"
    

That's it for now. Questions? Comments? Too many emoticons?