Skip to content

KerberosClient.tgs_req: PA-S4U-X509-USER checksum keyed with session key instead of FAST reply key (KRB_AP_ERR_MODIFIED under armored S4U2self) #5064

Description

@cbev0x

Brief description

KerberosClient.tgs_req keys the PA-S4U-X509-USER checksum with self.key (the raw TGT session key) instead of self.subkey (the FAST reply key) when fast=True. The KDC validates that checksum under USE_REPLY_KEY_USAGE, which under FAST means it expects the reply key. The mismatch causes the KDC to return KRB_AP_ERR_MODIFIED (41) on any armored S4U2self request. Unarmored S4U2self is unaffected because no subkey is generated, so the reply key and session key are the same.

Scapy version

2.7.0

Python version

3.12

Operating system

Kali Linux (tested); the bug is KDC-side validation so it reproduces on any OS running Scapy 2.7.0 against a FAST-enabled KDC.

Additional environment information

KDC: Windows Server 2025 (fully patched), CbacAndArmorLevel = 3 (fail-unarmored enforcement). Armor source: machine account TGT obtained via unarmored AS-REQ. The bug manifests specifically when both fast=True and for_user are set on the same tgs_req call (armored S4U2self). Armored plain TGS-REQ and armored AS-REQ are unaffected.

How to reproduce

  1. Obtain a TGT for a machine account (fakepc$) with a known password against a FAST-enabled KDC.
  2. Use that TGT as the armor source and call krb_tgs_req (or the higher-level KerberosClient path) with fast=True and for_user="<user>@DOMAIN" set simultaneously -- this is the armored S4U2self path.
  3. Observe the KDC response.

Concretely with the Scapy KerberosClient via any wrapper that sets both fast=True and for_user:

# Armored S4U2self -- both fast=True and for_user set
result = krb_tgs_req(
    upn="fakepc$@DOMAIN.LOCAL",
    spn="host/fakepc.domain.local",
    sessionkey=tgt_session_key,    # Key object from armor TGT
    ticket=tgt_ticket,
    ip="<KDC_IP>",
    realm="DOMAIN.LOCAL",
    for_user="Administrator@DOMAIN.LOCAL",
    fast=True,
    # armor kwargs ...
)

Actual result

The KDC returns KRB_AP_ERR_MODIFIED (41). The PA-S4U-X509-USER checksum was signed with self.key (TGT session key) but the KDC verifies it under USE_REPLY_KEY_USAGE using self.subkey (the FAST reply key). The two keys differ, so the checksum fails.

Expected result

The KDC should return a valid forwardable S4U2self service ticket. The fix is to key the PA-S4U-X509-USER checksum with self.subkey or self.key at the two call sites in tgs_req (lines approximately 3699-3706 in scapy/layers/kerberos.py):

# both PA-S4U-X509-USER checksum.make() calls -- change self.key to:
self.subkey or self.key,

The PA-FOR-USER checksum (HMAC-MD5, -138) and the authenticator checksum are correctly keyed and should not be changed.

Related resources

  • RFC 6113 Section 5.4 -- FAST reply key and USE_REPLY_KEY_USAGE
  • MS-SFU Section 2.2.1 -- PA-S4U-X509-USER checksum requirements
  • SteadFAST -- the tool where this was discovered; runtime workaround in lib/_scapy_fast_s4u_patch.py (version-guarded source patch, pending upstream fix)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions