Skip to main content

Overview

The impacket.krb5.asn1 module implements all ASN.1 (Abstract Syntax Notation One) structures defined in RFC 4120 and Microsoft extensions from [MS-KILE]. These structures represent Kerberos protocol messages, tickets, and data types encoded using Distinguished Encoding Rules (DER).

Module Location

from impacket.krb5.asn1 import (
    AS_REQ, AS_REP, TGS_REQ, TGS_REP,
    AP_REQ, AP_REP, KRB_ERROR,
    Ticket, EncryptedData, PrincipalName,
    EncASRepPart, EncTGSRepPart
)
Source: impacket/krb5/asn1.py

Basic Data Types

Primitive Types

Int32

32-bit signed integer used throughout Kerberos messages.
class Int32(univ.Integer):
    subtypeSpec = constraint.ValueRangeConstraint(-2147483648, 2147483647)
Range: -2,147,483,648 to 2,147,483,647

UInt32

32-bit unsigned integer for nonces and sequence numbers.
class UInt32(univ.Integer):
    pass  # 0 to 4,294,967,295

Microseconds

Microsecond values for timestamps.
class Microseconds(univ.Integer):
    subtypeSpec = constraint.ValueRangeConstraint(0, 999999)
Range: 0 to 999,999

KerberosString

UTF-8 encoded general string.
class KerberosString(char.GeneralString):
    encoding = 'utf-8'

# Usage
krb_string = KerberosString('username')

Realm

Kerberos realm name (domain).
class Realm(KerberosString):
    pass

# Example
realm = Realm('DOMAIN.LOCAL')

KerberosTime

Generalized time format: YYYYMMDDHHMMSSz
class KerberosTime(useful.GeneralizedTime):
    pass

# Format: "20240315120000Z"

KerberosFlags

Bit string for flags (32 bits minimum).
class KerberosFlags(univ.BitString):
    pass

# Usage with helper function
from impacket.krb5.asn1 import seq_set_flags
from impacket.krb5.constants import TicketFlags

flags = TicketFlags()
flags.forwardable = True
flags.renewable = True
seq_set_flags(ticket, 'flags', flags)

Principal Names

PrincipalName

Represents a Kerberos principal identity.
class PrincipalName(univ.Sequence):
    componentType = namedtype.NamedTypes(
        _sequence_component("name-type", 0, Int32()),
        _sequence_component("name-string", 1,
                          univ.SequenceOf(componentType=KerberosString()))
    )
Fields:
  • name-type: Principal type (NT_PRINCIPAL, NT_SRV_INST, etc.)
  • name-string: Sequence of name components
Example:
from impacket.krb5.asn1 import PrincipalName, seq_set
from impacket.krb5 import constants

# Create principal
principal = PrincipalName()
principal.setComponentByName('name-type', 
                             constants.PrincipalNameType.NT_PRINCIPAL.value)

# Set name components
name_string = principal.setComponentByName('name-string').getComponentByName('name-string')
name_string.setComponentByPosition(0, 'john')
name_string.setComponentByPosition(1, 'admin')  # Optional instance

# Result: john/admin
Common Name Types:
  • NT_PRINCIPAL = 1: User principal (user@REALM)
  • NT_SRV_INST = 2: Service with instance (krbtgt/REALM)
  • NT_SRV_HST = 3: Service with host (host/server.domain)
  • NT_ENTERPRISE = 10: UPN format

Encryption Structures

EncryptionKey

Cryptographic key with type identifier.
class EncryptionKey(univ.Sequence):
    componentType = namedtype.NamedTypes(
        _sequence_component('keytype', 0, Int32()),
        _sequence_component('keyvalue', 1, univ.OctetString())
    )
Fields:
  • keytype: Encryption algorithm identifier
  • keyvalue: Raw key bytes
Example:
from binascii import unhexlify

key = EncryptionKey()
key.setComponentByName('keytype', 18)  # AES256
key.setComponentByName('keyvalue', unhexlify('a1b2c3...'))
Key Types:
  • 1: DES-CBC-CRC
  • 3: DES-CBC-MD5
  • 16: DES3-CBC-SHA1
  • 17: AES128-CTS-HMAC-SHA1-96
  • 18: AES256-CTS-HMAC-SHA1-96
  • 23: RC4-HMAC

