Contents

Golden Certificate and OCSP

Almost everybody in the security industry turned their head to Active Directory Certificate Authorities after Lee Christensen (@tifkin_) and Will Schroeder (@harmj0y) published their whitepaper “Certified Pre-Owned: Abusing Active Directory Certificate Services”.

Their work threw the light on the risks that the operation of a PKI solution brings with it. Especially in Active Directory integrated environments, there is great risk through the tight integration of certificates and authentication.

Golden certificate

In this blog, I want to discuss one mitigation technique for the attack DPERSIST1 better known as “golden certificate”.

This attack describes the method of establishing persistence and possible DA (domain admin) in the environment through the means of stealing the private key of the online certificate authority. As you might correctly say: If this scenario will happen, you are screwed.

But it’s not an improbable risk and in many cases, you will not recognize it when it happened.

Possible scenarios are

  • Local Admin permission on the CA
  • Access to an unencrypted backup of the CA server

If the private key material is not protected through a hardware security module (HSM) it’s easy to export the certificate. You can use the built-in backup functionality of the CA or leverage mimikatz. More on that is described in the whitepaper under THEFT3.

If you are in possession of this key you can self sign your own certificates. And because you signed those certificates and not the Online CA, there will be no trace in any CA audit log or the CA database.

The missing entry in the CA database makes revoking such certificates even harder. How can you revoke something you don’t know nothing about?

Certificate Revocation Lists (CRLs)

First, let’s have a look on how CRLs work and why they are no help in this attack scenario.

When you revoke a certificate the serial number of the certificate is written in the CRL or delta CRL. You can either manually update the CRL after you revoked the certificate or wait until the CA service will do this on its own schedule.

/en/golden-certificate-ocsp/images/CRLSerialNumbers.png

When you manually publish a new CRL you have to rely on the client to download the latest version of the CRL or/and Delta CRL, check the serial number of the certificate against the serial numbers in the CRL file, and act accordingly.

This process of revoking a certificate can be very slow. Even if you publish a new Delta CRL, most of your clients won’t check if there is a new one until

  • the next publish date is due
  • the next update date is due
  • the cached CRL is manually deleted

/en/golden-certificate-ocsp/images/CRLInformation.png

Depending on your configuration this can take from a few days to up to a week.

And because you don’t know the serial number of the issued certificate you can’t revoke it in the first place. Also the attacker could just create a new one with a new serial number. This is where the Online Certificate Status Protocol (OCSP) comes into the picture. This protocol was meant to simplify the revocation process.

To manually clear the disk cache use certutil -urlcache crl delete

To also clear the memory cache certutil -setreg chain\ChainCacheResyncFiletime @now

Online Certificate Status Protocol (OCSP)

OCSP relies on short lived signing certificates, that are used to securely answer the question: Is this specific certificate valid?

The certificate that is used to sign the response has no revocation information and also contains the certificate extension “OCSP No revocation checking”. Also you can configure how often the OCSP responder should update the CRL information, even if the CRL is still valid and has not reached its validity date.

/en/golden-certificate-ocsp/images/OCSP-certificate.png

There are different ways in how OCSP information can reach the client.

  • OCSP stapling
    In this case, e.g. a web service requests a OCSP response and sends it to the client when the client is connecting to it. This method is not relevant in our case.
  • OCSP request
    The client itself (Domain Controller) reaches out to the OCSP server and asks if the certificate is valid.

/en/golden-certificate-ocsp/images/OCSP.png

The OCSP request method is interesting for our use case because

  1. The attacker creates a certificate and tries to create a krbtgt ticket
  2. The Domain Controller asks the OCSP server if the certificate is valid
  3. The OCSP server answers that this serial number was not signed by the certificate authority everything is Okay
  4. The Domain Controller denies gives access

The reason why the outcome in the default configuration is not different from the CRL approach is because

  • the OCSP responder only checks the CRL
  • Microsoft has not activated or even actively promoted the secure way by default

IssuedSerialNumbersDirectories

But there is a rather unknown configuration option in the OCSP responder configuration that allows the OCSP responder to be smarter. It was introduced into Windows Server 2008 R2 and 2012 R2 by means of an additional hotfix. Windows Server 2016 and 2019 have the functionality built-in but the only way to configure it is through a registry key and a manual script.

The additional feature introduces a third possible answer to an OCSP request

