Kerberos
In Kerberos, the client receives a TGT and then a service ticket from the KDC, and uses the ticket to authenticate to a service. This page follows Impacket’s code to show how it builds these exchanges and which keys process each message. For the overall AD authentication flow and SPNs, see Kerberos Authentication.
impacket/krb5/ is a client implementation of RFC 4120 with [MS-KILE],
[MS-PAC], and [MS-SFU] extensions. ASN.1 uses pyasn1; cryptography follows RFC 3961/3962/4757.
| Module | Responsibility |
|---|---|
constants.py | Message numbers, PA-DATA, KDC options, enctypes |
asn1.py | AS/TGS/AP, PA-DATA, KRB-CRED, S4U, dMSA |
types.py | Principal, Ticket, KerberosTime |
crypto.py | String-to-key, encrypt/decrypt, checksums, Key |
kerberosv5.py | getKerberosTGT / getKerberosTGS / GSS Type1/Type3 |
pac.py | PAC buffers and sign_pac |
ccache.py | MIT ccache and kirbi (KRB-CRED) |
gssapi.py | AP-REQ checksums, WRAP/MIC |
keytab.py | MIT keytab |
kpasswd.py | RFC 3244, TCP 464 |
Related commands: getTGT, getST, GetUserSPNs, GetNPUsers, ticketer, describeTicket
Exchange Overview
Section titled “Exchange Overview”sequenceDiagram
participant C as Client
participant K as KDC :88/tcp
participant S as Service
C->>K: AS-REQ (PA_PAC_REQUEST)
K-->>C: KDC_ERR_PREAUTH_REQUIRED + ETYPE_INFO2
C->>K: AS-REQ (PA_ENC_TIMESTAMP usage 1)
K-->>C: AS-REP (enc-part usage 3) = TGT + TGS session key
C->>K: TGS-REQ (PA_TGS_REQ AP-REQ usage 7)
K-->>C: TGS-REP (enc-part usage 8) = ST + app session key
C->>S: AP-REQ in SPNEGO (authenticator usage 11)
S-->>C: optional AP-REP (usage 12)
KDC communication uses sendReceive() over TCP with a four-byte big-endian length prefix.
Of the KRB_ERROR responses, only KDC_ERR_PREAUTH_REQUIRED (25) is returned as
a normal response; the others become KerberosError exceptions.
AS-REQ / AS-REP — getKerberosTGT
Section titled “AS-REQ / AS-REP — getKerberosTGT”getKerberosTGT(clientName, password, domain, lmhash, nthash, aesKey='', kdcHost=None, requestPAC=True, serverName=None, kerberoast_no_preauth=False, timeout=None)→ (tgt_bytes, cipher, client_key, sessionKey)The initial AS-REQ is unauthenticated and includes only PA_PAC_REQUEST.
The default sname is krbtgt/DOMAIN. Passing serverName requests another SPN
in the AS-REQ (such as kadmin/changepw for kpasswd or a no-preauth roast).
Etype selection:
| Input | Initial Etype |
|---|---|
| NT hash provided | RC4 (23) only |
| AES key 32 byte | AES256 (18) |
| AES key 16 byte | AES128 (17) |
| Password only | AES256, then RC4 on KDC_ERR_ETYPE_NOSUPP |
When the KDC returns METHOD_DATA, Impacket obtains the etype → salt mapping
from PA_ETYPE_INFO2 (or PA_ETYPE_INFO if absent) and calls
cipher.string_to_key(password, salt) to derive the long-term key. It adds
PA_ENC_TIMESTAMP (key usage 1) to the second AS-REQ.
With UF_DONT_REQUIRE_PREAUTH, the first response is already an AS-REP.
Its enc-part is still encrypted with the client’s long-term key (usage 3).
If decryption fails and kerberoast_no_preauth=True, Impacket returns the raw
AS-REP without a session key (AS-REP roasting).
If the second request on the password-only path returns KDC_ERR_ETYPE_NOSUPP,
Impacket calculates LM/NT hashes and recurses (RC4 fallback).
TGS-REQ / TGS-REP — getKerberosTGS
Section titled “TGS-REQ / TGS-REP — getKerberosTGS”getKerberosTGS(serverName, domain, kdcHost, tgt, cipher, sessionKey, renew=False, etypes=None, timeout=None)tgt may be either an AS-REP or a TGS-REP (to follow referrals).
- Build an AP-REQ containing the TGT. Its Authenticator uses the TGS session key with usage 7
- Add it to the TGS-REQ as
PA_TGS_REQ - option:
forwardable | renewable | renewable_ok | canonicalize(also setrenewwhenrenew=True) - Etypes: RC4, AES256, AES128, DES3, and DES-MD5 by default.
Passing
etypesselects the types and their offered order - Decrypt the TGS-REP
enc-partwith usage 8 → new session key - If the returned
snamediffers from the request, recurse to follow a referral
S4U and U2U are not in this function. examples/getST.py and
getPac.py / ticketer.py build the ASN.1 directly.
Cryptography and Salts
Section titled “Cryptography and Salts”Public APIs in crypto.py: Key, string_to_key, encrypt, decrypt,
make_checksum, verify_checksum, cf2, and generate_kerberos_keys.
| Class | Etype | Key Length | String-to-Key |
|---|---|---|---|
_DESCBC | 3 | 8 | MIT DES + salt |
_DES3CBC | 16 | 24 | n-fold(password+salt) |
_AES128CTS | 17 | 16 | PBKDF2-HMAC-SHA1, 4096 iterations by default, derive(..., b'kerberos') |
_AES256CTS | 18 | 32 | As above, with a 32-byte seed |
_RC4 | 23 | 16 | Ignores salt; MD4(UTF-16LE(password)) = NT hash |
AES/DES3 use the simplified profile from RFC 3961. Ke uses usage || 0xAA;
Ki uses usage || 0x55. The ciphertext is a confounder plus a truncated
12-byte HMAC-SHA1. RC4 (RFC 4757) remaps usages 3→8 and 23→13.
Common key usages:
| Usage | Location |
|---|---|
| 1 | AS-REQ PA_ENC_TIMESTAMP |
| 2 | Ticket enc-part (service long-term key); getST force-forwardable |
| 3 | AS-REP enc-part |
| 7 | TGS-REQ Authenticator |
| 8 | TGS-REP enc-part |
| 11 | AP-REQ Authenticator |
| 12 | AP-REP enc-part |
| 13 | KRB-PRIV (kpasswd) |
| 17 | S4U PA_FOR_USER HMAC-MD5 |
Typical AD salts: DOMAIN.COMuser for users, and DOMAIN.COMhost followed by
the lowercase sam for computers. When getST -force-forwardable derives an AES
key from a password, it hardcodes DOMAIN.upper()+user, which may not match
for computer accounts.
cf2() (FAST) is implemented but not connected to getKerberosTGT.
The PAC is AD_IF_RELEVANT / AD_WIN2K_PAC in the ticket’s authorization-data.
Its structures mix NDR and Structure.
| Constant | Value | Contents |
|---|---|---|
PAC_LOGON_INFO | 1 | KERB_VALIDATION_INFO (RID, groups, UAC, ExtraSids) |
PAC_CREDENTIALS_INFO | 2 | Credentials |
PAC_SERVER_CHECKSUM | 6 | Signature with the service key |
PAC_PRIVSVR_CHECKSUM | 7 | Signature with the KDC key (over the server checksum) |
PAC_CLIENT_INFO_TYPE | 10 | Client name and time |
PAC_DELEGATION_INFO | 11 | Services in the S4U2proxy chain |
PAC_UPN_DNS_INFO | 12 | UPN / DNS; the S flag adds SAM+SID |
PAC_CLIENT_CLAIMS_INFO_TYPE | 13 | Client claims |
PAC_DEVICE_INFO_TYPE | 14 | Device information |
PAC_DEVICE_CLAIMS_INFO_TYPE | 15 | Device claims |
PAC_ATTRIBUTES_INFO | 17 | PAC attributes |
PAC_REQUESTOR_INFO | 18 | Requestor SID |
sign_pac() zeros both checksums before serializing. It calculates the
server checksum over the entire PAC and the KDC checksum over the server signature.
The checksum type is KERB_NON_KERB_CKSUM_SALT (17). AES or HMAC-MD5 is
selected from SignatureType or the AES key length.
S4U2self / S4U2proxy / U2U
Section titled “S4U2self / S4U2proxy / U2U”The central implementation is GETST.doS4U.
S4U2self
- The calling principal’s TGT in
PA_TGS_REQ - Additional PA-DATA:
- Default:
PA_FOR_USER. SignS4UByteArray = LE32(NT_PRINCIPAL) || user || realm || 'Kerberos'with the session key, usage 17, and HMAC-MD5 -dmsa:PA_S4U_X509_USER. The TGS-REP’sencrypted_pa_datamay containKERB_DMSA_KEY_PACKAGE
- Default:
- The caller itself as
sname(a ticket to itself) - Stop here if
-selfis set
U2U (-u2u): Set enc_tkt_in_skey and place the caller’s TGT
in additional-tickets. Because the ticket enc-part is encrypted with
the TGT session key, its PAC can be read without the service key
(getPac).
S4U2proxy
- option:
cname_in_addl_tkt | canonicalize | forwardable | renewable - Set
resource_based_constrained_delegationinPA_PAC_OPTIONS additional-tickets= the ST from S4U2self (or-additional-ticket)sname= final SPN
-force-forwardable decrypts the S4U2self ticket with the service long-term key
(usage 2), sets forwardable, and re-encrypts it. This requires actually
possessing the service key.
ccache and kirbi
Section titled “ccache and kirbi”| Format | Representation |
|---|---|
| ccache | MIT FILE:, version 3/4 (0x0503 / 0x0504); v1/v2 unsupported |
| kirbi | Mimikatz KRB-CRED (msg-type 22); enc-part.etype=0 stores |
EncKrbCredPart in plaintext |
CCache.fromTGT / fromTGS decrypt the enc-part and populate the credential.
Credential.toTGT / toTGS build a synthetic AS-REP/TGS-REP with a dummy
enc-part so that getKerberosTGS can reuse the ticket and session key.
CCache.parseFile(domain, user, target) reads KRB5CCNAME and prefers
a TGS for the target SPN, falling back to krbtgt/DOMAIN@DOMAIN.
ticketConverter handles conversion between formats. Impacket does not use the second ticket or address fields that it retains.
GSS-API
Section titled “GSS-API”getKerberosType1 obtains a TGS for host/<target> and puts an
AP-REQ in SPNEGO NegTokenInit. The Authenticator checksum type is 0x8003
(CheckSumField: Lgth=16, Bnd[16], Flags).
DCERPC uses GSS_C_CONF|INTEG|SEQUENCE|REPLAY|MUTUAL|DCE_STYLE.
For LDAP over LDAPS, it puts the MD5 of the TLS CBT in Bnd.
WRAP: RC4 follows RFC 4757 (TOK_ID 0x0102); AES follows RFC 4121 (0x0504,
RRC=28, usages 24/22). LDAP signing wraps GSS_Wrap_LDAP in a MechIndepToken
(OID 1.2.840.113554.1.2.2).
Modifying and Forging Issued Tickets
Section titled “Modifying and Forging Issued Tickets”A ticket obtained from the KDC and one built using a long-term key on hand follow separate paths.
| Path | Required Key | Implementation |
|---|---|---|
| Golden | AES or NT hash for krbtgt | ticketer builds the PAC and calls sign_pac |
| Silver | Service long-term key | Same process, with sname set for the service |
| Sapphire / U2U PAC | Calling principal’s TGT session key | Obtain and modify a genuine PAC with S4U2self + U2U |
| MS14-068 | Missing signature verification | goldenPac creates a TGS with a modified PAC |
| Key List | AES key for RODC krbtgt_XXXXX | keylistattack, KERB_KEY_LIST_REQ (PA 161) |
ticketer fills the RID, groups, ExtraSids (SIDHistory), and UAC in
KERB_VALIDATION_INFO and signs the server/KDC checksums with the corresponding keys.
raiseChild follows the trust path from the child domain’s krbtgt to the forest
and creates a ticket containing SIDHistory.
These operations do not “edit” the output of getKerberosTGT.
The PAC buffer order, nested checksums, ticket flags, and crealm/sname
must match the service’s validation.
kpasswd / keytab
Section titled “kpasswd / keytab”- kpasswd: TCP 464, protocol
0xFF80, TGT SPNkadmin/changepw; AP-REQ (usage 11, random subkey) plusKRB_PRIV(usage 13) carriesChangePasswdData.changePasswordchanges one’s own password;setPasswordperforms an administrator reset. - keytab: MIT v0x0502.
getKeytries AES256 → AES128 → RC4 in order.loadKeysFromKeytabexpands to the CLI’s-aesKeyor-hashesoptions.
Checks When Making Changes
Section titled “Checks When Making Changes”- Changing the etype list or fallback order may break subsequent TGS requests
- Sign the PAC in server → KDC order; do not fix only one signature
- Do not force S4U PA-DATA and
additional-ticketsintogetKerberosTGS - Preserve clock skew, salt mismatch, and
KDC_ERR_ETYPE_NOSUPPas distinct diagnostic errors - Related tests:
tests/misc/test_ccache.py,test_krb5_crypto.py,test_krb5_gssapi.py