EncryptedData

Encrypted data with algorithm and optional version.
class EncryptedData(univ.Sequence):
    componentType = namedtype.NamedTypes(
        _sequence_component("etype", 0, Int32()),
        _sequence_optional_component("kvno", 1, UInt32()),
        _sequence_component("cipher", 2, univ.OctetString())
    )
Fields:
  • etype: Encryption type
  • kvno: Key version number (optional)
  • cipher: Encrypted ciphertext
Example:
enc_data = EncryptedData()
enc_data.setComponentByName('etype', 18)  # AES256
enc_data.setComponentByName('kvno', 3)
enc_data.setComponentByName('cipher', ciphertext_bytes)

Checksum

Integrity checksum for messages.
class Checksum(univ.Sequence):
    componentType = namedtype.NamedTypes(
        _sequence_component('cksumtype', 0, Int32()),
        _sequence_component('checksum', 1, univ.OctetString())
    )
Fields:
  • cksumtype: Checksum algorithm
  • checksum: Checksum value
Checksum Types:
  • 12: HMAC-SHA1-DES3
  • 15: HMAC-SHA1-96-AES128
  • 16: HMAC-SHA1-96-AES256
  • -138: HMAC-MD5 (0xffffff76)

Ticket Structures

Ticket

Kerberos ticket for service access.
class Ticket(univ.Sequence):
    tagSet = _application_tag(constants.ApplicationTagNumbers.Ticket.value)
    componentType = namedtype.NamedTypes(
        _vno_component(name="tkt-vno", tag_value=0),
        _sequence_component("realm", 1, Realm()),
        _sequence_component("sname", 2, PrincipalName()),
        _sequence_component("enc-part", 3, EncryptedData())
    )
Fields:
  • tkt-vno: Ticket version (always 5)
  • realm: Service realm
  • sname: Service principal name
  • enc-part: Encrypted ticket contents
Example:
from pyasn1.codec.der import decoder, encoder

# Parse ticket
ticket = decoder.decode(ticket_bytes, asn1Spec=Ticket())[0]

print(f"Realm: {ticket['realm']}")
print(f"Service: {ticket['sname']}")
print(f"Encryption: {ticket['enc-part']['etype']}")

# Encode ticket
ticket_bytes = encoder.encode(ticket)

EncTicketPart

Decrypted ticket contents (encrypted in ticket).
class EncTicketPart(univ.Sequence):
    tagSet = _application_tag(constants.ApplicationTagNumbers.EncTicketPart.value)
    componentType = namedtype.NamedTypes(
        _sequence_component("flags", 0, TicketFlags()),
        _sequence_component("key", 1, EncryptionKey()),
        _sequence_component("crealm", 2, Realm()),
        _sequence_component("cname", 3, PrincipalName()),
        _sequence_component("transited", 4, TransitedEncoding()),
        _sequence_component("authtime", 5, KerberosTime()),
        _sequence_optional_component("starttime", 6, KerberosTime()),
        _sequence_component("endtime", 7, KerberosTime()),
        _sequence_optional_component("renew-till", 8, KerberosTime()),
        _sequence_optional_component("caddr", 9, HostAddresses()),
        _sequence_optional_component("authorization-data", 10, AuthorizationData())
    )
Key Fields:
  • flags: Ticket flags (forwardable, renewable, etc.)
  • key: Session key for client-service communication
  • crealm: Client realm
  • cname: Client principal name
  • authtime: Initial authentication time
  • starttime: Ticket valid start time
  • endtime: Ticket expiration time
  • renew-till: Renewable until time
  • authorization-data: MS-PAC and other authz data

TicketFlags

Bit flags controlling ticket behavior.
class TicketFlags(KerberosFlags):
    pass
