Lab: Kerberoasting¶
In one sentence
A full Kerberoasting walkthrough in the home lab — the principle, setting up a vulnerable SPN account, roasting and cracking from Kali, and detecting it in Splunk via Windows event 4769.
Study side vs. detection side
This is the hands-on version. The mechanism and detection reference lives at Adversary › Kerberoasting; the exam-strategy view is on Active Directory.
1. Why it works¶
When a user wants to reach a service (MSSQL, a web app…), they ask the domain controller (KDC) for a service ticket (TGS) for that service. The key fact:
Part of the TGS the KDC hands out is encrypted with the password hash of the service account that runs the service.
Kerberos does not check, at ticket-issuing time, whether you are actually allowed to use that service — that check happens later, at the service. So any domain user can request a TGS for any account that has an SPN (Service Principal Name).
The attack, in four steps:
flowchart LR
A[Any domain user] -->|1. find SPN accounts| B[LDAP query to DC]
B -->|2. request TGS| C[DC / KDC]
C -->|3. TGS encrypted with<br/>service account hash| A
A -->|4. crack offline| D[hashcat]
No connection to the target service, no failed logon — just ordinary-looking Kerberos requests. It works because service accounts often have weak passwords that rarely change.
It is not spoofing, so unlike Responder poisoning it is allowed on the OSCP exam (exam rules).
2. Lab setup (once, on DC01)¶
You need a service account with an SPN and a weak password, plus a normal user to attack as. On DC01, as admin, in PowerShell:
# 1) Vulnerable service account — SPN set, deliberately weak password
New-ADUser -Name "svc_mssql" -SamAccountName svc_mssql `
-UserPrincipalName svc_mssql@lab.local `
-AccountPassword (ConvertTo-SecureString "Password1" -AsPlainText -Force) `
-Enabled $true -PasswordNeverExpires $true
setspn -S MSSQLSvc/db01.lab.local:1433 svc_mssql
# 2) A normal domain user to attack as
New-ADUser -Name "j.doe" -SamAccountName j.doe `
-AccountPassword (ConvertTo-SecureString "Welcome1!" -AsPlainText -Force) `
-Enabled $true
setspn -S MSSQLSvc/db01.lab.local:1433 svc_mssql registers an SPN on svc_mssql — an account is only Kerberoastable once it has an SPN. The password Password1 is in rockyou.txt, so the crack finishes in seconds; once the flow is familiar, change it to something not in rockyou (e.g. Autumn2026!) to feel a password that won't crack.
3. Run the attack (from Kali)¶
Linux tooling (Impacket), to match the exam. Run it from a Kali VM or the host laptop (10.10.10.1). Kerberos needs names, so fix resolution first:
export DC=10.10.10.20
export DOMAIN=lab.local
echo "$DC dc01.lab.local dc01 lab.local" | sudo tee -a /etc/hosts
3.1 Find SPN accounts¶
impacket-GetUserSPNs asks the domain over LDAP for accounts that have an SPN. The argument is domain/user:password; -dc-ip says which DC to ask.
ServicePrincipalName Name MemberOf PasswordLastSet LastLogon
----------------------------- --------- -------- ------------------- ---------
MSSQLSvc/db01.lab.local:1433 svc_mssql 2026-10-23 09:12:01 <never>
No ticket requested yet — this only confirms the target exists.
3.2 Request tickets¶
-request actually asks for the TGS of each SPN account and saves a crackable form to the file:
$krb5tgs$23$*svc_mssql$LAB.LOCAL$MSSQLSvc/db01.lab.local:1433*$a1b2...<long hex>...9f0e
$krb5tgs$23$ matters: krb5tgs = a Kerberos TGS hash, and 23 = encryption type RC4 (etype 23 / 0x17). RC4 cracks fast — good for the attacker, and a detection signal for the defender (§4). An AES ticket would show $krb5tgs$18$ and be far slower.
3.3 Crack offline¶
-m 13100 tells hashcat this is a Kerberoast (RC4 TGS) hash — the wrong mode won't crack. On success the password is appended:
Now feed svc_mssql:Password1 into the "try it everywhere" step → Active Directory › looting. Service accounts are often privileged, so this frequently unlocks the next host.
(alt) From Windows with Rubeus¶
If you have a domain user session on Win10:
/nowrap keeps each hash on one line so it pastes cleanly into hashcat.
4. Detect it in Splunk¶
Kerberoasting leaves event 4769 on the DC.
Event code 4769 — "A Kerberos service ticket was requested" is written to the DC's Security log whenever anyone requests a TGS. It fires thousands of times a day in normal use (every time a user reaches a file server, mail, etc.), so you don't look for "a 4769" — you look for a suspicious-shaped 4769:
| Field | Suspicious value | Why |
|---|---|---|
Ticket_Encryption_Type |
0x17 (RC4) |
Modern Windows defaults to AES (0x12). An RC4 request is the attack tool choosing weak crypto |
Service_Name |
one account requesting many in a short window | A normal user asks for one or two services; a single account sweeping SPNs is roasting |
4.0 Enable the audit first¶
Your lab's audit policy doesn't yet include Kerberos service-ticket operations, so 4769 isn't being written. On DC01:
The event lands in DC01's Security log, so DC01's Universal Forwarder must ship the Security channel to Splunk. Note the trace is on the DC, not on the host you attacked from.
4.1 The SPL, one line at a time¶
SPL chains commands with the pipe |: narrow the data on the left, reshape it at each |. Start by confirming the data arrives:
index=wineventlog is where the Windows logs go (index named explicitly — no index=*). source="WinEventLog:Security" keeps only the Security channel. EventCode=4769 keeps only service-ticket requests. Listed without pipes, these are all AND conditions.
Now keep only RC4:
Then drop computer accounts (their SPNs end in $) and krbtgt:
index=wineventlog source="WinEventLog:Security" EventCode=4769 Ticket_Encryption_Type=0x17
Service_Name!="*$" Service_Name!="krbtgt"
!= is "not equal", * is a wildcard, so Service_Name!="*$" means "service name does not end in $".
Finally, group by requester to expose the sweep:
index=wineventlog source="WinEventLog:Security" EventCode=4769 Ticket_Encryption_Type=0x17 Service_Name!="*$"
| stats dc(Service_Name) as spn_count values(Service_Name) as services by Account_Name, Client_Address
| where spn_count > 3
stats aggregates: dc(Service_Name) is a distinct count of service names, saved as spn_count; values(Service_Name) collects the actual names into services; by Account_Name, Client_Address groups per requesting account and source IP. | where spn_count > 3 keeps only accounts that asked for 4+ distinct SPNs.
Account_Name Client_Address spn_count services
------------ -------------- --------- -----------------------------------------
j.doe 10.10.10.30 7 MSSQLSvc/db01... HTTP/web01... CIFS/fs01...
One account, from the box you attacked, asking for 7 distinct SPNs over RC4 — the classic Kerberoasting shape. Account_Name and Client_Address are your investigation starting points.
If a field isn't extracted
If Ticket_Encryption_Type isn't a field in your instance, pull it from the raw text: | rex field=Message "Ticket Encryption Type:\s+(?<enc>0x[0-9a-fA-F]+)" then | search enc=0x17. rex extracts a regex capture group into a new field enc.
4.2 Reproduce with Atomic Red Team¶
Kerberoasting is T1558.003. On Win10:
Run it, then confirm the 4769s appear with the query above — the attack→detect cycle your lab is built for.
5. Zeek (sensor stack)¶
Once the Zeek sensor is up, Kerberos traffic is in kerberos.log with request_type (AS/TGS), service (the requested SPN), success, and encryption info. The network signal is the same — a burst of TGS requests from one source using weak encryption. Cross-checking host logs (4769) against network logs (kerberos.log) is the hunting standard. See Network.
6. Mitigation (report-ready)¶
- Move service accounts to gMSA (group managed service accounts) — long, auto-rotated passwords make cracking impractical.
- If a normal account must be used, require a 25+ character password; Kerberoasting is an offline crack, so length defeats it.
- Disable RC4 and allow AES only, so
0x17tickets never appear. - Alert on RC4 4769 requests (the SPL above as a saved search).
Related pages¶
- Adversary › Kerberoasting (detection reference) · Active Directory · Exam format › restrictions
- Next cousin technique: AS-REP Roasting (no password needed) — Adversary › AS-REP Roasting