BlackArrow blog header

AD CS: from ManageCA to RCE

Introduction

In our previous article, we covered an engagement where it was necessary to execute the ESC7 attack to escalate privileges by abusing the Active Directory Certificate Services (AD CS). During this Red Team exercise, a detailed research was conducted and it resulted in the publication of several modules for Certify, which allow the abuse of the ManageCA and ManageCertificates permissions as suggested in the original paper

Since the article was published, we have continued with this research, which has led us to discover two new ways to compromise the CA server (Certificate Authority) itself by abusing the ManageCA privilege. These attacks could be useful in different scenarios: 

  • When there are no certificate templates available for users that we can control, preventing the ESC6 and ESC7 attacks from being executed. 
  • In the circumstances where it is not possible to accomplish any of the attack scenarios proposed by SpecterOps, due to the impossibility of authenticating in the domain using certificates. We faced this problem in the engagement explained in our previous article
  • In any case where the target is the CA server and the information stored in it. 

As a result, in this article we expose the following methods to compromise a CA by abusing the CDP extension: 

  • Coerce the CA to authenticate to a remote server, opening the door to NTLM relay attacks, among others. 
  • Obtain remote code execution on the CA server by writing a webshell. 

Furthermore, we will release two new Certify modules to allow the automatic exploitation of these new attack vectors. 

Abusing CRL Distribution Points (CDP)

A CRL (Certificate Revocation List) is a file containing the identifiers of the certificates that have been revoked and are no longer valid. The CA must periodically publish the CRL in an accessible path, so the clients can check the validity of a certificate. This can be done by indicating one or more CDPs in its configuration:

CDP extension setup
CDP extension setup

When setting up a new CDP, we can specify either a local or remote path using several network protocols (HTTP, LDAP, FTP or SMB). Also, we must select if the CDP is used for reading, writing or both: 

  • CDP for reading (using the “Include in the CDP extension of issued certificates” option): the path will be added in the CDP extension of issued certificates, to indicate clients where to find a CRL. Only three protocols can be used to specify read CDPs, which are HTTP, FTP and LDAP.  
  • CDP for writing (through the option “Publish CRLs to this location“): a local or remote path where the CRL will be published. To specify a remote path, only LDAP and SMB protocols are supported, and the CA server must have write access to the provided remote location. 

Since a normal CRL contains the identifiers of all the revoked certificates prior to its publication (known as a Base CRL), the size of these files can increase considerably after a certain period of time, which can cause a significant network traffic growth due to the clients downloading them just to verify a single certificate. 

To optimize this process, a Delta CRL can be used, which will only contain the identifiers of the revoked certificates since the last CRL publication. Additionally, to ensure that the verifier finds the Delta CRLs, the CA allows to include their location inside the Base CRL file (using the “Include in CRLs” check). This option will be important when exploiting one of the attack vectors that we are going to discuss next. 

Coercing remote authentication

As we have already mentioned, it is possible to define in the CA a CDP for writing via the SMB protocol using the syntax file://remote.server/folder/file.crl. This allows to add a shared folder hosted on a remote machine as the publication path of a CRL, even if it is not part of the domain. This behavior makes sense since certificates may need to be verified beyond the limits of the Active Directory.  

If the shared folder requires authentication, the CA server will try to authenticate in order to access the folder (using NTLM or Kerberos, depending on whether the UNC path uses an IP or a hostname as its CDP). This means that a user with the ManageCA permission can retrieve a NTLM challenge from the server opening the door to NTLM relay attacks. Likewise, if you have in your control an account with Kerberos Unconstrained Delegation enabled, it would be possible to obtain a valid TGT for the CA server.  

Setup CDP to force a NTLM authentication against an arbitrary server
Setup CDP to force a NTLM authentication against an arbitrary server 