Common Flags:
  • Bit 1: forwardable - Can be forwarded to another service
  • Bit 2: forwarded - Ticket was forwarded
  • Bit 3: proxiable - Can be used to obtain proxy
  • Bit 8: renewable - Can be renewed
  • Bit 9: initial - Initial authentication
  • Bit 10: pre-authent - Pre-authentication used

Request Structures

AS-REQ (Authentication Service Request)

Initial authentication request for TGT.
class AS_REQ(KDC_REQ):
    tagSet = _application_tag(constants.ApplicationTagNumbers.AS_REQ.value)
Inherits from KDC_REQ:
class KDC_REQ(univ.Sequence):
    componentType = namedtype.NamedTypes(
        _vno_component(1),
        _msg_type_component(2, (AS_REQ_TAG, TGS_REQ_TAG)),
        _sequence_optional_component('padata', 3,
                                    univ.SequenceOf(componentType=PA_DATA())),
        _sequence_component('req-body', 4, KDC_REQ_BODY())
    )
Fields:
  • pvno: Protocol version (5)
  • msg-type: Message type (10 for AS-REQ)
  • padata: Pre-authentication data
  • req-body: Request body
Example:
from impacket.krb5.asn1 import AS_REQ, seq_set
from pyasn1.type.univ import noValue

asReq = AS_REQ()
asReq['pvno'] = 5
asReq['msg-type'] = 10

# Add pre-auth data
asReq['padata'] = noValue
asReq['padata'][0] = noValue
asReq['padata'][0]['padata-type'] = 2  # PA-ENC-TIMESTAMP
asReq['padata'][0]['padata-value'] = enc_timestamp

# Set request body
reqBody = seq_set(asReq, 'req-body')
reqBody['realm'] = 'DOMAIN.LOCAL'
reqBody['nonce'] = 123456

KDC_REQ_BODY

Request body for AS-REQ and TGS-REQ.
class KDC_REQ_BODY(univ.Sequence):
    componentType = namedtype.NamedTypes(
        _sequence_component('kdc-options', 0, KDCOptions()),
        _sequence_optional_component('cname', 1, PrincipalName()),
        _sequence_component('realm', 2, Realm()),
        _sequence_optional_component('sname', 3, PrincipalName()),
        _sequence_optional_component('from', 4, KerberosTime()),
        _sequence_component('till', 5, KerberosTime()),
        _sequence_optional_component('rtime', 6, KerberosTime()),
        _sequence_component('nonce', 7, UInt32()),
        _sequence_component('etype', 8, univ.SequenceOf(componentType=Int32())),
        _sequence_optional_component('addresses', 9, HostAddresses()),
        _sequence_optional_component('enc-authorization-data', 10, EncryptedData()),
        _sequence_optional_component('additional-tickets', 11,
                                    univ.SequenceOf(componentType=Ticket()))
    )
Key Fields:
  • kdc-options: Request options (forwardable, renewable, etc.)
  • cname: Client name (AS-REQ only)
  • realm: Target realm
  • sname: Service name
  • till: Requested expiration time
  • nonce: Random nonce for replay protection
  • etype: Acceptable encryption types

TGS-REQ (Ticket Granting Service Request)

Request for service ticket.
class TGS_REQ(KDC_REQ):
    tagSet = _application_tag(constants.ApplicationTagNumbers.TGS_REQ.value)
TGS-REQ Pre-auth Data:
# Requires AP-REQ in padata
tgsReq['padata'][0]['padata-type'] = 1  # PA-TGS-REQ
tgsReq['padata'][0]['padata-value'] = encoder.encode(apReq)

PA_DATA

Pre-authentication data.
class PA_DATA(univ.Sequence):
    componentType = namedtype.NamedTypes(
        _sequence_component('padata-type', 1, Int32()),
        _sequence_component('padata-value', 2, univ.OctetString())
    )
Common PA Types:
  • 1: PA-TGS-REQ (AP-REQ for TGS)
  • 2: PA-ENC-TIMESTAMP (encrypted timestamp)
  • 11: PA-ETYPE-INFO (salt information)
  • 19: PA-ETYPE-INFO2 (extended salt info)
  • 128: PA-PAC-REQUEST (request PAC)
  • 129: PA-FOR-USER (S4U2Self)
