============================================================================================================================================= | # Title : NetScaler 14.1 Vulnerability Scanner Assessment Tool | | # Author : indoushka | | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 145.0.1 (64 bits) | | # Vendor : https://www.netscaler.com/ | ============================================================================================================================================= POC : [+] References : https://packetstorm.news/files/id/212005/ & CVE-2025-6543 [+] Summary : CVE-2025-6543 is a critical vulnerability affecting Citrix NetScaler (ADC) appliances that allows remote code execution through improper input validation in the management interface. This scanner provides comprehensive assessment capabilities for identifying vulnerable NetScaler instances across multiple hosts and ports. [+] Affected Versions : - NetScaler ADC 14.1 before build 47.46 - NetScaler ADC 13.1 before build 59.19 - NetScaler ADC 13.1 FIPS before build 37.235 - NetScaler ADC 13.1 NDcPP before build 37.236 - NetScaler ADC 12.1 before build 55.328 [+] Vulnerability Description : The vulnerability exists in the management interface of Citrix NetScaler appliances where improper input validation allows attackers to execute arbitrary code. The issue stems from insufficient sanitization of user input in multiple components, leading to remote code execution with root privileges. [+] Technical Analysis : **Attack Vectors:** - SNMP service information disclosure - SSH management interface - Web management portal - API endpoints **Vulnerable Components:** - Management daemon (mgmtd) - SNMP service - SSH service configuration - Web interface handlers [+] Tool Features : **Scanning Capabilities:** - Multi-host concurrent scanning - Multi-port service detection - SNMP banner grabbing - SSH credential-based assessment - Build version extraction and analysis **Detection Methods:** php // SNMP Version Detection snmpget -v2c -c public 1.3.6.1.2.1.1.1.0 // SSH Version Detection ssh user@host "show version | head -n 6" // Build Version Regex Pattern /(?:NetScaler|NS).*?(?P\d+\.\d+)(?:[-_](?P\d+)\.(?P\d+))?(?:[-_](?PFIPS|NDCPP))?/i [+] Usage : php poc.php [+] POC : [47, 46], "13.1" => [59, 19], "13.1FIPS" => [37, 235], "13.1NDCPP" => [37, 236], "12.1" => [55, 328], ]; private $bannerRegex = '/(?:NetScaler|NS).*?(?P\d+\.\d+)(?:[-_](?P\d+)\.(?P\d+))?(?:[-_](?PFIPS|NDCPP))?/i'; public function __construct($verbose = false) { $this->verbose = $verbose; } private function log($message) { if ($this->verbose) { echo "[DEBUG] " . $message . PHP_EOL; } } private function parseBuild($text) { if (preg_match($this->bannerRegex, $text, $matches)) { $branch = $matches['branch'] ?? ''; $buildMajor = isset($matches['build_major']) ? (int)$matches['build_major'] : 0; $buildMinor = isset($matches['build_minor']) ? (int)$matches['build_minor'] : 0; $tag = $matches['tag'] ?? ''; $key = $branch . $tag; return [$key, [$buildMajor, $buildMinor]]; } return null; } private function isVulnerable($key, $build) { if (!isset($this->safeBuilds[$key])) { return true; } $safeBuild = $this->safeBuilds[$key]; return $build[0] < $safeBuild[0] || ($build[0] == $safeBuild[0] && $build[1] < $safeBuild[1]); } private function isPortOpen($host, $port, $timeout = 2) { $this->log("Checking TCP $host:$port"); $socket = @fsockopen($host, $port, $errno, $errstr, $timeout); if ($socket) { fclose($socket); $this->log("Open $host:$port"); return true; } else { $this->log("Closed $host:$port: $errstr"); return false; } } private function snmpBanner($host, $community = 'public', $timeout = 3) { $this->log("SNMP grab $host (community=$community)"); $command = "snmpget -v2c -c " . escapeshellarg($community) . " -Oqv " . escapeshellarg($host) . " 1.3.6.1.2.1.1.1.0 2>/dev/null"; $output = shell_exec($command); $banner = trim($output ?? ''); $this->log("SNMP banner: $banner"); return $banner; } private function cliBanner($host, $user, $password) { $this->log("SSH grab $host (user=$user)"); // Using sshpass for password authentication $command = "sshpass -p " . escapeshellarg($password) . " ssh -o BatchMode=yes -o StrictHostKeyChecking=no -o ConnectTimeout=5 " . escapeshellarg("$user@$host") . " 'show version | head -n 6' 2>/dev/null"; $output = shell_exec($command); $banner = trim($output ?? ''); $this->log("SSH banner: $banner"); return $banner; } private function exploitProbe($host, $port) { $this->log("Exploit stub $host:$port"); echo "[i] $host:$port - exploit probe not implemented" . PHP_EOL; } public function checkHostPort($host, $port, $options, $outputHandle = null) { // Check port reachability if (!$this->isPortOpen($host, $port)) { echo "[!] $host:$port - unreachable" . PHP_EOL; return; } $banner = ''; $origin = ''; // Try SNMP first if ($options['snmp']) { $banner = $this->snmpBanner($host, $options['community']); $origin = 'SNMP'; } // Try SSH if SNMP failed and credentials provided if (empty($banner) && !empty($options['ssh_user']) && !empty($options['ssh_pass'])) { $banner = $this->cliBanner($host, $options['ssh_user'], $options['ssh_pass']); $origin = 'SSH'; } if (empty($banner)) { echo "[?] $host:$port - no banner" . PHP_EOL; return; } $parsed = $this->parseBuild($banner); if (!$parsed) { echo "[?] $host:$port - unknown banner" . PHP_EOL; return; } list($key, $build) = $parsed; $state = $this->isVulnerable($key, $build) ? "VULNERABLE ⚠️" : "PATCHED ✅"; echo "[$state] $host:$port -> $key {$build[0]}.{$build[1]} via $origin" . PHP_EOL; // Write to CSV if output file specified if ($outputHandle) { fputcsv($outputHandle, [ $host, $port, $key, "{$build[0]}.{$build[1]}", $state ]); } // Run exploit probe if vulnerable and requested if ($options['exploit'] && $state === "VULNERABLE ⚠️") { $this->exploitProbe($host, $port); } } public function scan($hosts, $ports, $options) { $outputHandle = null; // Open output file if specified if (!empty($options['output'])) { $outputHandle = fopen($options['output'], 'w'); if ($outputHandle) { fputcsv($outputHandle, ['host', 'port', 'branch', 'build', 'state']); } else { echo "[!] Cannot open output file: {$options['output']}" . PHP_EOL; return false; } } $totalHosts = count($hosts); $currentHost = 0; foreach ($hosts as $host) { $currentHost++; echo "[Progress] Scanning host $currentHost/$totalHosts: $host" . PHP_EOL; foreach ($ports as $port) { $this->checkHostPort($host, $port, $options, $outputHandle); } } if ($outputHandle) { fclose($outputHandle); echo "[i] Results saved to: {$options['output']}" . PHP_EOL; } return true; } } // Command line argument parser function parseArguments() { $options = [ 'verbose' => false, 'hosts' => [], 'ports' => [], 'community' => 'public', 'snmp' => true, 'ssh_user' => '', 'ssh_pass' => '', 'exploit' => false, 'output' => '' ]; $shortopts = "vH:f:p:P:c:o:x"; $longopts = [ "verbose", "hosts:", "file:", "port:", "ports-file:", "community:", "no-snmp", "ssh-user:", "ssh-pass:", "exploit", "output:", "help" ]; $parsed = getopt($shortopts, $longopts); if (isset($parsed['help']) || isset($parsed['h'])) { showHelp(); exit(0); } // Verbose mode $options['verbose'] = isset($parsed['v']) || isset($parsed['verbose']); // Hosts input if (isset($parsed['H']) || isset($parsed['hosts'])) { $hosts = isset($parsed['H']) ? $parsed['H'] : $parsed['hosts']; $options['hosts'] = is_array($hosts) ? $hosts : [$hosts]; } elseif (isset($parsed['f']) || isset($parsed['file'])) { $file = isset($parsed['f']) ? $parsed['f'] : $parsed['file']; if (file_exists($file)) { $options['hosts'] = array_filter( array_map('trim', file($file)), function($line) { return !empty($line); } ); } else { echo "[!] Host file not found: $file" . PHP_EOL; exit(1); } } else { echo "[!] Either --hosts or --file must be specified" . PHP_EOL; exit(1); } // Ports input if (isset($parsed['p']) || isset($parsed['port'])) { $port = isset($parsed['p']) ? $parsed['p'] : $parsed['port']; $options['ports'] = [(int)$port]; } elseif (isset($parsed['P']) || isset($parsed['ports-file'])) { $file = isset($parsed['P']) ? $parsed['P'] : $parsed['ports-file']; if (file_exists($file)) { $options['ports'] = array_filter( array_map(function($line) { $line = trim($line); return is_numeric($line) ? (int)$line : null; }, file($file)), function($port) { return $port !== null; } ); } else { echo "[!] Ports file not found: $file" . PHP_EOL; exit(1); } } else { echo "[!] Either --port or --ports-file must be specified" . PHP_EOL; exit(1); } // Other options if (isset($parsed['c']) || isset($parsed['community'])) { $options['community'] = isset($parsed['c']) ? $parsed['c'] : $parsed['community']; } $options['snmp'] = !(isset($parsed['no-snmp'])); if (isset($parsed['ssh-user'])) { $options['ssh_user'] = $parsed['ssh-user']; } if (isset($parsed['ssh-pass'])) { $options['ssh_pass'] = $parsed['ssh-pass']; } $options['exploit'] = isset($parsed['x']) || isset($parsed['exploit']); if (isset($parsed['o']) || isset($parsed['output'])) { $options['output'] = isset($parsed['o']) ? $parsed['o'] : $parsed['output']; } return $options; } function showHelp() { echo "CVE-2025-6543 NetScaler Vulnerability Scanner - PHP Version" . PHP_EOL . PHP_EOL; echo "Usage: php netscaler_scanner.php [OPTIONS]" . PHP_EOL . PHP_EOL; echo "Options:" . PHP_EOL; echo " -H, --hosts HOSTS Space-separated list of hosts" . PHP_EOL; echo " -f, --file FILE File with one host per line" . PHP_EOL; echo " -p, --port PORT Single TCP port to test" . PHP_EOL; echo " -P, --ports-file FILE File with one port per line" . PHP_EOL; echo " -c, --community STRING SNMP community (default: public)" . PHP_EOL; echo " --no-snmp Disable SNMP checking" . PHP_EOL; echo " --ssh-user USER SSH username" . PHP_EOL; echo " --ssh-pass PASS SSH password" . PHP_EOL; echo " -x, --exploit Run exploit probe on vulnerable hosts" . PHP_EOL; echo " -o, --output FILE Write CSV results to file" . PHP_EOL; echo " -v, --verbose Enable verbose output" . PHP_EOL; echo " --help Show this help message" . PHP_EOL . PHP_EOL; echo "Examples:" . PHP_EOL; echo " php netscaler_scanner.php -H 192.168.1.100 192.168.1.101 -p 161 -v" . PHP_EOL; echo " php netscaler_scanner.php -f hosts.txt -P ports.txt --ssh-user admin --ssh-pass password" . PHP_EOL; echo " php netscaler_scanner.php -H 10.0.0.1 -p 22 -x -o results.csv" . PHP_EOL; } // Main execution if (php_sapi_name() === 'cli') { $options = parseArguments(); $scanner = new NetScalerVulnerabilityScanner($options['verbose']); $success = $scanner->scan($options['hosts'], $options['ports'], $options); if ($success) { echo "[+] Scan completed successfully" . PHP_EOL; } else { echo "[!] Scan completed with errors" . PHP_EOL; exit(1); } } else { echo "This script must be run from the command line." . PHP_EOL; exit(1); } ?> Greetings to :===================================================================================== jericho * Larry W. Cashdollar * LiquidWorm * Hussin-X * D4NB4R * Malvuln (John Page aka hyp3rlinx)| ===================================================================================================