AD^:Active Directory

PERSIST3 — Account Persistence via Certificate Renewal

Templates that allow renewal let a holder present their current certificate and receive a fresh one with a new validity window, authenticated by the…

advancedupdated 2026-08-10Certipy · OpenSSL · PowerShell

PERSIST3 — Account Persistence via Certificate Renewal

Quick Reference

FieldValue
CategoryAccount Persistence (renewal)
DifficultyLow
Pre-requisitesAn existing valid certificate + private key for the account; the template permits renewal
ToolsCertipy (req -renew), certreq
OPSEC NoiseLow — looks like normal certificate lifecycle
One-linerRenew a certificate before it expires using only the existing cert/key — no account password needed — extending your access for another full validity period, indefinitely.

What Is PERSIST3?

Templates that allow renewal let a holder present their current certificate and receive a fresh one with a new validity window, authenticated by the existing key rather than by the user’s password. An attacker who obtained a cert (via an ESC, THEFT, or PERSIST1) can therefore roll it forward forever, so long as they renew before each expiry. Password resets never break the chain because renewal never uses the password.

Renewal persistence loopLR
cert v1expires in 30d cert v2fresh 1-2y cert v3 … renew with key renew again forever

Step 1 — Renew Before Expiry

# Certipy — renew using the current pfx (no password required)
certipy-ad req -renew \
  -pfx current.pfx \
  -dc-ip $TARGET -ca 'DOMAIN-CA'
#   -> renewed.pfx with a fresh validity window
# Windows — certreq renewal of an existing cert by thumbprint
certreq -enroll -user -q -PolicyServer * -cert <THUMBPRINT> Renew

Step 2 — Track & Automate

# Check remaining validity of a stashed cert
certipy-ad cert -pfx current.pfx -nokey -out /dev/stdout | grep -i 'Not After'
openssl pkcs12 -in current.pfx -nodes -nokeys | openssl x509 -noout -enddate
  • Set a reminder a week before each expiry and re-run the renewal.
  • Keep the private key material offline between renewals to reduce host footprint.

OPSEC Considerations

ActionLogNoise
Renewal requestEvent 4886/4887 on CA (looks routine)🟢 Low
PKINIT auth with renewed certEvent 4768 on DC🟢 Low

[!note] Blends into normal lifecycle Renewals are indistinguishable from legitimate certificate maintenance, which is what makes this quiet persistence.


Mitigation

  • On compromise, revoke the certificate and its renewals, and disable renewal on sensitive templates.
  • Reduce validity/overlap windows; require re-approval on renewal for high-value templates.
  • Correlate renewals against expected owners and enrolment agents.

See Also

  • _ADCS Attack Methodology Guide · PERSIST1 — Active User Credential Theft via Certificates · PERSIST2 — Machine Account Persistence via Certificates
  • Sources: SpecterOps Certified Pre-Owned; Certipy Wiki
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.