Example:
from impacket.krb5.asn1 import PA_DATA, PA_ENC_TIMESTAMP
from pyasn1.codec.der import encoder

# Create encrypted timestamp
pa_enc_ts = PA_ENC_TS_ENC()
pa_enc_ts['patimestamp'] = KerberosTime.to_asn1(now)
pa_enc_ts['pausec'] = now.microsecond

# Encrypt it
enc_ts = cipher.encrypt(key, 1, encoder.encode(pa_enc_ts), None)

# Wrap in PA_DATA
padata = PA_DATA()
padata['padata-type'] = 2
padata['padata-value'] = enc_ts

Response Structures

AS-REP (Authentication Service Reply)

TGT response from KDC.
class AS_REP(KDC_REP):
    tagSet = _application_tag(constants.ApplicationTagNumbers.AS_REP.value)
Inherits from KDC_REP:
class KDC_REP(univ.Sequence):
    componentType = namedtype.NamedTypes(
        _vno_component(0),
        _msg_type_component(1, (AS_REP_TAG, TGS_REP_TAG)),
        _sequence_optional_component('padata', 2,
                                    univ.SequenceOf(componentType=PA_DATA())),
        _sequence_component('crealm', 3, Realm()),
        _sequence_component('cname', 4, PrincipalName()),
        _sequence_component('ticket', 5, Ticket()),
        _sequence_component('enc-part', 6, EncryptedData())
    )
Fields:
  • pvno: Protocol version (5)
  • msg-type: Message type (11 for AS-REP)
  • crealm: Client realm
  • cname: Client name
  • ticket: The TGT
  • enc-part: Encrypted part (session key, times, etc.)
Example:
from pyasn1.codec.der import decoder

# Decode AS-REP
asRep = decoder.decode(response_bytes, asn1Spec=AS_REP())[0]

# Extract ticket
tgt = asRep['ticket']

# Decrypt enc-part
cipherText = asRep['enc-part']['cipher']
plainText = cipher.decrypt(key, 3, cipherText)  # Key usage 3

encASRepPart = decoder.decode(plainText, asn1Spec=EncASRepPart())[0]
sessionKey = encASRepPart['key']

EncASRepPart

Decrypted AS-REP encrypted part.
class EncASRepPart(EncKDCRepPart):
    tagSet = _application_tag(constants.ApplicationTagNumbers.EncASRepPart.value)
Inherits from EncKDCRepPart:
class EncKDCRepPart(univ.Sequence):
    componentType = namedtype.NamedTypes(
        _sequence_component('key', 0, EncryptionKey()),
        _sequence_component('last-req', 1, LastReq()),
        _sequence_component('nonce', 2, UInt32()),
        _sequence_optional_component('key-expiration', 3, KerberosTime()),
        _sequence_component('flags', 4, TicketFlags()),
        _sequence_component('authtime', 5, KerberosTime()),
        _sequence_optional_component('starttime', 6, KerberosTime()),
        _sequence_component('endtime', 7, KerberosTime()),
        _sequence_optional_component('renew-till', 8, KerberosTime()),
        _sequence_component('srealm', 9, Realm()),
        _sequence_component('sname', 10, PrincipalName()),
        _sequence_optional_component('caddr', 11, HostAddresses())
    )
Critical Fields:
  • key: Session key for TGS-REQ
  • nonce: Must match request nonce
  • flags: Ticket flags granted
  • authtime: Authentication time
  • endtime: TGT expiration
  • srealm: Server realm
  • sname: Server name (krbtgt/REALM)

TGS-REP (Ticket Granting Service Reply)

Service ticket response.
class TGS_REP(KDC_REP):
    tagSet = _application_tag(constants.ApplicationTagNumbers.TGS_REP.value)
Similar to AS-REP but:
  • msg-type: 13
  • ticket: Service ticket (not TGT)
  • Encrypted with TGS session key

EncTGSRepPart

Decrypted TGS-REP encrypted part.
class EncTGSRepPart(EncKDCRepPart):
    tagSet = _application_tag(constants.ApplicationTagNumbers.EncTGSRepPart.value)
