ADTRUST-004: SID Filtering Status
- Platform
- Active Directory
- Category
- AD Trust Relationships
- Severity
- Critical
- Zero Trust pillar
- Identity (weight 3)
- Golden fixtures
- 3
- Branch coverage
- Observed: fixtures prove the verdicts they exercise
- Provenance
- baseline
What it checks
The check binds to the configuration naming context and the default naming context of every domain in the forest and enumerates all trustedDomain objects under CN=System,DC=<domain>. For each object it captures trustPartner, trustDirection (1=inbound, 2=outbound, 3=bidirectional), trustType (1=Windows NT downlevel, 2=AD external/forest, 3=MIT realm, 4=DCE), and trustAttributes. trustAttributes is the load-bearing bitmask. The relevant bits per MS-ADTS section 6.1.6.7.9 are: 0x00000001 TRUST_ATTRIBUTE_NON_TRANSITIVE, 0x00000004 TRUST_ATTRIBUTE_QUARANTINED_DOMAIN (the external trust SID-filter "quarantine" flag), 0x00000008 TRUST_ATTRIBUTE_FOREST_TRANSITIVE (this object is a forest trust), 0x00000040 TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL (cross-forest SID filtering relaxed to external-trust behavior), 0x00000080 TRUST_ATTRIBUTE_USES_RC4_ENCRYPTION, 0x00000200 TRUST_ATTRIBUTE_CROSS_ORGANIZATION_ENABLE_TGT_DELEGATION, and 0x00000400 TRUST_ATTRIBUTE_PIM_TRUST. For external trusts (trustType=2 with the FOREST_TRANSITIVE bit clear) the check requires the QUARANTINED_DOMAIN bit (0x4) to be set. For forest trusts (trustType=2 with the FOREST_TRANSITIVE bit 0x8 set) the check requires that TREAT_AS_EXTERNAL (0x40) is NOT set and that EnableSidHistory is not configured (read via netdom or via the msDS-TrustForestTrustInfo blob). Any trust that fails these conditions is surfaced as a finding with the trust partner, direction, and the exact attribute bitmask in hex.
Why it matters
Forest and external trusts are the only routes by which a SID from a foreign domain can land in a Kerberos PAC presented to your KDC. SID filtering is the choke point that decides whether that SID will be honored or stripped. When filtering is disabled or weakened, the entire trusted forest becomes a privilege escalation path into yours. The classic abuse pattern: attacker compromises a small subsidiary, partner, lab, or merger-and-acquisition forest with a trust into the corporate forest. The attacker obtains the krbtgt hash of the trusted domain (a one-time DCSync of any domain controller they now own). They forge a "golden ticket" inter-realm referral PAC with ExtraSids populated with the SID of Enterprise Admins in the trusting forest. If the trust is a same-forest trust, or a cross-forest trust with TREAT_AS_EXTERNAL set, or an external trust without quarantine, the trusting KDC builds the access token with Enterprise Admins membership and the attacker has total control of the trusting forest. Sean Metcalf, Will Schroeder, Lee Christensen, and Dirk-jan Mollema have demonstrated this end-to-end repeatedly since 2014. The forest is documented by Microsoft (after SpecterOps published Not A Security Boundary in 2018) as not a security boundary, and SID filtering on inbound trusts is one of the few controls that actually makes a forest boundary meaningful. Mergers, acquisitions, and migrations frequently leave SID filtering disabled "temporarily" to permit SID history copying via ADMT or Quest QMM, and the disabled state then becomes permanent because no one knows it is unsafe to leave it that way.
Attack path
Step 1: Foothold in the trusted domain. The attacker compromises any domain in a forest that holds a trust into your forest, or compromises a standalone domain on the other end of an external trust. This is frequently easier than attacking the target forest directly: subsidiaries, dev labs, and acquired companies typically have weaker controls than the corporate forest. Domain Admin in the trusted domain is the precondition. Step 2: Extract krbtgt. The attacker runs DCSync against any DC in the trusted domain (Mimikatz lsadump::dcsync /domain:trusted.local /user:krbtgt or Impacket secretsdump.py -just-dc-user trusted.local/krbtgt). The krbtgt NT hash is now in their possession permanently; rotation in the trusted domain does not affect the trusting domain. Step 3: Enumerate trust posture from the trusted side. The attacker reads the inbound trustedDomain object (Get-ADTrust -Filter * | Select Name, TrustAttributes, TrustDirection, TrustType, or PowerView Get-DomainTrust). They check whether QUARANTINED_DOMAIN (0x4) is set on the external trust into the target, or whether TREAT_AS_EXTERNAL (0x40) is set on the cross-forest trust, or whether EnableSidHistory has been turned on. Any of these makes the next step viable with high-RID SIDs at minimum. Step 4: Identify a target SID. Cross-forest with strict SID filtering: only SIDs with RID >= 1000 from the trusted forest survive, so the attacker enumerates RID >= 1000 groups in the target forest with effective privilege (Exchange security groups, helpdesk groups, custom Tier 0 groups, server-admin groups) using Get-DomainGroup -Domain target.local or BloodHound. Cross-forest with TREAT_AS_EXTERNAL or same-forest trust: built-in groups Enterprise Admins (RID 519), Domain Admins (RID 512), and Administrators (S-1-5-32-544) become reachable via SID History injection. Step 5: Forge the inter-realm ticket. The attacker uses Mimikatz kerberos::golden /domain:trusted.local /sid:<trusted-sid> /sids:S-1-5-21-<target>-519,S-1-5-21-<target>-512 /rc4:<krbtgt-hash> /user:Administrator /service:krbtgt /target:target.local /ticket:trust.kirbi, or Rubeus.exe silver / golden with /sids:. The SIDs supplied via /sids land in the ExtraSids field of the PAC KERB_VALIDATION_INFO structure, which the trusting KDC reads on the inter-realm TGS-REQ. Step 6: Present the ticket to the target KDC. The attacker submits the forged inter-realm TGT to a DC in the target forest. With SID filtering broken, the KDC accepts the ExtraSids, issues a service ticket whose PAC carries Enterprise Admins, and the attacker now has full control of the target forest. From here they DCSync the target krbtgt for persistence, dump LSASS on every Tier 0 asset, and the engagement is over. Step 7: Persist. Even after the original foothold is closed, the attacker can repeat the SID-injection golden ticket at will using the trusted-domain krbtgt hash, because the trust object itself is the durable persistence mechanism. Closing the door requires re-enabling SID filtering on the trust and ideally tearing the trust down and rebuilding it.
How Guerrilla assesses it
Guerrilla enumerates the System container in every domain naming context via LDAP filter (objectClass=trustedDomain) and pulls the attribute set [trustPartner, trustDirection, trustType, trustAttributes, flatName, securityIdentifier, msDS-TrustForestTrustInfo, whenCreated, whenChanged]. For each trust object it decomposes trustAttributes into named flags and applies the following rules. External trust (trustType=2, FOREST_TRANSITIVE 0x8 NOT set, direction inbound or bidirectional): fail if QUARANTINED_DOMAIN 0x4 is NOT set. Forest trust (trustType=2, FOREST_TRANSITIVE 0x8 set, direction inbound or bidirectional): fail if TREAT_AS_EXTERNAL 0x40 is set, or if msDS-TrustForestTrustInfo indicates EnableSidHistory is on for the inbound direction. The check additionally flags trusts with USES_RC4_ENCRYPTION 0x80 set, CROSS_ORGANIZATION_ENABLE_TGT_DELEGATION 0x200 set (the unconstrained-delegation cross-trust path documented by SpecterOps), and PIM_TRUST 0x400 set. Where the running account has the necessary rights, Guerrilla cross-validates by shelling to netdom trust <localdomain> /domain:<trustpartner> /Quarantine and netdom trust <forestroot> /domain:<trustpartner> /EnableSIDHistory to parse the textual confirmation. Findings include the trustAttributes value rendered in hex (e.g., 0x00000008 for an unfiltered forest trust) and the equivalent netdom command to remediate.
Recommended value
SID filtering (quarantine) enabled on all external and forest trusts
Remediation
Verify SID filtering status using 'netdom trust /domain:trusted.domain /Quarantine'. Enable SID filtering with 'netdom trust /domain:trusted.domain /Quarantine:Yes'. Note: SID filtering is enabled by default on external trusts but must be verified on forest trusts where it may have been deliberately disabled
Fixture-proven verdicts
Every verdict below is proven by a golden fixture in the module's gating test suite. This table derives from the last green run; it cannot be edited by hand.
| Scenario | Expected verdict |
|---|---|
| clean | PASS |
| known-bad | FAIL |
| throttled | Not Assessed |
Framework mappings
- NIST SP 800-53
- AC-4, AC-6
- CIS Benchmark
- 18.3.1
- ANSSI
- R32
- CIS AD Benchmark
- 3.2.1
- MITRE ATT&CK
- T1134.005