Diamond ticket: preserve KDC-issued PAC_REQUESTOR and PAC_ATTRIBUTES in -request mode#2201
Open
0xCZR1 wants to merge 1 commit into
Open
Diamond ticket: preserve KDC-issued PAC_REQUESTOR and PAC_ATTRIBUTES in -request mode#22010xCZR1 wants to merge 1 commit into
0xCZR1 wants to merge 1 commit into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Introduction
When using
ticketer.pyin diamond mode (-requestwithout-impersonate), the script requests a real TGT from the KDC but then rebuilds the PAC from scratch viacreateBasicPac(). This discards the KDC-issuedPAC_REQUESTOR(type 18) andPAC_ATTRIBUTES(type 17) structures and replaces them with fabricated versions viacreateRequestorInfoPac().On fully patched KDCs with KB5008380/KB5020009 enforcement, this causes
KDC_ERR_TGT_REVOKED(substatus0x520) during cross-realm referral TGS-REQ. The KDC validates whether thePAC_REQUESTORin the TGT matches what it originally issued. The fabricated version, while structurally valid, was never issued by the KDC and fails this validation.This is specifically triggered during cross-realm operations (e.g., ExtraSid golden/diamond tickets targeting a parent domain from a child domain). Intra-realm usage may work because the same KDC that issued the TGT processes the TGS-REQ, but cross-realm referrals to a different KDC expose the mismatch.
Reproduction scenario
The patched
ticketer.pyforges a diamond ticket on Linux with-requestand-extra-sid(Enterprise Admins SID from the parent domain). The resulting.ccacheis converted to.kirbiand injected into a Windows SYSTEM session on a domain-joined host viaLsaRegisterLogonProcess+KerbSubmitTicketMessage. Windows then handles the cross-realm referral natively using AES-256, bypassing the RC4 inter-realm trust incompatibility that breaks Linux-based cross-realm attacks.Before (without patch): TGT injects successfully.
klist.exe get cifs/PARENT-DC01.parent.domain.comtriggers the cross-realm referral TGS-REQ. The KDC rejects it with substatus0x520(KDC_ERR_TGT_REVOKED) because the fabricatedPAC_REQUESTORdoes not match what the KDC originally issued. Windows LSA purges the TGT.After (with patch): Same flow. The preserved
PAC_REQUESTORpasses KDC validation. Cross-realm referral succeeds. Three tickets appear: the cross-realm TGT, the child-domain TGT, and thecifs/service ticket for the parent DC. Forest rootC$is accessible.Why diamond mode (not sapphire)
Sapphire tickets (
-impersonate) cannot be used for cross-realm privilege escalation via ExtraSid for three reasons:No ExtraSid support. The
-extra-sidlogic incustomizeTicket()is in the non-impersonate branch. Sapphire mode never processes ExtraSid.Protected Users blocks S4U2Self. Sapphire needs to impersonate a privileged user via S4U2Self+U2U to obtain their PAC. In hardened environments, all Domain Admins and Enterprise Admins are in Protected Users, which blocks S4U2Self delegation.
Different purpose. Sapphire copies existing privilege from a real user's PAC (stealth). Diamond fabricates privilege by modifying group memberships and adding ExtraSid (escalation). When the target privilege only exists in a parent domain (Enterprise Admins) and every account holding it is protected, diamond with ExtraSid is the only viable approach.
This patch ensures diamond mode works against fully patched KDCs where KB5020009 enforcement rejects the fabricated
PAC_REQUESTORduring cross-realm referral.What this PR does
Adds
_extractOriginalPacFields()method that:EncTicketPartusing the krbtgt key (already required for diamond mode)PAC_REQUESTORandPAC_ATTRIBUTESstructuresAfter
createBasicPac()rebuilds the PAC with modified group memberships and ExtraSid, the preserved originals overwrite the fabricated entries. The PAC signatures are then recomputed with the krbtgt key as usual.This only applies to diamond mode (
-requestwithout-impersonate). Sapphire mode (-impersonate) is unaffected as it has its own PAC handling via S4U2Self+U2U.Failure case without this patch
With this patch
Testing
Tested against Windows Server 2022 DCs (build 20348) with KB5020009 enforcement enabled, in a multi-domain forest with RC4 inter-realm trust keys. Cross-realm ExtraSid diamond ticket with Enterprise Admins SID successfully obtained cross-realm service tickets after the patch. Without the patch, the same configuration failed with
0x520on every attempt.Notes
-old-pacflag bypasses this entirely (no PAC_REQUESTOR/PAC_ATTRIBUTES at all)