Skip to content

[FEAT] Add esc5 command: audit and exploit ESC5 (vulnerable PKI object access control) - #374

Open
f8al wants to merge 2 commits into
ly4k:mainfrom
f8al:main
Open

f8al wants to merge 2 commits into
ly4k:mainfrom
f8al:main

Conversation

@f8al

@f8al f8al commented Sep 9, 2026 •

Copy link
Copy Markdown

This PR adds support for ESC5

Why

find has no code path for ESC5 ("Vulnerable PKI Object Access Control") — it enumerates
certificate templates, CAs, and issuance policies, and none of those queries touch the AD
objects ESC5 is actually about: the Public Key Services container tree (Enrollment
Services, Certificate Templates, Certification Authorities, OID), each CA's own AD object
and its underlying computer object, and NTAuthCertificates. This is a real gap — see
SpecterOps' "From DA to EA with ESC5" —
and today identifying it means falling back to BloodHound/ADSIEdit/PowerShell entirely
outside Certipy.

What

A new esc5 subcommand with three actions:

  • audit (default-safe, read-only): resolves the authenticated identity's SID plus
    its full nested group closure, walks every audited object's DACL, and reports which
    objects that identity already holds a qualifying right on — GenericAll/GenericWrite/
    WriteDacl/WriteOwner/ownership, plus WriteProperty scoped specifically to
    cACertificate (resolved live from the schema) and Create-Child on containers. Every
    other grantee is still reported for defensive visibility (-hide-admins to suppress
    well-known admins, matching find's own flag).
  • exploit: if the identity holds a qualifying right on NTAuthCertificates, adds a
    self-signed rogue CA certificate to it — a forest-wide trust change. Only ever ADDs,
    never touches existing trusted CAs; prompts for confirmation unless -force; always
    writes a restore record (base64 DER + a standalone PFX) before reporting success. The
    resulting CA .pfx hands off directly to forge -ca-pfx for weaponization rather than
    reimplementing certificate forging here.
  • restore: undoes a prior exploit by removing exactly the recorded certificate and
    nothing else, verified via before/after counts on NTAuthCertificates.

Every other sub-case (container control, a CA's own object, a CA's computer object) is
reported with manual next-step guidance pointing at existing commands (template, ca,
shadow) rather than auto-exploited, since each of those chains into a separate,
already-tooled attack.

Built on Certipy's existing primitives rather than as a bolt-on: Target/LDAPConnection
for auth (Kerberos, hashes, certs, LDAP signing/channel-binding options all come for free),
get_user_sids for the identity's group closure, lookup_sid/is_admin_sid for grantee
resolution, and certipy.lib.certificate/files for the rogue CA and output handling.

Testing

black/isort/flake8/pyright all clean. No tests/ directory exists in the repo to
extend, so validation was done with throwaway scripts (not included in this diff):
ACE classification against hand-built impacket security-descriptor structures (generic
rights, scoped WriteProperty(cACertificate), scoped Create-Child, inherited flags,
denied ACEs), and a fully mocked-LDAPConnection run of audit/exploit/restore,
including the "no precondition, no -force" refusal path and idempotent restore. Manually
exercised certipy esc5 -h / esc5 audit -h etc. for CLI correctness.

Docs

Wiki updates for ESC5 (06 - Privilege Escalation) and the command reference
(08 - Command Reference) are ready — sending as a patch against the wiki repo per
CONTRIBUTING.md, separately from this PR since wikis don't support PRs.

f8al added 2 commits September 9, 2026 09:58
certipy has no code for ESC5 (vulnerable PKI object access control):
dangerous ACEs on the AD objects that make up AD CS itself -- the Public
Key Services container tree (Enrollment Services, Certificate Templates,
Certification Authorities, OID), each CA's own AD object and its
underlying computer object, and NTAuthCertificates -- as opposed to a
single certificate template (ESC4) or a CA's ManageCA/ManageCertificates
security descriptor (ESC7). 'find' never queries any of these objects.

Adds a new `esc5` subcommand with three actions:

- audit (default-safe, read-only): resolves the authenticated identity's
  SID plus full group closure, walks every audited object's DACL, and
  reports which objects that identity already holds a qualifying right
  on (GenericAll/GenericWrite/WriteDacl/WriteOwner/ownership, plus
  WriteProperty scoped to cACertificate and Create-Child on containers),
  alongside every other grantee for defensive visibility.
- exploit: if the identity holds a qualifying right on
  NTAuthCertificates, adds a self-signed rogue CA certificate to it --
  a forest-wide trust change. Only ever ADDs, never touches existing
  trusted CAs, prompts for confirmation unless -force is given, and
  always writes a restore record before reporting success. The
  resulting CA .pfx hands off directly to `certipy-ad forge -ca-pfx`
  for weaponization rather than reimplementing certificate forging.
- restore: undoes a prior exploit run by removing exactly the recorded
  certificate and nothing else, verified via before/after counts.

Every other sub-case (container control, a CA's own object, a CA's
computer object) is reported with manual next-step guidance pointing at
existing certipy commands (template, ca, shadow) rather than
auto-exploited, since those chain into separate, already-tooled attacks.

Built on certipy's existing primitives rather than as a standalone
script: Target/LDAPConnection for auth (Kerberos, hashes, certs, etc.
all come for free), get_user_sids for the identity's group closure,
lookup_sid/is_admin_sid for grantee resolution and -hide-admins
filtering, and certipy.lib.certificate/files for the rogue CA and
output handling.
@f8al f8al changed the title Add esc5 command: audit and exploit ESC5 (vulnerable PKI object access control) [FEAT] Add esc5 command: audit and exploit ESC5 (vulnerable PKI object access control) Sep 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant