The Penetration Testing with Kali Linux course offered by Offensive Security (PWK) covers a lot of ground important to every penetration tester, but it can’t cover everything. Some topics are only touched upon briefly in the textbook and your knowledge of them isn’t thoroughly tested in the lab. The intent of this series is to expand upon and fill in some gaps left by the PWK course, so that you’re confident in your ability to handle Windows networks. This series covers techniques that I’ve learned from the best researchers in the field, done in a step-by-step fashion.
All of the topics in this series will have some things in common.
Shields Up - Wherever possible, the payloads, post-exploitation steps, techniques and procedures demonstrated will happen on Windows machines with some level of defenses active. Normal endpoint defenses like AV and AMSI will be present. UAC will be active and set to default. PowerShell logging will be active. PowerShell execution policy will be default for the OS. The idea is to replicate a reasonable default defensive posture.
Low privileges by default - Where applicable, I’m not going to begin conveniently as local Administrator. Too many Active Directory post exploitation tutorials begin with “Once on the machine, just
magically privesc to local admin, and then…”. This is unhelpful. We’re going to explore what to do when high privileges don’t just fall into your lap.
Narrow tool focus - These articles will focus on using a small set of tools. Finding good projects that are maintained and responsive to bug reports is difficult in this space. The gems that get continued support are worth investing time into.
These posts were written near the beginning of 2019 and while mostly still relevant, might not use the most up-to-date versions of software or techniques. I’m leaving them up because they continue to get views.
“Kerberoasting” is abusing the underlying authentication mechanism of Active Directory (AD) to obtain the password hash of a domain user account. All that is required is the domain account be referenced by a Service Principal Name (SPN).
The purpose of an SPN is to act as a “pointer” to domain resources consumed by users and computers alike. It encodes information about the resource and the host providing that resource to the network, and optionally an account under whose privileges that resource will execute.
Kerberoasting is effective when a user account, and not a computer account, is tied to an SPN. Generally, SPNs are bound to computer accounts, thus becoming ‘service accounts’. Computer accounts have long, sophisticated passwords by default. Human user accounts, not so much.
As I’ll describe below, user accounts with SPNs weaken the security of the AD because of their enhanced risk of offline password cracking attacks.
Active Directory is a complex subject. Fortunately, Sean Metcalf (@PyroTek3) has extensively documented the red and blue team concerns of AD at adsecurity.org. It’s an enormously useful resource, and you should definitely go there and read. However, I’ll briefly summarize what exactly is in play that makes kerberoasting work.
AD machinery and tickets⌗
The Domain Controller(DC) in an AD controls authentication of user and computer accounts through a system of “tickets.” Users on the domain receive a ticket when they successfully log into their workstations. This ticket is examined by the DC when it handles the authentication of the user for other services on the AD. When the DC determines that the user seeking access to a resource is authentic, it produces a different ticket, one that contains information specific to the resource. The first type of ticket is called a Ticket Granting Ticket (TGT) and the second a Ticket Granting Service ticket (TGS).
When the user TGT is authenticated by the DC, it encrypts the new TGS ticket with the password of the service account. The DC then sends it to the user. The user then sends the TGS ticket to the service host referenced by the SPN. The service host checks to see if it can decrypt the TGS ticket with the service account’s password. If it can, the ticket is examined for more information, and the user is authenticated to the service.
Let me walk you through a simplied example of this process. This omits some particulars about Kerberos interactions, but is sufficient to understand the communications involved.
So let’s say you have a webserver on your domain that hosts an internal site for Git repositories, like GitLab. It supports Kerberos authentication, so your admin set up a SPN for it. Assuming you’ve already logged into your workstation, the communication will look like this:
- You send your TGT (already in memory) along with some information about your request (for authentication to the webserver and its SPN) to your DC.
- The DC checks to see if the SPN exists in its database of domain resources. If it does, it consults its database for the password of the service account for that SPN. It creates a new message, encrypted with the service account’s password, containing some information that the service account will use to communicate with you. The DC then sends this bundle back to you. This is the TGS.
- With the TGS now in memory, your computer contacts the host the SPN points to, and sends it the TGS ticket. The service host can decrypt the TGS, which it then examines to confirm your identity.
- The service host sends a message back to you confirming its identity, along with info about how the two of you will communicate until your session expires.
- Assuming that you have the permissions to view the website, you will find youself both authenticated and granted access.
The purpose of all of this interchange is to centralize the authentication of accounts on the domain, not to enforce a permissions stack. Permissions are enforced across the domain with a system of objects and Access Control Lists (ACLs), which we will get very familiar with next post. In other words, successfully authenticating to the service host with a valid TGS does not confer rights to that service.
The process of communicating with the DC for these tickets is so germaine and expected that naturally, no special domain rights are required. Only a valid set of credentials are needed to operate on a domain. Since no special privileges are required, many TGS tickets can be acquired and potentially attacked for their passwords. However, TGS tickets encrypted with computer/machine account passwords are effectively uncrackable, since they are extremely long, random, and changed automatically on a schedule. For the purposes of kerberoasting, we’re only interested in SPNs that use domain user accounts.
SPNs and Service Accounts⌗
AD actions leveraging authentication include logging in, domain replication, and remote management. All of these actions use SPNs under the hood. Third party applications that explicitly integrate with AD will use SPNs to do so. In sum, if a resource needs Kerberos-backed authentication, it needs an SPN.
A domain administrator might create SPNs in two different ways. They could make a domain user account whose sole purpose is to control the given resource, and bind an SPN to it. This is common when installing enterprise software.
Alternatively, they could use an existing user account. This might be an account already associated with the resource like a manager or engineer. Situations where control over resources is segregated by business unit commonly delegate SPNs in this manner.
In practice these will have different consequences. Bespoke accounts are easier to monitor and are easier to apply the Principle of Least Privilege to. However, once created and functioning they will likely be ignored thereafter, and this means a breached password or hash might persist for a very long time unaddressed.
Elevating an existing user account with an SPN is the reverse situation. Poorer in regard to isolation, but more likely to be managed by password policies in the organization.
Anatomy of an SPN⌗
I’ve talked a whole lot about SPNs without showing one, so let’s fix that.
- Well-known service name. There doesn’t appear to be a canonical list, but the closest thing available is here, thanks to Sean Metcalf.
- NETBIOS name, FQDN, or IP address, with a port number if not the standard port associated with the service.
- Optional unique ‘servicename’, which is required if there is more than one potential service/port pairing on the same host with the same service account. This can be used to point to different ‘endpoints’ for the same service.
Here’s a sample of SPNs from the Domain Controller in my lab.
Dfsr-12F9A27C-BF97-4787-9364-D31B6C55EB04/0metaLabDC01.0metalab.private ldap/0metaLabDC01.0metalab.private/ForestDnsZones.0metalab.private ldap/0metaLabDC01.0metalab.private/DomainDnsZones.0metalab.private TERMSRV/0METALABDC01 TERMSRV/0metaLabDC01.0metalab.private DNS/0metaLabDC01.0metalab.private GC/0metaLabDC01.0metalab.private/0metalab.private RestrictedKrbHost/0metaLabDC01.0metalab.private RestrictedKrbHost/0METALABDC01 RPC/8e1b9a60-af61-4bcc-a80c-c51bf144b229._msdcs.0metalab.private HOST/0METALABDC01/0METALAB HOST/0metaLabDC01.0metalab.private/0METALAB HOST/0METALABDC01 HOST/0metaLabDC01.0metalab.private HOST/0metaLabDC01.0metalab.private/0metalab.private E3514235-4B06-11D1-AB04-00C04FC2DCD2/8e1b9a60-af61-4bcc-a80c-c51bf144b229/0metalab.private ldap/0METALABDC01/0METALAB ldap/8e1b9a60-af61-4bcc-a80c-c51bf144b229._msdcs.0metalab.private ldap/0metaLabDC01.0metalab.private/0METALAB ldap/0METALABDC01 ldap/0metaLabDC01.0metalab.private ldap/0metaLabDC01.0metalab.private/0metalab.private
As you can see, some of these are essentially aliases based on the hostname. We have FDQN and NetBIOS versions of many services, but internally they bind to the same service. You can see the LDAP endpoints your workstation uses to communicate with the DC for queries. There are Kerberos (KrbHost) endpoints used to get your TGT and TGS. You can also observe the use of the servicename alias in a couple of instances.
Enough theory, let’s look at kerberoasting in practice. Following on from the last post, you have a working PoshC2 Implant.
First, we need to query the AD for any SPNs. There are a couple of straightforward ways to do this.
- Independent psh script - This script is a great study to see what exactly is being queried on the domain to get the information we’re looking for. The script has some nice extra features as well, such as displaying the age of the password, and any approaching expiry. It does, by default, attempt to connect to the resource to see if it’s reachable and alive though, which may or may not be desirable. In the event it isn’t, pass the
-stealthargument and these extra checks will be skipped.
- Built-ins - PoshC2 ships with PowerView, which includes several cmdlets to deal with SPNs and kerberoasting.
Get-DomainUser -SPNwill search for and print all relevant service accounts.
To get your hash, use
Get-DomainSPNTicket. This function is part of PowerView as well, and a typical use looks like this:
Get-DomainSPNTicket -SPN <full SPN> -OutputFormat hashcat | fl
This will prettyprint the hash into a text blob ready to be sent to a hashcat rig.
Alternatively, you may chain the output from
Get-DomainUser -SPN directly into
Get-DomainSPNTicket by using the ‘|’ character.
You can test the before-and-after of a successful TGS request with the
klist Windows built-in command. The SPN will be listed next to the
I’m not going to cover setting up a Hashcat rig and attacking your hash, since there’s many resources online already about this task, as well has how to conduct dictionary and bruteforce attacks. There are also bespoke projects for this, like tgscrack from tifkin_ that can you use. There are a few resources online for password lists, such as the SecLists project on Github, and infocon.
At the end, you should have a plaintext password. Hopefully. If your client is using strong passwords that resist your cracking attempts, even better!
So, what do you do with the password? I’ll cover that in the next article all about lateral movement!
Does this always work?
- Yes and no. To crack hashes without a truly impressive GPU array, the domain needs to be using the RC4 encryption type on its TGS tickets. Otherwise, it will be encrypted using AES, and AES represents a much much higher bar for cracking than RC4 does. The older the AD is, the greater the chance that some legacy requirement will make RC4 mandatory on the domain. Also bear in mind that if a domain is mostly using AES tickets, and you generate a RC4 ticket, that can be picked up on by logging and monitoring devices.
So now that you can execute kerberoasts, you have one more tool available to you to move within a domain. Next time, we’ll cover fully enumerating the AD and discovering opportunities to move laterally.
I couldn’t have written this series without the tireless work and research given freely by those in the infosec community. I’ve tried to cite them each time I link an article, but here in no particular order:
Last but certainly not least, is @benpturner for the PoshC2 framework used extensively throughout this series. Accepting questions, bug reports, and nagging throughout, he was always ready to help.
And a second shout-out to @harmj0y and others for the PowerView project. While the leading edge of offensive tooling is moving on to C#, PowerView still provides a stout resource for investigating Active Directory.
_edited first paragraph on 4/16 to provide a simpler first description of kerberoasting.