Key usage: 8 (TGS session key)

Application Protocol

AP-REQ (Application Request)

Client authentication to service.
class AP_REQ(univ.Sequence):
    tagSet = _application_tag(constants.ApplicationTagNumbers.AP_REQ.value)
    componentType = namedtype.NamedTypes(
        _vno_component(0),
        _msg_type_component(1, (AP_REQ_TAG,)),
        _sequence_component('ap-options', 2, APOptions()),
        _sequence_component('ticket', 3, Ticket()),
        _sequence_component('authenticator', 4, EncryptedData())
    )
Fields:
  • pvno: 5
  • msg-type: 14
  • ap-options: Request options
  • ticket: Service ticket from TGS-REP
  • authenticator: Encrypted authenticator
AP Options:
  • Bit 2: mutual-required - Request AP-REP
Example:
apReq = AP_REQ()
apReq['pvno'] = 5
apReq['msg-type'] = 14

# Set mutual authentication
opts = []
opts.append(2)  # mutual-required
apReq['ap-options'] = constants.encodeFlags(opts)

# Set ticket
seq_set(apReq, 'ticket', ticket.to_asn1)

# Create and encrypt authenticator
authenticator = Authenticator()
authenticator['authenticator-vno'] = 5
authenticator['crealm'] = domain
authenticator['cusec'] = now.microsecond
authenticator['ctime'] = KerberosTime.to_asn1(now)

enc_auth = cipher.encrypt(sessionKey, 11, encoder.encode(authenticator), None)
apReq['authenticator']['etype'] = cipher.enctype
apReq['authenticator']['cipher'] = enc_auth

Authenticator

Proof of session key possession.
class Authenticator(univ.Sequence):
    tagSet = _application_tag(constants.ApplicationTagNumbers.Authenticator.value)
    componentType = namedtype.NamedTypes(
        _vno_component(name='authenticator-vno', tag_value=0),
        _sequence_component('crealm', 1, Realm()),
        _sequence_component('cname', 2, PrincipalName()),
        _sequence_optional_component('cksum', 3, Checksum()),
        _sequence_component('cusec', 4, Microseconds()),
        _sequence_component('ctime', 5, KerberosTime()),
        _sequence_optional_component('subkey', 6, EncryptionKey()),
        _sequence_optional_component('seq-number', 7, UInt32()),
        _sequence_optional_component('authorization-data', 8, AuthorizationData())
    )
Fields:
  • crealm: Client realm
  • cname: Client name
  • cksum: Checksum of application data (optional)
  • cusec: Microseconds of ctime
  • ctime: Current time
  • subkey: Optional session subkey
  • seq-number: Sequence number
Key Usage: 11 (for encryption)

AP-REP (Application Reply)

Mutual authentication response.
class AP_REP(univ.Sequence):
    tagSet = _application_tag(constants.ApplicationTagNumbers.AP_REP.value)
    componentType = namedtype.NamedTypes(
        _vno_component(0),
        _msg_type_component(1, (AP_REP_TAG,)),
        _sequence_component('enc-part', 2, EncryptedData())
    )
Fields:
  • pvno: 5
  • msg-type: 15
  • enc-part: Encrypted EncAPRepPart

EncAPRepPart

Decrypted AP-REP contents.
class EncAPRepPart(univ.Sequence):
    tagSet = _application_tag(constants.ApplicationTagNumbers.EncApRepPart.value)
    componentType = namedtype.NamedTypes(
        _sequence_component('ctime', 0, KerberosTime()),
        _sequence_component('cusec', 1, Microseconds()),
        _sequence_optional_component('subkey', 2, EncryptionKey()),
        _sequence_optional_component('seq-number', 3, UInt32())
    )
Key Usage: 12

Error Messages

KRB_ERROR