Answer
GOOD Everything is great, go ahead
REVOKED This certificate is revoked. You shall not pass!
UNKNOWN This certificate is unknown to the certificate authority

To transfer every known and valid serial number between the CA and the OCSP responder Microsoft is using advanced technology. A shared folder.

This folder contains files with no content whatsoever, but the name of each file is equal to a valid certificate serial number. Hence the name IssuedSerialNumbersDirectories.

/en/golden-certificate-ocsp/images/IssuedSerialNumbersDirectories.png

With this configuration applied it is no longer as easy to sign in with a forged certificate

  1. The attacker creates a certificate and tries to create a krbtgt ticket
  2. The Domain Controller asks the OCSP server if the certificate is valid
  3. The OCSP server checks if there is a file named exactly as the serial number in the issued serial numbers directory
  4. The OCSP server answers that this serial number was not signed by the certificate authority
  5. The Domain Controller denies access

/en/golden-certificate-ocsp/images/OCSP-IssuedSerialNumbersDirectories.png

Configuration

I will not cover the complete installation and configuration of an OCSP responder, but will show you what you have to do to add this feature to an existing OCSP responder. Also I assume you have configured auditing on your online CA.

Warning
Test this configuration in you test environment first. This configuration changes how you domain controllers check certificates and it could break smartcard authentication for everybody if not implemented correctly. Also check if you current high availability concept for the OCSP array is still sufficient.

Certificate authority

The serial numbers of all valid certificates have to be exported on a regular basis. Failing so will block out valid certificates, because the OCSP responder cannot validate them. Microsoft provides a basic script, that I extended a bit.

I added the parameters CAName and Mode.

CAName allows you to specify the CA which you want to target, which allows the script to be execute on a different server.

Mode has to possible values. Full which deletes the complete folder content and recreates it. This process can be a bit slow on big CA databases and should only be performed off hours. The other option DeltaAdd creates only new files for all certificates issued in the last hour.

Example:

#> C:\OCSPValidation\OCSPCertValidation.ps1 -Path C:\OCSPValidation\ValidCerts -CAName "CA01.lab.bader.cloud\LAB-SINGLE-CA" -Mode Full

  1. Copy the script to your CA and create a folder where you want to place the serial number files.
  2. Create two scheduled tasks
    • Time based trigger that executes the Full mode sometimes out of office hours to recreate the whole folder content.
    • Event log trigger based on event Id 4887 to run in DeltaAdd mode. This way every time a new certificate is issued the necessary file is created. This is much better than doing it every few minutes.
  3. Start the script in Full mode
  4. Publish the folder and restrict access to read only for the computer accounts of your OCSP responder servers.

OCSP responder

Create a registry value of type “Multi String Value” and name IssuedSerialNumbersDirectories in the key HLKM:\SYSTEM\CurrentControlSet\Services\OcspSvc\Responder\<OCSPResponderName>\Provider.

Edit the value data and change it to your shared folder.

/en/golden-certificate-ocsp/images/registry-config.png

Restart the OCSP service.

New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\OcspSvc\Responder\<OCSPResponderName>\Provider" -Name 'IssuedSerialNumbersDirectories' -PropertyType MultiString -Value "C:\OCSPValidation\ValidCerts"
Restart-Service ocspsvc

You can check if the configuration was activated by using Process Monitor and filter on the path or the ocspsvc.exe

/en/golden-certificate-ocsp/images/ProcMonFileAccess.png

Now your OCSP responder will check every time a request comes in, and the request is not already cached, if a file with this serial number is present.

/en/golden-certificate-ocsp/images/ProcMonCheck.png

Domain Controller

Because Windows defaults to CRL usage after 50 cached OCSP responses (the magic count, really!) we have to pin the Domain Controllers to OCSP usage.

This can be done via group policy.

  1. Create a new GPO that is only applied to your Domain Controllers and import the public certificate of the online CA under “Computer” - “Policies” - “Windows Settings” - “Security Settings” - “Public Key Policies”. Choose “Trusted Root CA” or “Intermediate CA” based on your CA design.
  2. Select the imported certificate and switch to “Details” - “Edit Properties” - “OCSP”
  3. Check “Disable Certificate Revocation Lists (CRL)”
  4. Add your OCSP responder URL

After this configuration is deployed and the servers have rebooted, they will only use the defined OCSP responder service for certificate verification. The certificate that is being validated does not necessarily have to contain the OCSP information. As you will see this is important, otherwise the attacker could just omit this information.

