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
- Obtain a TGT for a machine account (
fakepc$) with a known password against a FAST-enabled KDC.
- 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.
- 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)
Brief description
KerberosClient.tgs_reqkeys the PA-S4U-X509-USER checksum withself.key(the raw TGT session key) instead ofself.subkey(the FAST reply key) whenfast=True. The KDC validates that checksum underUSE_REPLY_KEY_USAGE, which under FAST means it expects the reply key. The mismatch causes the KDC to returnKRB_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 bothfast=Trueandfor_userare set on the sametgs_reqcall (armored S4U2self). Armored plain TGS-REQ and armored AS-REQ are unaffected.How to reproduce
fakepc$) with a known password against a FAST-enabled KDC.krb_tgs_req(or the higher-levelKerberosClientpath) withfast=Trueandfor_user="<user>@DOMAIN"set simultaneously -- this is the armored S4U2self path.Concretely with the Scapy
KerberosClientvia any wrapper that sets bothfast=Trueandfor_user:Actual result
The KDC returns
KRB_AP_ERR_MODIFIED (41). The PA-S4U-X509-USER checksum was signed withself.key(TGT session key) but the KDC verifies it underUSE_REPLY_KEY_USAGEusingself.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.subkeyorself.keyat the two call sites intgs_req(lines approximately 3699-3706 inscapy/layers/kerberos.py):The PA-FOR-USER checksum (HMAC-MD5, -138) and the authenticator checksum are correctly keyed and should not be changed.
Related resources
USE_REPLY_KEY_USAGElib/_scapy_fast_s4u_patch.py(version-guarded source patch, pending upstream fix)