Error response from KDC or service.
class KRB_ERROR(univ.Sequence):
    tagSet = _application_tag(constants.ApplicationTagNumbers.KRB_ERROR.value)
    componentType = namedtype.NamedTypes(
        _vno_component(0),
        _msg_type_component(1, (KRB_ERROR_TAG,)),
        _sequence_optional_component('ctime', 2, KerberosTime()),
        _sequence_optional_component('cusec', 3, Microseconds()),
        _sequence_component('stime', 4, KerberosTime()),
        _sequence_component('susec', 5, Microseconds()),
        _sequence_component('error-code', 6, Int32()),
        _sequence_optional_component('crealm', 7, Realm()),
        _sequence_optional_component('cname', 8, PrincipalName()),
        _sequence_component('realm', 9, Realm()),
        _sequence_component('sname', 10, PrincipalName()),
        _sequence_optional_component('e-text', 11, KerberosString()),
        _sequence_optional_component('e-data', 12, univ.OctetString())
    )
Critical Fields:
  • stime: Server time
  • error-code: Kerberos error code
  • e-text: Human-readable error
  • e-data: Additional error data
Example:
try:
    asRep = decoder.decode(response, asn1Spec=AS_REP())[0]
except:
    krbError = decoder.decode(response, asn1Spec=KRB_ERROR())[0]
    error_code = krbError['error-code']
    
    if error_code == 25:  # KDC_ERR_PREAUTH_REQUIRED
        # Extract salt from e-data
        methods = decoder.decode(krbError['e-data'], asn1Spec=METHOD_DATA())[0]
        # Process pre-auth requirements

Microsoft Extensions

KERB_PA_PAC_REQUEST

Request PAC in ticket.
class KERB_PA_PAC_REQUEST(univ.Sequence):
    componentType = namedtype.NamedTypes(
        namedtype.NamedType('include-pac', univ.Boolean().subtype(
            explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)))
    )
Usage:
pacRequest = KERB_PA_PAC_REQUEST()
pacRequest['include-pac'] = True
encodedPacRequest = encoder.encode(pacRequest)

asReq['padata'][0]['padata-type'] = 128  # PA-PAC-REQUEST
asReq['padata'][0]['padata-value'] = encodedPacRequest

PA_FOR_USER_ENC

S4U2Self protocol data.
class PA_FOR_USER_ENC(univ.Sequence):
    componentType = namedtype.NamedTypes(
        _sequence_component('userName', 0, PrincipalName()),
        _sequence_optional_component('userRealm', 1, Realm()),
        _sequence_optional_component('cksum', 2, Checksum()),
        _sequence_optional_component('auth-package', 3, KerberosString())
    )
Purpose: Request ticket on behalf of user

PA_S4U_X509_USER