/en/golden-certificate-ocsp/images/GPO.png

Info
Microsoft states that the cache size for about 50,000 users which use smart-card authentication is about 100 MB. Each OCSP response is about 2 kilobytes in size.

Testing

Default behavior

Create a forged certificate with ForgeCert

ForgeCert.exe --CaCertPath "C:\Users\Fabian\Desktop\LAB-SINGLE-CA.p12" --CaCertPassword Pa$$word --Subject CN=tako --SubjectAltName takeshi.kovacs@lab.bader.cloud --NewCertPath "C:\Users\Fabian\Desktop\tako2.pfx" --NewCertPassword Pa$$word --CRL http://cdp.lab.bader.cloud/certenroll/LAB-SINGLE-CA.crl

/en/golden-certificate-ocsp/images/ForgeCert.png

Now use the new Rubeus to create a new cmd.exe and ask for a Kerberos Ticket (krbtgt) using the created certificate. I did this on a workgroup joined workstation that had no relation to the domain.

Rubeus.exe asktgt /user:LAB\tako /certificate:C:\Users\Fabian\Desktop\tako.pfx /password:Pa$$word /createnetonly:C:\Windows\System32\cmd.exe /servicekey:KRBTGTKEY /show /domain:lab.bader.cloud /dc:dc01.lab.bader.cloud

As you can see the login is successful, I hold a valid krbtgt and can query addition TGTs all because the OCSP responder returns GOOD in response to the query by the domain controller.

/en/golden-certificate-ocsp/images/Rubeus-good.png

Info
Please note that I created this screenshot outside of the VM and the Wireshark windows is not running in the VM. The OCSP query and response are done by the domain controller, not the client itself.

Deterministic OCSP

Now apply the described configuration to your environment, clear the CRL and OCSP cache on the DC and try again.

Warning
KDC_ERR_CLIENT_NOT_TRUSTED

The OCSP responder now answers the response with an value of UNKNOWN in which case the domain controller rejects the login attempt. No krbtgt is created by the domain controller.

/en/golden-certificate-ocsp/images/Rubeus-unknown.png

In the CAPI logs (not enabled by default) on the domain controller you can monitor this behavior without doing a network trace. The initiating process of the query is lsass.exe.

/en/golden-certificate-ocsp/images/CAPI-OCSP-Request.png

/en/golden-certificate-ocsp/images/CAPI-OCSP-Response.png

What about the magic count

As I wrote earlier in the default behavior the Windows OS would fall back to using the CRL after 50 OCSP queries to the same OCSP responder. This might make sense for performance, but we are more concerned about the security.

But since we disabled CRL checking for this certificate authority on the domain controllers completely Windows does not fall back to CRL.

I check this by lowering the number to 5 on the domain controllers.

/en/golden-certificate-ocsp/images/OCSP-magiccount-configuration.png

Than I created six forged certificates and tried to login with all six.

/en/golden-certificate-ocsp/images/OCSP-magicnumber.png

The login was not possible with all six certificates and the network trace showed that the domain controller queried all six certificates against the OCSP responder.

Final thoughts

This method is not bulletproof at all. Since the attacker is in charge of the certificate creation process, she could just change the serial number to a valid one. Since the serial number is public information this is not hard. The easiest way to do this is by checking the domain controllers LDAPS certificate and using this serial number, as Benjamin Delpy (@gentilkiwi) pointed out

openssl s_client -connect dc01.lab.bader.cloud:636 < nul | openssl x509 -noout -text

/en/golden-certificate-ocsp/images/serialnumber.png

Currently neither mimikatz nor ForgeCert posses this capability, but I created a pull request to add this capability.

But even with this flaw, this configuration adds an additional layer of security and makes it a bit harder for the attacker.

Also does it allow for more timely revocation of a valid smart card certificate since the OCSP responder checks the CRL more often.

UPDATE

I created a PR to add this capability.

You first have to convert the serial number to a big integer. This can can be done via PowerShell.

[bigint]::Parse("4d0000000ab586afdc0ea9304d00000000000a",'AllowHexSpecifier')

With this number you can create your custom tailored certificate.

/en/golden-certificate-ocsp/images/ForgeCertUpdate.png

Attribution

A big shout-out to @tifkin_ and @harmj0y for creating the whitepaper and releasing the tools.

Also a big thank you to Jim Sykora @JimSycurity who’s question on Twitter lead to this blog post.