unconstrained kerberos delegation

Kerberos is a computer network security protocol that authenticates service requests between two or more trusted hosts across an untrusted network, like the internet. It uses secret-key cryptography and a trusted third party for authenticating client-server applications and verifying users’ identities.

<>

WHAT IS KERBEROS DELEGATION?

Kerberos Delegation is a feature that allows an application to impersonate a user. For example, you have a Web Application that connects to a SQL database. Kerberos Delegation can be configured on the application to connect to the database as the accessing user.

WHAT IS UNCONSTRAINED DELEGATION?

Unconstrained Delegation (introduced with Server 2000) means that the Web Application can impersonate a user against ANY service within the domain. This could include the domain controllers as domain admins.

WHAT IS CONSTRAINED DELEGATION

Constrained Delegation (introduced with Server 2003) means that the Web Application can only impersonate a user against SPECIFIC services within the domain (i.e. only the MSSQL database).

WHAT IS RESOURCE-BASED CONSTRAINED DELEGATION

Resource-based Constrained Delegation (introduced with Server 2012) would be set on the SQL Server to ONLY allow delegation from the Web Application (preventing a fake web app being setup and impersonating users to access the database).

HOW DO WE KILL IT?

In a production environment, you want to remove the unconstrained delegation but being operation focused, you don’t want to impact service. All of the following work will be carried out within Azure Log Analytics/Azure Sentinel as this is my correlation point.

To start with, we are going to look for Event ID 4769. This Event ID is generated every time a Kereberos Service ticket is requested, whether successful or not.

SecurityEvent
| where EventID == 4769
| parse EventData with * '"TransmittedServices">' TransmittedServices "<" * 
| parse EventData with * '"ServiceName">' ServiceName "<" *
| project TransmittedServices, ServiceName
//| where TransmittedServices != "-"
| summarize count() by TransmittedServices, ServiceName
 

This query gives you a count of the number of delegation requests per service, along with which service they were delegating to. The ‘TransmittedServices’ column relates to the account doing the delegation. This should be your web server using the example above. Or if you use Azure AD App Proxy with Constrained Delegation, you will see these listed here. The ‘TransmittedServices’ in the XML contents of the event log translates to the ‘Transited Services’ attribute when you view in Event Viewer. The ServiceName column relates to the service that is being contacted. This should be your SQL Server Service using the example of the web app to SQL.

If you’ve got a whole heap of SPNs, for example the SQL Server Account is used on 50 different SQL Servers as a first port of call you might wish to just constrain to all the SQL SPN’s attached to the account.

<> ___

To confirm/find computers (windows servers) on a domain that have unrestricted kerberos delegation property set:

In PowerShell:

import-module ActiveDirectory
Get-ADComputer -Filter {TrustedForDelegation -eq $true -and primarygroupid -eq 515} -Properties trustedfordelegation,serviceprincipalname,description

If you want to know more on this and why it poses a security risk, take a look at:

Kerberos Delegation Attack How to Abuse Machine Account to Gain Local Admin Privilege (https://www.youtube.com/watch?v=YH9MIPubZfg)

Microsoft Docs (https://docs.microsoft.com/en-us/defender-for-identity/cas-isp-unconstrained-kerberos)

https://docs.microsoft.com/en-us/windows/security/threat-protection/auditing/event-4769

https://blogs.technet.microsoft.com/389thoughts/2017/04/18/get-rid-of-accounts-that-use-kerberos-unconstrained-delegation/

Defender Query

SecurityEvent | where EventID == “4738” | parse EventData with * ‘NewUacValue”>’ NewUacValue ‘</Data>’ * | parse EventData with * ‘TargetUserName”>’ UserName ‘</Data>’ * | parse EventData with * ‘SubjectUserName”>’ Actor ‘</Data>’ * | where NewUacValue == “0x2010” or NewUacValue == “0x2080” | project TimeGenerated, Activity, UserName, Actor