S4U with certificate.
class PA_S4U_X509_USER(univ.Sequence):
    componentType = namedtype.NamedTypes(
        namedtype.NamedType('user-id', S4UUserID().subtype(
            explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
        namedtype.NamedType('checksum', Checksum().subtype(
            explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1)))
    )

ETYPE_INFO2

Extended encryption type info.
class ETYPE_INFO2_ENTRY(univ.Sequence):
    componentType = namedtype.NamedTypes(
        _sequence_component('etype', 0, Int32()),
        _sequence_optional_component('salt', 1, KerberosString()),
        _sequence_optional_component('s2kparams', 2, univ.OctetString())
    )

class ETYPE_INFO2(univ.SequenceOf):
    componentType = ETYPE_INFO2_ENTRY()
Usage: Provides salt for string-to-key conversion

Helper Functions

seq_set

Set component and return it for chaining.
def seq_set(seq, name, builder=None, *args, **kwargs):
    component = seq.setComponentByName(name).getComponentByName(name)
    if builder is not None:
        seq.setComponentByName(name, builder(component, *args, **kwargs))
    else:
        seq.setComponentByName(name)
    return seq.getComponentByName(name)

# Usage
reqBody = seq_set(asReq, 'req-body')
seq_set(reqBody, 'sname', serverName.components_to_asn1)

seq_set_iter

Set sequence from iterable.
def seq_set_iter(seq, name, iterable):
    component = seq.setComponentByName(name).getComponentByName(name)
    for pos, v in enumerate(iterable):
        component.setComponentByPosition(pos, v)

# Usage
seq_set_iter(reqBody, 'etype', (17, 18, 23))  # AES128, AES256, RC4

seq_append

Append to sequence component.
def seq_append(seq, name, pairs):
    component = seq.getComponentByName(name)
    if component is None:
        component = seq.setComponentByName(name).getComponentByName(name)
    index = len(component)
    element = component.setComponentByPosition(index).getComponentByPosition(index)
    for k, v in pairs.items():
        element.setComponentByName(k, v)

# Usage
seq_append(asReq, 'padata', {'padata-type': 2, 'padata-value': data})

Encoding/Decoding

Encoding to DER

from pyasn1.codec.der import encoder

# Encode AS-REQ to bytes
asReqBytes = encoder.encode(asReq)

# Send to KDC
messageLen = struct.pack('!i', len(asReqBytes))
socket.sendall(messageLen + asReqBytes)

Decoding from DER

from pyasn1.codec.der import decoder

# Try to decode as AS-REP
try:
    asRep = decoder.decode(responseBytes, asn1Spec=AS_REP())[0]
except:
    # Maybe it's an error
    krbError = decoder.decode(responseBytes, asn1Spec=KRB_ERROR())[0]

Complete Example

Building AS-REQ

from impacket.krb5.asn1 import (
    AS_REQ, PA_DATA, KERB_PA_PAC_REQUEST,
    PA_ENC_TS_ENC, EncryptedData, seq_set, seq_set_iter
)
from impacket.krb5.types import Principal, KerberosTime
from impacket.krb5 import constants, crypto
from pyasn1.codec.der import encoder
from pyasn1.type.univ import noValue
import datetime

def build_as_req(username, password, domain, salt):
    # Create AS-REQ
    asReq = AS_REQ()
    asReq['pvno'] = 5
    asReq['msg-type'] = int(constants.ApplicationTagNumbers.AS_REQ.value)
    
    # Add PAC request
    pacRequest = KERB_PA_PAC_REQUEST()
    pacRequest['include-pac'] = True
    encodedPacRequest = encoder.encode(pacRequest)
    
    asReq['padata'] = noValue
    asReq['padata'][0] = noValue
    asReq['padata'][0]['padata-type'] = 128
    asReq['padata'][0]['padata-value'] = encodedPacRequest
    
    # Add encrypted timestamp
    cipher = crypto._enctype_table[18]  # AES256
    key = cipher.string_to_key(password, salt, None)
    
    timeStamp = PA_ENC_TS_ENC()
    now = datetime.datetime.now(datetime.timezone.utc)
    timeStamp['patimestamp'] = KerberosTime.to_asn1(now)
    timeStamp['pausec'] = now.microsecond
    
    encTS = cipher.encrypt(key, 1, encoder.encode(timeStamp), None)
    
    encryptedData = EncryptedData()
    encryptedData['etype'] = cipher.enctype
    encryptedData['cipher'] = encTS
    
    asReq['padata'][1] = noValue
    asReq['padata'][1]['padata-type'] = 2
    asReq['padata'][1]['padata-value'] = encoder.encode(encryptedData)
    
    # Build request body
    clientName = Principal(username, type=constants.PrincipalNameType.NT_PRINCIPAL.value)
    serverName = Principal(f'krbtgt/{domain}', type=constants.PrincipalNameType.NT_SRV_INST.value)
    
    reqBody = seq_set(asReq, 'req-body')
    opts = [1, 8, 3]  # forwardable, renewable, proxiable
    reqBody['kdc-options'] = constants.encodeFlags(opts)
    seq_set(reqBody, 'cname', clientName.components_to_asn1)
    seq_set(reqBody, 'sname', serverName.components_to_asn1)
    reqBody['realm'] = domain
    reqBody['till'] = KerberosTime.to_asn1(now + datetime.timedelta(days=1))
    reqBody['nonce'] = 12345
    seq_set_iter(reqBody, 'etype', (18,))  # AES256 only
    
    return encoder.encode(asReq)

See Also

Build docs developers (and LLMs) love