Since Microsoft published the MS16-075 patch, relaying a NTLM authentication to the same machine stopped being a possibility (even cross-protocol), so this primitive can’t be used to relay to the same CA’s web inscription service to request a new certificate (an attack path related to ESC8). However, if there are more CAs available in the environment, you can successfully relay to another CA’s web enrollment service and get a valid certificate for the vulnerable CA:  

ntlmrelaxy.py NTLM relay from one CA to another
NTLM relay from one CA to another 

While this case of abuse requires the presence of several CAs, we do not consider this to be uncommon in environments of significant size, where multiple CAs or SubCAs may coexist. 

This method for coercing authentication was also implemented as a new module (coerceauth) for Certify:  

Using Certify to force the CA server to authenticate against a remote IP
Using Certify to force the CA server to authenticate against a remote IP

After triggering the connection, this module will restore the previous configuration, to avoid leaving behind a non-existent CDP. 

Code execution via webshell deployment 

Since the recommended method for downloading and consuming CRLs is via the HTTP protocol, one of the hypotheses raised during the research was the abuse of CDPs to deploy webshells. Moreover, this assumption became even stronger when we realized that a CDP can write files with any extension, instead of the expected one (.crl). 

The main challenge was to reliably control some contents of the created file, especially since webshell code often uses problematic characters such as <, % or >.  

Our first approach was to request certificates with the malicious content inserted in different fields, hoping that when the certificates were revoked this information would be inserted into the CRL. However, we did not find any field in the certificates sufficiently large and malleable to be able to carry out this process. 

After multiple attempts, we recalled the previously mentioned option that allows us to add the path of a Delta CRL inside a Base CRL. We realized that this way it was possible to partially control the contents of the published CRLs. 

Using this feature, we can successfully deploy a webshell through the following steps:   

  • Create a first CDP to write a CRL in the desired path, adding the appropriate extension (e.g. .asp).   
  • Specify a second malicious CDP with the webshell payload as path, which would be inserted inside the CRL generated by the first CDP. 
Partial file write
Partial file write

As a first attempt, we tried to write a minimal ASP webshell in the local web directory C:\inetpub\wwwroot, which is created when installing any of the web roles available within the Active Directory Certificate Services (AD CS), as we will discuss later. 

Error when using the percentage symbol
Error when using the percentage symbol

When performing this test, we got an error due to the use of the % character when inserting our malicious CDP. This is because CDPs make use of a feature known as replacement tokens, which are strings composed by a percentage sign followed by an index number. Depending on this index, they are replaced with a different value, therefore allowing the creation of dynamic CDPs. 

If we compare the default CDPs of a CA with the value stored in the corresponding registry key (HKLM:\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\<CAName>\
CRLPublicationURLs), we can notice that, although the replacement tokens are stored in the registry, their value is dynamically replaced by the corresponding strings when the configuration is read by the CA. 

Correlation between default CDPs and values stored in the registry
Correlation between default CDPs and values stored in the registry

After reverse engineering the AD CS service process (certsrv.exe) we were able to identify that the certsrv.exe!myFormatCertsrvStringArray function generates an array with the replacement tokens values. Then, after calling certsrv.exe!myFormatMessageFromSource it ends up invoking the FormatMessageW function to generate the final path. Internally, this function is the one that performs the substitution of the replacement token occurrences by the corresponding values stored in the array. In addition, the CA also makes use of the InternetCanonicalizeUrlW function to complete the process of filtering and canonicalizing the inserted path. 

Snippet from the decompiled certsrv.exe!myFormatCertsrvStringArray function
Snippet from the decompiled certsrv.exe!myFormatCertsrvStringArray function

It is worth noting that the FormatMessageW function allows the use of format strings by using the %n!format string! syntax. We can acknowledge this behavior, for example, by printing in a CRL the memory address of the first element inside the array (e.g. %1!p!):   

Memory address printed using format string expansion
Memory address printed using format string expansion

While this could open the door to Format String Attacks or memory corruptions, we have not seen any way to introduce non-printable characters. That said, it is possible to cause a denial of service in the CA by specifying a CDP with a format string that expands to a size larger than 2^16 (e.g. %1!65536s!). 

