This post will demonstrate how to perform a “Kerberoasting” attack in an Active Directory (AD) environment. In a previous post, I detailed how to create an AD lab in AWS and how to configure a user with a Service Principal Name (SPN) that will allow for the Kerberoasting attack.
Kerberoasting is an attack against an Active Directory environment that has users configured with SPNs. The attack was discovered/publicized by Tim Medin. ADSecurity and harmj0y have detailed posts describing what a Kerberoasting attack is, and how it is performed. I highly recommend reading their write-ups over my post!
Kerberoasting attacks the kerberos authentication process. When an AD user is configured with an SPN, they are a “service” account in the domain. This is done so that services on systems can run under the context of the service account, and to then allow for other AD users to authenticate to the service account using kerberos. When an AD user wants to authenticate to the service account, they request a Ticket Granting Service (TGS) ticket to the Domain Controller (DC). A valid TGS is required to authenticate and access the desired service. If the AD user is authenticated to the domain, the DC responds with a TGS ticket for the user to access the service. The TGS ticket is encrypted with the NTLM hash of the service account’s password.
The last bit is what will be attacked in a kerberoasting attack. The goal of the attack is to acquire the password for a service account. An attacker can do this by requesting a TGS ticket for the service (as an authenticated user in the domain), and then attempting to decrypt the TGS ticket by trying NTLM hashes of various passwords. When the correct NTLM hash is used to decrypt the ticket, a valid kerberos ticket will be decrypted and the attacker will know the password of the service account. Password cracking tools such as Hashcat and John the Ripper support cracking kerberos TGS tickets.
Performing the Attack – Requesting the Ticket
During this post I will be using Covenant C2, which I described how to setup in a previous post. This attack is not unique to Covenant, and can be performed over your preferred C2 framework or directly from a box you have RDP or hands-on-keyboard access to.
I will demonstrate three different methods that can be used to request the TGS ticket through Covenant.
Powershell and PowerView
The first method is to use a PowerShell tool called PowerView. PowerView is from the PowerSploit suite of tools that allows you to enumerate and attack AD. I use the dev branch of PowerView in this post.
To start, you will want a Covenant grunt communicating back to your C2 server. In my environment, I ran the PowerShell launcher on the wkst01 system as the unprivileged user regularuser.
Access the grunt tab in Covenant, then import the PowerView.ps1 with the command “PowerShellImport.”
After PowerView.ps1 has been imported throught he grunt, you can use “powershell” to execute PowerView’s cmdlets. This can be done with “Invoke-Kerberoast”, which more-or-less automates the manual command shown below.
Get-DomainUser -SPN * | Get-DomainSPNTicket -Outputformat hashcat | select -exp hash
This command does the following:
- Searches for all AD users with a Service Principal Name
- Requests a TGS ticket for each discovered Service Principal Name
- Specifies that the format of the ticket displayed to you will be one that the tool hashcat can use to crack
- Selects and displays only the “hash” of the TGS ticket
After the command is run, you will see output similar to the following.
This command will request a ticket for all service accounts in your current domain. In my lab, the only accounts with an SPN are krbtgt and serviceaccount.
Covenant has builtin methods for kerberoasting as well. Typing in “kerber” in the grunt command line will show some of those options.
The tool Rubeus is “builtin”, so to speak. Rubeus is a tool created with C# that allows you to perform various kerberos attacks, including kerberoasting. This is simple to use within Covenant with the following command. Assuming I am understanding the Covenant documentation correctly, Covenant will have your grunt download the C# binary of Rubeus, and then reflectively load it into memory to execute Rubeus’s functionality.
This will provide the hashes for the TGS tickets for the service accounts in the domain in the hashcat format.
Rubeus has several options you can pass related to opsec concerns. When you request a ticket in the hashcat format, at the beginning of each hash you should see something like “$krb5tgs$23$.” That number “$23$” means it is encrypted with the RC4 cipher. This is a weaker encryption cipher that allows for faster cracking times. Other types you’ll likely see are $18$ and $17$, which means the TGS ticket is encrypted with the AES cipher. This is a much stronger cipher than RC4 and takes much longer to crack. TGS tickets encrypted with AES can still be cracked using hashcat, but they will take much more time than the RC4 encrypted tickets.
The PowerView command shown previous will attempt to request an RC4 encrypted TGS ticket for every service account it discovers. This can be unusual in an environment, as most TGS tickets will be encrypted using AES. Defenders can then create alerts for requests made for TGS tickets using RC4 encryption and then investigate for attacker activity. Rubeus allows you to specify to request AES tickets if the service account supports it, and only request the RC4 encrypted ticket if the service only supports RC4 encrypted tickets. This helps your activity blend in with what would be “normal” in an environment.
Covenant also has a builtin command for kerberoast. The help dialogue for the command can be seen here.
The username has to be specified, so you will need to enumerate the users with SPNs before using the kerberoast command. In my lab, the only user is the “serviceaccount” user, so the kerberoast command looked like this.
kerberoast serviceaccount hashcat
Decrypting the TGS Ticket
After the TGS ticket has been requested, you will want to copy and paste the hash into a text file. You can then use either john or hashcat to decrypt it. For this, I used hashcat in a virtual box VM of Kali (for reasons I do not fully understand, hashcat works for me in a virtual box VM, but not a VMware VM. I guess VMware’s drivers don’t play well with hashcat or something).
The command to decrypt the ticket is shown below. The “-m 13100” specifies to decrypt a type 23/RC4 encrypted kerberos TGS ticket. “service-account-tgs-ticket” is the file containing the hash. “password-list” is a dictionary file that will be used by hashcat to guess the passwords. “–force” tells hashcat to ignore that there is no GPU in the VM and use the CPU to crack.
hashcat -m 13100 service-account-tgs-ticket password-list --force
Because this is in a lab environment that I set up, I already knew the serviceaccount user’s password, and included it in my wordlist. I recommend reading this post by MWR Labs on creating wordlists and rules for password cracking for real world attacks.
Using the Cracked Password
After the ticket has been cracked, you now have the password for the service account. Service accounts are often configured with high privileges in an AD environment (and often with too high of privileges!), which is what makes service accounts valuable targets.
Back in my Covenant grunt, I used PowerView’s “Find-LocalAdminAccess” functionality to see if the serviceaccount user was a local administrator on any systems in the environment. I did this by creating a credential object and passing it to Find-LocalAdminAccess with the -Credential option.
This returned that the serviceaccount user is a local administrator on the srv01.murph.coop system. I can also demonstrate this by using “MakeToken” to create a token for the serviceaccount user, and then getting a directory listing of the C$ share on srv01.
Lateral Movement with Cracked Credentials
I could continue accessing the srv01 from my grunt on wkst01, but right now I want to demonstrate how to move laterally from wkts01 to srv01 within Covenant.
Click on the “Task” tab at the top of the grunt page, and then select “WMIGrunt” from the task drop down. This will launch a new grunt process on a system using WMI. In order to run WMI commands on a remote system, you would need to be a local administrator on that system. The regularuser account the wkst01 grunt is running as would not be able to execute WMI on srv01, but the serviceaccount user should be able to. The WMIGrunt task allows you to specify the credentials to be used in the task. Enter in the serviceaccount user’s credentials. For the “Launcher”, copy and paste in the PowerShell command generated from the “PowerShell” launcher in Covenant. You could also provide a command to execute whatever other launcher of your choosing.
Click the “Task” button for the grunt to execute this task. You should see if the WMIGrunt task executed successfully in either the grunt “>_Interact” or “Taskings” tabs. If execution was successful, you should see a new grunt checked into Covenant.
You can now interact with the grunt on srv01 as the serviceaccount user. Note that the “Integrity” of the grunt is “High” on the srv01 grunt compared to “Medium” on wkst01. To put it simply based on my uneducated understanding, medium integrity means your process is running with regular user privileges, and high integrity means your process is running with administrative privileges. Note that a process started by an administrative user can still run in medium integrity. If you are running as an administrative user in a medium integrity process, and want to execute tasks requiring administrator privileges, you will need to spawn a new process with the higher integrity. The cobalt strike blog discusses this here.
Since I am running as an administrator and like to live dangerously, I run mimikatz‘s logonpasswords to dump credential information from the srv01 system.
Defending Against Kerberoast
Three “easy” (nothing is actually easy in the real world) ways to defend against kerberoast attacks are:
- Ensure accounts with SPNs actually require them
- All accounts with SPNs should have long, complex passwords that are not reused across accounts
- Accounts with SPNs should not be provided unnecessary privileges in the environment
Often in environments you’ll see accounts with SPNs that do not actually need the SPN, such as the default Administrator account for the domain. This is very bad! If an account does not need to run a service and have users authenticate to it using kerberos, it shouldn’t have an SPN.
All accounts with SPNs should also have long passwords, preferably random ones only accessible with password managers. Service accounts shouldn’t have to re authenticate by entering in their password manually often, so the account should be set up with a randomly generated password and not one your administrators use repeatedly across the environment. If the password can’t be cracked, then the kerberoast attack fails.
Often you’ll see service accounts configured as local administrators on systems or even as members in groups like server admins or domain admin (uh-oh). This is often unnecessary for the service account to function. The privileges of service accounts should be regularly audited. If the service account has no real privileges in the environment, cracking its password won’t provide an attacker much.
Other ways to defend against the attack are:
- Disable RC4 encryption on TGS tickets (makes cracking take longer, but can cause issues with legacy services/systems)***
- Create honeypot users with SPNs (if a TGS ticket is request for the honeypot SPN, you know you have an attacker up to no good)
- Detection and alerting rules for when TGS tickets are requested with RC4 encryption instead of AES encryption. This will require some fine tuning to prevent false positive alerts in case there are legitimate uses of RC4 encrypted tickets in your environment. I believe Microsoft’s ATA supports this detection
***UPDATE: Turns out, disabling RC4 completely is much easier said than done, and potentially not entirely possible. Harmj0y’s Kerberoasting Revisited post discusses how even when AES is the only supported encryption type, it is still possible to receive an RC4 encrypted TGS ticket. Rubeus supports requesting RC4 encrypted tickets when only AES is supported with the following command:
Rubeus.exe kerberoast /tgtdeleg