While writing my latest post, my attention was also drawn to the Cert Publishers group, which is associated with the Certificate service (ADCS) in an Active Directory Domain.
I was wondering about the purpose of this group and what type of permissions were assigned to its members. I was also curious to understand if it was possible to exploit this membership to acquire the highest privileges within a domain. By default, this group contains the computer accounts hosting the Certification Authority and Sub CA. It is not clear whether this group should be considered really highly privileged, and I have not found any documentation of potential abuse. For sure, CA and SubCA Windows servers should be considered highly privileged, even just for the fact that they can do backups of the CA keys…
Last but not least, Microsoft does not protect this group by AdminSDHolder:
What is the purpose of Cert Publishers?
Microsoft’s official documentation on this group is not very clear nor exhaustive:
“Members of the Cert Publishers group are authorized to publish certificates for User objects in Active Directory.“
What does this mean? Members of the group have write access to the userCertificate attribute of users and computers and this permission is also controlled by the AdminSDholder configuration:
The userCertificate attribute is a multi-valued attribute that contains the DER-encoded X509v3 certificates issued to the user. The public key certificates issued to this user by the Microsoft Certificate Service are stored in this attribute if the “Publish to Active Directory” is set in the Certificate Templates, which is the default for several certificate templates:
Should you accept this default setting? In theory, this would be useful when using Email Encryption, Email Signing, or Encrypted Files System (EFS). I see no other reason and if you don’t need it remove this flag
From the security perspective, as far as I know, no reasonable path could permit an attacker to elevate the privileges by altering the certificates stored in this attribute.
There could be in theory a denial of service attack by adding a huge amount of certificates to the attribute to create replication issues between DC’s, but in my tests, I was not able to reproduce this given that there seems to be a hard limit of around 1200 certificates (or maybe a limit on the size), at least in a Windows AD 2016.
So if you really need this attribute, at least check “Do not automatically reenroll..” which will prevent uncontrolled growth of this attribute.
Is there anything else they can do? Yes!
Permissions granted to cert Publishers in Configuration Partition
Cert Publishers have control over some objects located under the “Public Key Services” container of Configuration Partition of AD:
- CN=AIA,CN=Public Key Services,CN=Services,CN=Configuration,DC=…
Authority Information Access (AIA) is used to indicate how to access information and services related to the issuer of the certificate.
“This container stores the intermediate CA and cross-certificates. All certificates from this container are propagated to each client in the Intermediate Certification Authority certificates store via Group Policy.“
Cert Publishers have full control over it, so they can create new entries with fake certificates via certutil or adsiedit, for example:
certutil -dspublish -f fakeca.crt subCA (sub CA) certutil -dspublish -f fakeca.crt crossCA (cross CA)
But the resulting published fake certificates in the intermediate CA will not be trusted due to missing root CA, so probably that is not useful…
We have also to keep in mind that Cert Publishers cannot modify the original AIA object created during the installation of the CA:
- CN=[CA_NAME],CN=CDP,CN=Public Key Services,CN=Services,CN=Configuration,DC= …
Certificate Revocation List Distribution Point (CDP) provides information on where to find the CRL associated with the certificate.
Members of Cert Publishers have full control over this container and subsequent objects. But what’s the purpose of this container in ADCS?
“This container is used to store certificate revocation lists (CRL). To differentiate CRLs a separate container is created for each CA. Typically CA host NetBIOS name is used. CRLs from CDP containers are NOT propagated to clients and is used only when a certificate refers to a particular CRLDistributionPoint entry in CDP container.”
Members could overwrite attributes of the existing object, especially the certificateRevocationList and deltaRevocationList attribute with a fake one or just remove it. However given that these configurations are not replicated to clients, these permissions are not very useful from an attacker’s perspective.
It’s worth noting that Cert Publishers cannot modify the extensions relative to AIA/CDP configuration of the CA server:
- CN=[CA_NAME],CN=Certification Authorities,CN=Public Key Services,CN=Services,CN=Configuration,DC=..
This container stores trusted root certificates. The root certificate of the CA server is automatically placed inside and the certificates will be published (via GP) under the trusted root certification authorities.
While Cert Publishers have full control over the CA_NAME object, they are unable to add other certification authority objects. This restriction is probably in place to mitigate the risk of a malicious user, who is a member of the group, from publishing fake CA certificates. Such fake certificates could potentially be trusted by all clients. Hence, what are the potential abuse scenarios to consider?
Abusing the Certification Authorities object
My objective was to explore potential workarounds to have my fake Certificate Authority (CA) published and accepted as trustworthy by all clients, despite the established limitations.
Following various tests, where I attempted to substitute the existing certificate stored in the caCertificate attribute of the CA object with a fake one or add to the current caCertificate a fake certificate (without success, as the fake CA was not published), I eventually identified a solution that circumvents the existing ‘safety’ (or should we say ‘security’?) boundary. Why just not creating a fake one with the exact same common name as the official CA? If it works as expected, it would be appended to the existing CA’s configuration…
Creating a fake self-signed CA with the openssl tool is fairly straightforward, I won’t go into details as I already explained this in my previous post.
The provided common name matches the name of our official CA.
After obtaining the certificate, we will log in to the AD domain using the credentials of a user who is a member of Cert Publishers and proceed to add the certificate to the Certification Authorities container
We can safely ignore the error, and with adsiedit we can confirm that the certificate was added:
Let’s see if it works, but instead of waiting for the GPO refresh, we manually perform a gpupdate /force and look in the certificates of the local computer/user:
Bingo! We now have our fake Certificate Authority (CA) established as a trusted entity. To confirm its functionality, we’ll configure a web server with an SSL certificate issued by our CA.
In my instance, I used an IIS web server and requested an SSL certificate (you can do this in many different ways..) using the Certificates snap-in (I’ll omit some steps, as there is a huge documentation available on how to accomplish this)
Once we get our csr file (evil.csr), we need to setup the CA configuration for the CRL endpoints and certificate signing.
default_ca = EVILCA
dir = ./
new_certs_dir = $dir
unique_subject = no
certificate = ./evilca.crt
database = ./certindex
private_key = ./evilca.key
serial = ./certserial
default_days = 729
default_md = sha1
policy = myca_policy
x509_extensions = myca_extensions
crlnumber = ./crlnumber
default_crl_days = 729
default_md = sha256
copy_extensions = copy
commonName = supplied
stateOrProvinceName = optional
countryName = optional
emailAddress = optional
organizationName = supplied
basicConstraints = CA:false
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always
keyUsage = digitalSignature,keyEncipherment
extendedKeyUsage = serverAuth
crlDistributionPoints = URI:http://192.168.1.88/root.crl
Run the usual commands:
openssl genrsa -out cert.key 2048 openssl req -new -key cert.key -out cert.csr touch certindex echo 01 > certserial echo 01 > crlnumber openssl ca -batch -config ca.conf -notext -in cert.csr -out cert.crt openssl pkcs12 -export -out cert.p12 -inkey cert.key -in cert.crt -chain -CAfile evilca.crt openssl ca -config ca.conf -gencrl -keyfile evilca.key -cert evilca.crt -out rt.crl.pem openssl crl -inform PEM -in rt.crl.pem -outform DER -out root.crl
We are now ready to process the certificate request:
And import the evil.crt on our webserver. From a domain joined machine, we try to navigate to https://myevilserver.mylab.local:
As expected, the site is trusted by our fake CA.
With forged trusted certificate could empower a malicious actor to execute various attacks, potentially resulting in the compromise of the entire domain by enrolling any type of certificates which will be then trusted…
While not an expert on these abuses, the following are initial considerations:
- Man in the middle (MITM) attacks such as SSL inspection to decrypt all the traffic
- Code signing of malicious enterprise applications or script
- Server authentication, VPN,…
But let’s go a set further. Remember my so-called Silver Certificate?
To be able to (ab)use a forged client certificate for authentication, via PKINIT or Schannel, the CA also has to present in NTAuthcertificates store.
Let’s consider the scenario where the Cert Publishers group is granted write access to the NTAuthcertificates object. While not the default setting, I’ve encountered a couple of real-world scenarios where this (mis)configuration was implemented. This transforms the original situation described in my previous post, by having only write permission on NTAuthcertificates, from a mere persistence technique to a genuine privilege escalation. This shift is noteworthy, especially considering that we already have a trusted Certificate Authority at our disposal, enabling the forging of client certificates.
All we need at this point is to add our fake CA certificate to the NTAuthcertificates object (assuming Cert Publishers have been granted this permission)
Let’s wait for the GP refresh on the Domain Controllers and then proceed as usual using for example the certipy tool:
certipy forge -ca-pfx evilca.pfx -upn [email protected] -subject 'CN=Administrator,CN=Users,DC=mylab,DC=local' -crl 'http://192.168.1.88/root.crl' certipy auth -pfx administrator_forged.pfx -dc-ip 192.168.212.21
And get the expected result!
At the end of our experiments, we can derive the following conclusions:
- Members of Cert Publishers can add a malicious Certification Authority under the control of an ADCS environment and subsequently be trusted by all the clients. While certificates issued under this CA will not be automatically trusted for client authentication via PKINIT or SChannel, they could still be abused for other malicious tasks.
- Cert Publishers membership + write access to NTAuthcertificates is the most dangerous mix in these scenarios. You can then forge and request a certificate, the Silver++ , for client authentication against any user in the domain.
- Cert Publishers should be considered High-Value Targets (or Tier-0 members), and membership in this group should be actively monitored, along with possible attack paths originating from non-privileged users leading to this group.