Skip to content

Back to the Technology Index

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.

ModuleResponsibility
constants.pyMessage numbers, PA-DATA, KDC options, enctypes
asn1.pyAS/TGS/AP, PA-DATA, KRB-CRED, S4U, dMSA
types.pyPrincipal, Ticket, KerberosTime
crypto.pyString-to-key, encrypt/decrypt, checksums, Key
kerberosv5.pygetKerberosTGT / getKerberosTGS / GSS Type1/Type3
pac.pyPAC buffers and sign_pac
ccache.pyMIT ccache and kirbi (KRB-CRED)
gssapi.pyAP-REQ checksums, WRAP/MIC
keytab.pyMIT keytab
kpasswd.pyRFC 3244, TCP 464

Related commands: getTGT, getST, GetUserSPNs, GetNPUsers, ticketer, describeTicket

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.

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:

InputInitial Etype
NT hash providedRC4 (23) only
AES key 32 byteAES256 (18)
AES key 16 byteAES128 (17)
Password onlyAES256, 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).

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).

  1. Build an AP-REQ containing the TGT. Its Authenticator uses the TGS session key with usage 7
  2. Add it to the TGS-REQ as PA_TGS_REQ
  3. option: forwardable | renewable | renewable_ok | canonicalize (also set renew when renew=True)
  4. Etypes: RC4, AES256, AES128, DES3, and DES-MD5 by default. Passing etypes selects the types and their offered order
  5. Decrypt the TGS-REP enc-part with usage 8 → new session key
  6. If the returned sname differs 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.

Public APIs in crypto.py: Key, string_to_key, encrypt, decrypt, make_checksum, verify_checksum, cf2, and generate_kerberos_keys.

ClassEtypeKey LengthString-to-Key
_DESCBC38MIT DES + salt
_DES3CBC1624n-fold(password+salt)
_AES128CTS1716PBKDF2-HMAC-SHA1, 4096 iterations by default, derive(..., b'kerberos')
_AES256CTS1832As above, with a 32-byte seed
_RC42316Ignores 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:

UsageLocation
1AS-REQ PA_ENC_TIMESTAMP
2Ticket enc-part (service long-term key); getST force-forwardable
3AS-REP enc-part
7TGS-REQ Authenticator
8TGS-REP enc-part
11AP-REQ Authenticator
12AP-REP enc-part
13KRB-PRIV (kpasswd)
17S4U 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.

ConstantValueContents
PAC_LOGON_INFO1KERB_VALIDATION_INFO (RID, groups, UAC, ExtraSids)
PAC_CREDENTIALS_INFO2Credentials
PAC_SERVER_CHECKSUM6Signature with the service key
PAC_PRIVSVR_CHECKSUM7Signature with the KDC key (over the server checksum)
PAC_CLIENT_INFO_TYPE10Client name and time
PAC_DELEGATION_INFO11Services in the S4U2proxy chain
PAC_UPN_DNS_INFO12UPN / DNS; the S flag adds SAM+SID
PAC_CLIENT_CLAIMS_INFO_TYPE13Client claims
PAC_DEVICE_INFO_TYPE14Device information
PAC_DEVICE_CLAIMS_INFO_TYPE15Device claims
PAC_ATTRIBUTES_INFO17PAC attributes
PAC_REQUESTOR_INFO18Requestor 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.

The central implementation is GETST.doS4U.

S4U2self

  1. The calling principal’s TGT in PA_TGS_REQ
  2. Additional PA-DATA:
    • Default: PA_FOR_USER. Sign S4UByteArray = LE32(NT_PRINCIPAL) || user || realm || 'Kerberos' with the session key, usage 17, and HMAC-MD5
    • -dmsa: PA_S4U_X509_USER. The TGS-REP’s encrypted_pa_data may contain KERB_DMSA_KEY_PACKAGE
  3. The caller itself as sname (a ticket to itself)
  4. Stop here if -self is 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_delegation in PA_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.

FormatRepresentation
ccacheMIT FILE:, version 3/4 (0x0503 / 0x0504); v1/v2 unsupported
kirbiMimikatz 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.

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).

A ticket obtained from the KDC and one built using a long-term key on hand follow separate paths.

PathRequired KeyImplementation
GoldenAES or NT hash for krbtgtticketer builds the PAC and calls sign_pac
SilverService long-term keySame process, with sname set for the service
Sapphire / U2U PACCalling principal’s TGT session keyObtain and modify a genuine PAC with S4U2self + U2U
MS14-068Missing signature verificationgoldenPac creates a TGS with a modified PAC
Key ListAES key for RODC krbtgt_XXXXXkeylistattack, 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: TCP 464, protocol 0xFF80, TGT SPN kadmin/changepw; AP-REQ (usage 11, random subkey) plus KRB_PRIV (usage 13) carries ChangePasswdData. changePassword changes one’s own password; setPassword performs an administrator reset.
  • keytab: MIT v0x0502. getKey tries AES256 → AES128 → RC4 in order. loadKeysFromKeytab expands to the CLI’s -aesKey or -hashes options.
  • 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-tickets into getKerberosTGS
  • Preserve clock skew, salt mismatch, and KDC_ERR_ETYPE_NOSUPP as distinct diagnostic errors
  • Related tests: tests/misc/test_ccache.py, test_krb5_crypto.py, test_krb5_gssapi.py