Why this module exists. Forest trusts were Microsoft’s promise that the forest boundary was a hard security boundary. SID Filtering — enabled by default on external trusts since Windows Server 2003 — was the control that made the promise real. But every year, a new variation on SID-History abuse shows it is not as hard a boundary as the marketing says. This module walks the canonical attack, the modern variations, and where the boundary actually lives.
What SID History actually is
SID History is the sIDHistory attribute on a user, group, or computer object. It is a multi-valued attribute holding old SIDs the principal used to have. When AD builds a Kerberos ticket for the principal, the contents of sIDHistory are added to the PAC (Privilege Attribute Certificate) alongside the principal’s current SID and group SIDs. Every Windows machine the principal authenticates to evaluates access against the union of all those SIDs.
The legitimate use: a company merger. Alice was contoso\alice with SID S-1-5-21-AAAA. After migration she becomes fabrikam\alice with SID S-1-5-21-BBBB. Resources in contoso still ACL Alice’s old SID. Putting S-1-5-21-AAAA in her sIDHistory keeps that ACL access working while she lives in fabrikam.
The classic attack — SID History injection across an unfiltered trust
Assume the attacker is Domain Admin in a low-trust child domain dev.corp.local. The parent domain corp.local trusts dev.corp.local via an intra-forest trust (parent-child trust). Intra-forest trusts do not have SID Filtering enabled by default — by design, because users move between domains in the same forest.
# Mimikatz Golden Ticket with injected SID History for Enterprise Admins
# of the parent (corp.local) forest:
kerberos::golden \
/domain:dev.corp.local \
/sid:S-1-5-21-AAAA \ # child domain SID
/sids:S-1-5-21-CCCC-519 \ # Enterprise Admins SID of parent
/krbtgt:<krbtgt hash of dev.corp.local> \
/user:DontMatter \
/ptt
The injected SID S-1-5-21-CCCC-519 puts the forged ticket into the Enterprise Admins group of the parent forest. The PAC validation on a parent-forest DC will trust the ticket because it came over an intra-forest trust, where SID Filtering is off. Result: full Enterprise Admins privilege across the parent forest, originating from a Domain Admin compromise of a single child.
Why SID Filtering does not always save you
SID Filtering on a trust strips out SIDs from foreign domains from incoming PACs. It is enabled by default on:
- External trusts (one domain to another, not in the same forest)
- Forest trusts (since Server 2003 with the
EnableSIDHistorydefault policy)
It is not enabled on intra-forest (parent-child or tree-root) trusts. So the forest is the security boundary, not the domain. This is the single most common misunderstanding in AD security audits: organisations think Domain Admin in a sandbox child means “sandbox compromise”; in reality, Domain Admin in any child domain is one Golden Ticket from Enterprise Admin of the whole forest.
The modern variation — SID History on a regular user object
Writing sIDHistory on a regular user (not via a Golden Ticket) requires the SeMigrateSIDHistoryPrivilege right, which only DSRM or the built-in ADMT-style tooling holds. So historically this required PDC-emulator equivalent privilege. But:
- If an attacker reaches Domain Admin in a forest, they can write sIDHistory on user objects directly via LDAP modify operations from a DC. The PDC emulator runs the SDProp thread that enforces protected-account rules, but it does not block sIDHistory writes from a DA.
- This is persistence: the user object now has the privileged SID in its sIDHistory permanently. Every login produces a ticket with the privileged SID embedded. Removing the user from privileged groups does not strip sIDHistory.
External / forest trust attacks — the bypass class
Forest and external trusts have SID Filtering on by default, but specific configurations turn it off:
- Selective Authentication mode. When configured, only specific principals can authenticate across the trust. Misconfiguration is more common than absence of configuration.
- Quarantined Trust mode (legacy). An older variant that some upgraded environments still carry. Less restrictive than modern SID Filtering.
- Trusts with
netdom trust /quarantine:noapplied. Indian banking environments doing legacy AD federation with vendor forests have historically disabled SID Filtering for compatibility. Auditors miss this regularly.
Check the state of every trust:
# PowerShell on a DC in the trusting domain
Get-ADTrust -Filter * | Select-Object Name,Direction,DisallowTransivity,SIDFilteringForestAware,SIDFilteringQuarantined
# Any False in SIDFilteringForestAware or SIDFilteringQuarantined columns
# is a trust where SID History injection works. Investigate why.
Detection
- Event 4662 on the parent domain DC with
Propertiescontaining the sIDHistory write attribute GUID. Indicates a sIDHistory modification. - BloodHound’s “Forest Domain Trust SID History” edge. The newer BloodHound CE versions surface this class explicitly.
- PAC inspection on suspicious tickets. Tools like
Rubeus describeon a captured ticket show the embedded SID History — useful for incident forensics. - Periodic LDAP audit for users with non-empty sIDHistory.
Get-ADUser -Filter {sIDHistory -like '*'} -Properties sIDHistory. In a steady-state environment with no recent migrations, this should be empty.
Defender’s playbook
- Audit every trust quarterly. Any non-default SID Filtering state needs a written justification, signed off by AD operations leadership.
- Treat Domain Admin in any child domain as Enterprise Admin equivalent. The forest is the trust boundary; act accordingly.
- Where intra-forest trusts are not needed (rare but possible — empty root forest model), consolidate to a single domain.
- Disable sIDHistory writes via Set-ADTrust quarantine mode where the trust is non-migrational. Then re-enable for the migration window if needed.
- If you find a non-empty sIDHistory on a non-migrated user — investigate as compromise. Strip it via
Set-ADUser -Clear sIDHistoryonly after IR clears the account.
Why this is the highest-impact AD attack class
Most AD attacks let you compromise one identity. SID History injection across an unfiltered intra-forest trust lets you take the entire forest from a single child-domain DA. Indian banking environments with three-domain forests inherited from 2010-era deployments are particularly exposed: the dev/staging child is treated as low-trust, but the trust topology says otherwise.
Key takeaways
- SID History puts old SIDs in a principal’s Kerberos PAC; resources evaluate access against the union.
- SID Filtering blocks foreign SIDs on external and forest trusts but is OFF by default on intra-forest trusts.
- The forest, not the domain, is the AD security boundary. Audit child-domain Tier-0 the same as root.
- Hunt for non-empty sIDHistory in steady-state environments — anomalies are persistence.
Get a VAPT scoping call
Senior practitioner-led VAPT — not a checklist run by juniors. CVSS-scored findings, free retest, attestation letter. India's SMBs and SaaS teams.