After identifying the process of formatting and filtering URLs done by the CA, it will be necessary to escape certain special characters using % so that they do not disappear after the substitutions made by FormatMessageW. On the other hand, we also noticed that adding a line break (%n) at the beginning of the CDP bypasses part of the filtering performed by the InternetCanonicalizeUrlW function. 

Considering all the above, we decided to implement a new Certify module that allows to write an arbitrary file to a local or remote path through the CDP extension. We once again made use of the  ICertAdmin2::SetConfigEntry DCOM method to modify the value of the CRLPublicationURLs registry key: 

Using Certify to write a webshell using a local ASP file as input
Using Certify to write a webshell using a local ASP file as input

Also, if no input file is specified via the /input flag, a default ASP or PHP webshell is written depending on the extension of the destination path: 

Example of default webshell generated if no input file is specified
Example of default webshell generated if no input file is specified

This way, a user with the ManageCA permission gets the ability to perform an arbitrary file write on any local path on the CA server or on any remote path where that server has write permissions. Besides, we managed to partially control the content of this file as well as its extension, allowing us to obtain remote code execution through the deployment of a webshell. By default, the webshell is executed in the context of the Application Pool identity (DefaultAppPool user), so it is possible to elevate privileges to SYSTEM by abusing the SeImpersonate privilege. 

Likewise, it should be noted that the CA itself is responsible for writing the CRLs, which process is executed with NT AUTHORITY\SYSTEM privileges. This means that we can write to any local path and overwrite any file on the system. Although this could be used in other ways that we have not detected, the fact of not being able to completely control the content of the CRL and not being able to insert binary content reduces the chances of exploitation. Regardless, this attack vector could be used to remotely corrupt the CA server by overwriting system files. 

At this point, the major issue that we can face is the lack of a web server in the CA where to host our webshell. Therefore, we have verified in our lab that the installation of any of the different AD CS web roles includes the installation of an IIS server, where the default web directory is located at C:\inetpub\wwwroot.  

Depending on the installed roles, there will be support for ASP or ASPX files, and we can detect which ones are installed based on the available endpoints: 

AD CS paths

During our tests, we have detected that writing a webshell in C:\Windows\System32 is immediately detected by Windows Defender. 

If no web services are installed on the CA server, it might be possible that there is an already configured CDP pointing to an external web server, where a webshell could be written. This Microsoft article explains several scenarios in which the use of a separate server might be necessary, reason why the new Certify module allows to specify local or remote paths. 

To detect potential remote web directories where the CA is already publishing CRLs and consequently has write permissions, a /readonly flag has been added to the writefile command in order to read the CA’s list of CDPs without messing with them: 

Using Certify to list current CDP list
Using Certify to list current CDP list

Detection

In terms of detecting these attacks, the best option is to enable auditing of AD CS-related events as indicated in the original paper. Once enabled, we can monitor the following events:  

  • Event 4871 (“Certificate Services received a request to publish the certificate revocation list“): since the publication of CRLs is usually an automatic activity that occurs every certain time set in the CA configuration, the generation of this event outside those time periods may be an indicator of the malicious activity described in this article.  
  • Event 4872 (“Certificate Services published the certificate revocation list (CRL)“): analyzing the URL and extension of the CDP could allow to detect suspicious activity related to the writing of malicious CRL files.  
security Event 4872 generated when publishing a CRL
Event 4872, generated when publishing a CRL

Conclusion 

This second article dedicated to AD CS led us to discover new methods in which users with the ManageCA permission can compromise the CA server by leveraging the CDP extension.

On the other hand, we have added two new modules to Certify that allow the automatic exploitation of the attack vectors explained in this article. These features, as well as those published in the previous article, can be found in the BlackArrow repository

More articles in this series about AD CS

This article is part of a series of articles about AD CS

  1. AD CS: weaponizing the ESC7 attack
  2. AD CS: from ManageCA to RCE