Abusing Unconstrained Delegation via Service Principal Name hijacking

Authored by Andrew Petro

Recently I was working on an Internal Penetration test for a client in the financial services industry and came across an interesting situation I thought was worth writing about and sharing with the rest of the cybersecurity industry. This scenario requires at least a basic understanding of Kerberos, specifically Service Principal Names (SPN) and Delegation. If you are unfamiliar with those terms, I would suggest doing a bit of background reading before jumping in. Here are a few links to some resources to get you started:

https://learn.microsoft.com/en-us/windows/win32/ad/name-formats-for-unique-spns

https://m365internals.com/2021/10/27/revisiting-unconstrained-delegation

For security purposes, all screenshots in this article were from a test environment re-creating the situation in the client environment.

Scenario

During enumeration of my client’s environment, I discovered several user accounts configured with unconstrained delegation. When conducting penetration tests, abusing delegation is one of my favorite attacks to conduct. Not only is it usually a quick and easy way to elevate privileges, but I often find that many clients do not fully understand the risks associated with delegation and perhaps more importantly, they don’t know how to detect it. For this scenario we’ll be focusing on unconstrained delegation, a privilege I see given out far too often and, at least so far, has never actually been needed. Simply put, if an account has been granted unconstrained delegation privilege, it can impersonate any user to any Kerberos enabled service. That means that a service account running SQL server that has been granted unconstrained delegation privilege can RDP into a domain controller as an Administrator. There are a few ways to identify accounts with unconstrained delegation configured. In this case I used findDelegation.py from Impacket.

Abusing unconstrained delegation was not a new concept for me, however, I generally find it easier to abuse (and less disruptive) when computer accounts are assigned the privilege. This is because computer accounts have rights to edit their own attributes in Active Directory, whereas user accounts do not (unless of course it’s a privileged user account). As an attacker, this gives us the flexibility to modify service principal names (SPN) on the computer account which in turn, allows us to dictate not only which host the attack takes place on, but also the service. With user accounts, we don’t have that flexibility which means our options for exploitation are going to be limited.

I decided to dig in deeper anyway and noticed that this account had well over 100 SPN’s configured. This can be seen using addspn.py tool from krbrelayx.py or setspn on Windows.

This was a bit unusual in my experience, so I continued to investigate, looking into the SPN entries I found that more than half of the DNS names no longer resolved.

Kerberos requires use of DNS names to function correctly. The fact that the hostnames in the configured SPN’s no longer resolve indicates that these were stale entries that never got removed when a respective application or system was retired. While seemingly insignificant, initially, it gave me back the flexibility of being able to pick the host on which to conduct the attack. This time instead of adding an SPN to my account, all I needed to do was recreate a DNS record for one of the stale SPN entries. This allowed me to hijack the SPN and direct authentication to my attacker machine and abuse unconstrained delegation to elevate my privileges.

The only thing that was left was to trigger authentication and start stealing Kerberos tickets.

Lessons Learned

There are several lessons that can be learned from this scenario. While some of the specifics may be a bit unusual, the lessons learned are applicable to almost every environment.

Principle of Least Privilege – Anyone who works in the cybersecurity industry should be familiar with this term. Simply put, it means that accounts should only be granted the exact privilege they need to be able to conduct their respective function, nothing more. It’s a term that everyone knows but is rarely followed. We see two violations of this, in this scenario that were critical to the attack’s success.

1. Unconstrained Delegation granted to a service account that really didn’t need it. I learned quick in this industry never to say never, therefore there are only rare circumstances in which unconstrained delegation may be required. In 99.9% of situations where this privilege is granted, those environments are simply making it easier for attackers to elevate privileges and steal information.

2. Users had ability to create DNS records when they really didn’t need it. DNS is a powerful protocol that opens the door to a number of attacks. Here I used it to abuse Kerberos, but we’ve also seen it abused to conduct man-in-the-middle attacks and disable controls like multi-factor authentication. By default, Active Directory allows any valid account to create DNS records, and this is a misconfiguration that I feel gets commonly overlooked.

Logging, Monitoring and Alerting – As I mentioned earlier, I rarely come across a client that can detect delegation abuse. The main reason for this is that while logging tools pay close attention to the username or account performing the actions, not enough attention is placed on how that user authenticated to the system. When it comes to incident response, one of the most common steps I always hear from clients is “We would reset the users password”. The problem with this is that attacks that abuse delegation can circumvent password resets. Consider the scenario where “service_account” is granted unconstrained delegation and being used to impersonate “domain_admin” on a critical server. Logging tools see the actions performed by “domain_admin” and so responders reset “domain_admin” password. However, access to the server was granted from a Kerberos ticket which  still remains valid after the password change. Worse than that, the ticket was requested using “service_account” password. So even if the Kerberos ticket is rendered invalid, we still have all the information we need to obtain a new ticket and restart the attack again. That’s why it is important to understand how the user authenticates so you can trace back the activity to the true malicious account.

Kerberos Security Features – There are some built-in security features that can help make this abuse more challenging and less beneficial. Active Directory provides a built-in group called “protected users”. Members of this group cannot be impersonated or delegated, adding privileged users to this group can severely limit the ability for an attacker to elevate privileges this way. Another useful security feature is to disable outdated encryption protocols. Windows systems are vulnerable to what’s known as pass-the-hash attack, this essentially means that a NT hashed version of a password is just as good as having the password itself. Kerberos is the exception, as the NT hash only works when the deprecated RC4 algorithm is enabled. That means that if you configure your domain to require AES encryption and disable the outdated RC4 algorithm, you can eliminate the ability for users to utilize password hashes to execute delegation-based attacks, rather they have to obtain the cleartext password to proceed. If you combine this with strong and random passwords for service accounts, you can make attacks like unconstrained delegation far too costly and time consuming to conduct. Combine that with protected users, and the attacker may go through all that trouble and still may not be able to elevate.

  • 704-816-8470

Javier is a principal within the Cybersecurity Services Group at CLA. Prior to joining CLA, Javier spent ten years supporting the Department of Defense as well as a financial services company in the fields of insider threat, incident response, analytics, and systems engineering.

Comments are closed.