Skip to content

Instantly share code, notes, and snippets.

@ftkro
Created March 27, 2015 17:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ftkro/a3642d9c4029d215cb87 to your computer and use it in GitHub Desktop.
Save ftkro/a3642d9c4029d215cb87 to your computer and use it in GitHub Desktop.
おーと☆でぷでぷ
<?php
/* Thanks: Many Website & Developer
BEGIN of Net-SSH2 */
define('NET_SSH2_MASK_CONSTRUCTOR', 0x00000001); define('NET_SSH2_MASK_CONNECTED', 0x00000002); define('NET_SSH2_MASK_LOGIN_REQ', 0x00000004); define('NET_SSH2_MASK_LOGIN', 0x00000008); define('NET_SSH2_MASK_SHELL', 0x00000010); define('NET_SSH2_MASK_WINDOW_ADJUST', 0x00000020); define('NET_SSH2_CHANNEL_EXEC', 0); define('NET_SSH2_CHANNEL_SHELL', 1); define('NET_SSH2_CHANNEL_SUBSYSTEM', 2); define('NET_SSH2_LOG_SIMPLE', 1); define('NET_SSH2_LOG_COMPLEX', 2); define('NET_SSH2_LOG_REALTIME', 3); define('NET_SSH2_LOG_REALTIME_FILE', 4); define('NET_SSH2_READ_SIMPLE', 1); define('NET_SSH2_READ_REGEX', 2); define('NET_SSH2_LOG_MAX_SIZE', 1024 * 1024); class Net_SSH2 { var $identifier; var $fsock; var $bitmap = 0; var $errors = array(); var $server_identifier = false; var $kex_algorithms = false; var $server_host_key_algorithms = false; var $encryption_algorithms_client_to_server = false; var $encryption_algorithms_server_to_client = false; var $mac_algorithms_client_to_server = false; var $mac_algorithms_server_to_client = false; var $compression_algorithms_client_to_server = false; var $compression_algorithms_server_to_client = false; var $languages_server_to_client = false; var $languages_client_to_server = false; var $encrypt_block_size = 8; var $decrypt_block_size = 8; var $decrypt = false; var $encrypt = false; var $hmac_create = false; var $hmac_check = false; var $hmac_size = false; var $server_public_host_key; var $session_id = false; var $exchange_hash = false; var $message_numbers = array(); var $disconnect_reasons = array(); var $channel_open_failure_reasons = array(); var $terminal_modes = array(); var $channel_extended_data_type_codes = array(); var $send_seq_no = 0; var $get_seq_no = 0; var $server_channels = array(); var $channel_buffers = array(); var $channel_status = array(); var $packet_size_client_to_server = array(); var $message_number_log = array(); var $message_log = array(); var $window_size = 0x7FFFFFFF; var $window_size_server_to_client = array(); var $window_size_client_to_server = array(); var $signature = ''; var $signature_format = ''; var $interactiveBuffer = ''; var $log_size; var $timeout; var $curTimeout; var $realtime_log_file; var $realtime_log_size; var $signature_validated = false; var $realtime_log_wrap; var $quiet_mode = false; var $last_packet; var $exit_status; var $request_pty = false; var $in_request_pty_exec = false; var $in_subsystem; var $stdErrorLog; var $last_interactive_response = ''; var $keyboard_requests_responses = array(); var $banner_message = ''; var $is_timeout = false; var $log_boundary = ':'; var $log_long_width = 65; var $log_short_width = 16; var $host; var $port; var $connectionTimeout; var $windowColumns = 80; var $windowRows = 24; function Net_SSH2($host, $port = 22, $timeout = 10) { if (!class_exists('Math_BigInteger')) { include_once 'Math/BigInteger.php'; } if (!function_exists('crypt_random_string')) { include_once 'Crypt/Random.php'; } if (!class_exists('Crypt_Hash')) { include_once 'Crypt/Hash.php'; } $this->message_numbers = array( 1 => 'NET_SSH2_MSG_DISCONNECT', 2 => 'NET_SSH2_MSG_IGNORE', 3 => 'NET_SSH2_MSG_UNIMPLEMENTED', 4 => 'NET_SSH2_MSG_DEBUG', 5 => 'NET_SSH2_MSG_SERVICE_REQUEST', 6 => 'NET_SSH2_MSG_SERVICE_ACCEPT', 20 => 'NET_SSH2_MSG_KEXINIT', 21 => 'NET_SSH2_MSG_NEWKEYS', 30 => 'NET_SSH2_MSG_KEXDH_INIT', 31 => 'NET_SSH2_MSG_KEXDH_REPLY', 50 => 'NET_SSH2_MSG_USERAUTH_REQUEST', 51 => 'NET_SSH2_MSG_USERAUTH_FAILURE', 52 => 'NET_SSH2_MSG_USERAUTH_SUCCESS', 53 => 'NET_SSH2_MSG_USERAUTH_BANNER', 80 => 'NET_SSH2_MSG_GLOBAL_REQUEST', 81 => 'NET_SSH2_MSG_REQUEST_SUCCESS', 82 => 'NET_SSH2_MSG_REQUEST_FAILURE', 90 => 'NET_SSH2_MSG_CHANNEL_OPEN', 91 => 'NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION', 92 => 'NET_SSH2_MSG_CHANNEL_OPEN_FAILURE', 93 => 'NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST', 94 => 'NET_SSH2_MSG_CHANNEL_DATA', 95 => 'NET_SSH2_MSG_CHANNEL_EXTENDED_DATA', 96 => 'NET_SSH2_MSG_CHANNEL_EOF', 97 => 'NET_SSH2_MSG_CHANNEL_CLOSE', 98 => 'NET_SSH2_MSG_CHANNEL_REQUEST', 99 => 'NET_SSH2_MSG_CHANNEL_SUCCESS', 100 => 'NET_SSH2_MSG_CHANNEL_FAILURE' ); $this->disconnect_reasons = array( 1 => 'NET_SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT', 2 => 'NET_SSH2_DISCONNECT_PROTOCOL_ERROR', 3 => 'NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED', 4 => 'NET_SSH2_DISCONNECT_RESERVED', 5 => 'NET_SSH2_DISCONNECT_MAC_ERROR', 6 => 'NET_SSH2_DISCONNECT_COMPRESSION_ERROR', 7 => 'NET_SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE', 8 => 'NET_SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED', 9 => 'NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE', 10 => 'NET_SSH2_DISCONNECT_CONNECTION_LOST', 11 => 'NET_SSH2_DISCONNECT_BY_APPLICATION', 12 => 'NET_SSH2_DISCONNECT_TOO_MANY_CONNECTIONS', 13 => 'NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER', 14 => 'NET_SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE', 15 => 'NET_SSH2_DISCONNECT_ILLEGAL_USER_NAME' ); $this->channel_open_failure_reasons = array( 1 => 'NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED' ); $this->terminal_modes = array( 0 => 'NET_SSH2_TTY_OP_END' ); $this->channel_extended_data_type_codes = array( 1 => 'NET_SSH2_EXTENDED_DATA_STDERR' ); $this->_define_array( $this->message_numbers, $this->disconnect_reasons, $this->channel_open_failure_reasons, $this->terminal_modes, $this->channel_extended_data_type_codes, array(60 => 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ'), array(60 => 'NET_SSH2_MSG_USERAUTH_PK_OK'), array(60 => 'NET_SSH2_MSG_USERAUTH_INFO_REQUEST', 61 => 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE') ); $this->host = $host; $this->port = $port; $this->connectionTimeout = $timeout; } function _connect() { if ($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR) { return false; } $this->bitmap |= NET_SSH2_MASK_CONSTRUCTOR; $timeout = $this->connectionTimeout; $host = $this->host . ':' . $this->port; $this->last_packet = strtok(microtime(), ' ') + strtok(''); $start = strtok(microtime(), ' ') + strtok(''); $this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $timeout); if (!$this->fsock) { user_error(rtrim("Cannot connect to $host. Error $errno. $errstr")); return false; } $elapsed = strtok(microtime(), ' ') + strtok('') - $start; $timeout-= $elapsed; if ($timeout <= 0) { user_error("Cannot connect to $host. Timeout error"); return false; } $read = array($this->fsock); $write = $except = null; $sec = floor($timeout); $usec = 1000000 * ($timeout - $sec); if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) { user_error("Cannot connect to $host. Banner timeout"); return false; } $temp = ''; $extra = ''; while (!feof($this->fsock) && !preg_match('#^SSH-(\d\.\d+)#', $temp, $matches)) { if (substr($temp, -2) == "\r\n") { $extra.= $temp; $temp = ''; } $temp.= fgets($this->fsock, 255); } if (feof($this->fsock)) { user_error('Connection closed by server'); return false; } $this->identifier = $this->_generate_identifier(); if (defined('NET_SSH2_LOGGING')) { $this->_append_log('<-', $extra . $temp); $this->_append_log('->', $this->identifier . "\r\n"); } $this->server_identifier = trim($temp, "\r\n"); if (strlen($extra)) { $this->errors[] = utf8_decode($extra); } if ($matches[1] != '1.99' && $matches[1] != '2.0') { user_error("Cannot connect to SSH $matches[1] servers"); return false; } fputs($this->fsock, $this->identifier . "\r\n"); $response = $this->_get_binary_packet(); if ($response === false) { user_error('Connection closed by server'); return false; } if (ord($response[0]) != NET_SSH2_MSG_KEXINIT) { user_error('Expected SSH_MSG_KEXINIT'); return false; } if (!$this->_key_exchange($response)) { return false; } $this->bitmap|= NET_SSH2_MASK_CONNECTED; return true; } function _generate_identifier() { $identifier = 'SSH-2.0-phpseclib_0.3'; $ext = array(); if (extension_loaded('mcrypt')) { $ext[] = 'mcrypt'; } if (extension_loaded('gmp')) { $ext[] = 'gmp'; } elseif (extension_loaded('bcmath')) { $ext[] = 'bcmath'; } if (!empty($ext)) { $identifier .= ' (' . implode(', ', $ext) . ')'; } return $identifier; } function _key_exchange($kexinit_payload_server) { static $kex_algorithms = array( 'diffie-hellman-group1-sha1', 'diffie-hellman-group14-sha1' ); static $server_host_key_algorithms = array( 'ssh-rsa', 'ssh-dss' ); static $encryption_algorithms = false; if ($encryption_algorithms === false) { $encryption_algorithms = array( 'arcfour256', 'arcfour128', 'aes128-ctr', 'aes192-ctr', 'aes256-ctr', 'twofish128-ctr', 'twofish192-ctr', 'twofish256-ctr', 'aes128-cbc', 'aes192-cbc', 'aes256-cbc', 'twofish128-cbc', 'twofish192-cbc', 'twofish256-cbc', 'twofish-cbc', 'blowfish-ctr', 'blowfish-cbc', '3des-ctr', '3des-cbc', ); if (phpseclib_resolve_include_path('Crypt/RC4.php') === false) { $encryption_algorithms = array_diff( $encryption_algorithms, array('arcfour256', 'arcfour128', 'arcfour') ); } if (phpseclib_resolve_include_path('Crypt/Rijndael.php') === false) { $encryption_algorithms = array_diff( $encryption_algorithms, array('aes128-ctr', 'aes192-ctr', 'aes256-ctr', 'aes128-cbc', 'aes192-cbc', 'aes256-cbc') ); } if (phpseclib_resolve_include_path('Crypt/Twofish.php') === false) { $encryption_algorithms = array_diff( $encryption_algorithms, array('twofish128-ctr', 'twofish192-ctr', 'twofish256-ctr', 'twofish128-cbc', 'twofish192-cbc', 'twofish256-cbc', 'twofish-cbc') ); } if (phpseclib_resolve_include_path('Crypt/Blowfish.php') === false) { $encryption_algorithms = array_diff( $encryption_algorithms, array('blowfish-ctr', 'blowfish-cbc') ); } if (phpseclib_resolve_include_path('Crypt/TripleDES.php') === false) { $encryption_algorithms = array_diff( $encryption_algorithms, array('3des-ctr', '3des-cbc') ); } $encryption_algorithms = array_values($encryption_algorithms); } $mac_algorithms = array( 'hmac-sha2-256', 'hmac-sha1-96', 'hmac-sha1', 'hmac-md5-96', 'hmac-md5', ); static $compression_algorithms = array( 'none' ); switch ($this->server_identifier) { case 'SSH-2.0-SSHD': $mac_algorithms = array_values(array_diff( $mac_algorithms, array('hmac-sha1-96', 'hmac-md5-96') )); } static $str_kex_algorithms, $str_server_host_key_algorithms, $encryption_algorithms_server_to_client, $mac_algorithms_server_to_client, $compression_algorithms_server_to_client, $encryption_algorithms_client_to_server, $mac_algorithms_client_to_server, $compression_algorithms_client_to_server; if (empty($str_kex_algorithms)) { $str_kex_algorithms = implode(',', $kex_algorithms); $str_server_host_key_algorithms = implode(',', $server_host_key_algorithms); $encryption_algorithms_server_to_client = $encryption_algorithms_client_to_server = implode(',', $encryption_algorithms); $mac_algorithms_server_to_client = $mac_algorithms_client_to_server = implode(',', $mac_algorithms); $compression_algorithms_server_to_client = $compression_algorithms_client_to_server = implode(',', $compression_algorithms); } $client_cookie = crypt_random_string(16); $response = $kexinit_payload_server; $this->_string_shift($response, 1); $server_cookie = $this->_string_shift($response, 16); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->kex_algorithms = explode(',', $this->_string_shift($response, $temp['length'])); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->server_host_key_algorithms = explode(',', $this->_string_shift($response, $temp['length'])); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->encryption_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length'])); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->encryption_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length'])); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->mac_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length'])); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->mac_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length'])); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->compression_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length'])); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->compression_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length'])); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->languages_client_to_server = explode(',', $this->_string_shift($response, $temp['length'])); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->languages_server_to_client = explode(',', $this->_string_shift($response, $temp['length'])); extract(unpack('Cfirst_kex_packet_follows', $this->_string_shift($response, 1))); $first_kex_packet_follows = $first_kex_packet_follows != 0; $kexinit_payload_client = pack('Ca*Na*Na*Na*Na*Na*Na*Na*Na*Na*Na*CN', NET_SSH2_MSG_KEXINIT, $client_cookie, strlen($str_kex_algorithms), $str_kex_algorithms, strlen($str_server_host_key_algorithms), $str_server_host_key_algorithms, strlen($encryption_algorithms_client_to_server), $encryption_algorithms_client_to_server, strlen($encryption_algorithms_server_to_client), $encryption_algorithms_server_to_client, strlen($mac_algorithms_client_to_server), $mac_algorithms_client_to_server, strlen($mac_algorithms_server_to_client), $mac_algorithms_server_to_client, strlen($compression_algorithms_client_to_server), $compression_algorithms_client_to_server, strlen($compression_algorithms_server_to_client), $compression_algorithms_server_to_client, 0, '', 0, '', 0, 0 ); if (!$this->_send_binary_packet($kexinit_payload_client)) { return false; } for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_server_to_client); $i++); if ($i == count($encryption_algorithms)) { user_error('No compatible server to client encryption algorithms found'); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } $decrypt = $encryption_algorithms[$i]; switch ($decrypt) { case '3des-cbc': case '3des-ctr': $decryptKeyLength = 24; break; case 'aes256-cbc': case 'aes256-ctr': case 'twofish-cbc': case 'twofish256-cbc': case 'twofish256-ctr': $decryptKeyLength = 32; break; case 'aes192-cbc': case 'aes192-ctr': case 'twofish192-cbc': case 'twofish192-ctr': $decryptKeyLength = 24; break; case 'aes128-cbc': case 'aes128-ctr': case 'twofish128-cbc': case 'twofish128-ctr': case 'blowfish-cbc': case 'blowfish-ctr': $decryptKeyLength = 16; break; case 'arcfour': case 'arcfour128': $decryptKeyLength = 16; break; case 'arcfour256': $decryptKeyLength = 32; break; case 'none'; $decryptKeyLength = 0; } for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_client_to_server); $i++); if ($i == count($encryption_algorithms)) { user_error('No compatible client to server encryption algorithms found'); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } $encrypt = $encryption_algorithms[$i]; switch ($encrypt) { case '3des-cbc': case '3des-ctr': $encryptKeyLength = 24; break; case 'aes256-cbc': case 'aes256-ctr': case 'twofish-cbc': case 'twofish256-cbc': case 'twofish256-ctr': $encryptKeyLength = 32; break; case 'aes192-cbc': case 'aes192-ctr': case 'twofish192-cbc': case 'twofish192-ctr': $encryptKeyLength = 24; break; case 'aes128-cbc': case 'aes128-ctr': case 'twofish128-cbc': case 'twofish128-ctr': case 'blowfish-cbc': case 'blowfish-ctr': $encryptKeyLength = 16; break; case 'arcfour': case 'arcfour128': $encryptKeyLength = 16; break; case 'arcfour256': $encryptKeyLength = 32; break; case 'none'; $encryptKeyLength = 0; } $keyLength = $decryptKeyLength > $encryptKeyLength ? $decryptKeyLength : $encryptKeyLength; for ($i = 0; $i < count($kex_algorithms) && !in_array($kex_algorithms[$i], $this->kex_algorithms); $i++); if ($i == count($kex_algorithms)) { user_error('No compatible key exchange algorithms found'); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } switch ($kex_algorithms[$i]) { case 'diffie-hellman-group1-sha1': $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF'; break; case 'diffie-hellman-group14-sha1': $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' . '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' . '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' . 'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' . '3995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF'; break; } $g = new Math_BigInteger(2); $prime = new Math_BigInteger($prime, 16); $kexHash = new Crypt_Hash('sha1'); $one = new Math_BigInteger(1); $keyLength = min($keyLength, $kexHash->getLength()); $max = $one->bitwise_leftShift(16 * $keyLength); $max = $max->subtract($one); $x = $one->random($one, $max); $e = $g->modPow($x, $prime); $eBytes = $e->toBytes(true); $data = pack('CNa*', NET_SSH2_MSG_KEXDH_INIT, strlen($eBytes), $eBytes); if (!$this->_send_binary_packet($data)) { user_error('Connection closed by server'); return false; } $response = $this->_get_binary_packet(); if ($response === false) { user_error('Connection closed by server'); return false; } extract(unpack('Ctype', $this->_string_shift($response, 1))); if ($type != NET_SSH2_MSG_KEXDH_REPLY) { user_error('Expected SSH_MSG_KEXDH_REPLY'); return false; } $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->server_public_host_key = $server_public_host_key = $this->_string_shift($response, $temp['length']); $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); $public_key_format = $this->_string_shift($server_public_host_key, $temp['length']); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $fBytes = $this->_string_shift($response, $temp['length']); $f = new Math_BigInteger($fBytes, -256); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->signature = $this->_string_shift($response, $temp['length']); $temp = unpack('Nlength', $this->_string_shift($this->signature, 4)); $this->signature_format = $this->_string_shift($this->signature, $temp['length']); $key = $f->modPow($x, $prime); $keyBytes = $key->toBytes(true); $this->exchange_hash = pack('Na*Na*Na*Na*Na*Na*Na*Na*', strlen($this->identifier), $this->identifier, strlen($this->server_identifier), $this->server_identifier, strlen($kexinit_payload_client), $kexinit_payload_client, strlen($kexinit_payload_server), $kexinit_payload_server, strlen($this->server_public_host_key), $this->server_public_host_key, strlen($eBytes), $eBytes, strlen($fBytes), $fBytes, strlen($keyBytes), $keyBytes ); $this->exchange_hash = $kexHash->hash($this->exchange_hash); if ($this->session_id === false) { $this->session_id = $this->exchange_hash; } for ($i = 0; $i < count($server_host_key_algorithms) && !in_array($server_host_key_algorithms[$i], $this->server_host_key_algorithms); $i++); if ($i == count($server_host_key_algorithms)) { user_error('No compatible server host key algorithms found'); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } if ($public_key_format != $server_host_key_algorithms[$i] || $this->signature_format != $server_host_key_algorithms[$i]) { user_error('Server Host Key Algorithm Mismatch'); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } $packet = pack('C', NET_SSH2_MSG_NEWKEYS ); if (!$this->_send_binary_packet($packet)) { return false; } $response = $this->_get_binary_packet(); if ($response === false) { user_error('Connection closed by server'); return false; } extract(unpack('Ctype', $this->_string_shift($response, 1))); if ($type != NET_SSH2_MSG_NEWKEYS) { user_error('Expected SSH_MSG_NEWKEYS'); return false; } switch ($encrypt) { case '3des-cbc': if (!class_exists('Crypt_TripleDES')) { include_once 'Crypt/TripleDES.php'; } $this->encrypt = new Crypt_TripleDES(); break; case '3des-ctr': if (!class_exists('Crypt_TripleDES')) { include_once 'Crypt/TripleDES.php'; } $this->encrypt = new Crypt_TripleDES(CRYPT_DES_MODE_CTR); break; case 'aes256-cbc': case 'aes192-cbc': case 'aes128-cbc': if (!class_exists('Crypt_Rijndael')) { include_once 'Crypt/Rijndael.php'; } $this->encrypt = new Crypt_Rijndael(); $this->encrypt_block_size = 16; break; case 'aes256-ctr': case 'aes192-ctr': case 'aes128-ctr': if (!class_exists('Crypt_Rijndael')) { include_once 'Crypt/Rijndael.php'; } $this->encrypt = new Crypt_Rijndael(CRYPT_RIJNDAEL_MODE_CTR); $this->encrypt_block_size = 16; break; case 'blowfish-cbc': if (!class_exists('Crypt_Blowfish')) { include_once 'Crypt/Blowfish.php'; } $this->encrypt = new Crypt_Blowfish(); $this->encrypt_block_size = 8; break; case 'blowfish-ctr': if (!class_exists('Crypt_Blowfish')) { include_once 'Crypt/Blowfish.php'; } $this->encrypt = new Crypt_Blowfish(CRYPT_BLOWFISH_MODE_CTR); $this->encrypt_block_size = 8; break; case 'twofish128-cbc': case 'twofish192-cbc': case 'twofish256-cbc': case 'twofish-cbc': if (!class_exists('Crypt_Twofish')) { include_once 'Crypt/Twofish.php'; } $this->encrypt = new Crypt_Twofish(); $this->encrypt_block_size = 16; break; case 'twofish128-ctr': case 'twofish192-ctr': case 'twofish256-ctr': if (!class_exists('Crypt_Twofish')) { include_once 'Crypt/Twofish.php'; } $this->encrypt = new Crypt_Twofish(CRYPT_TWOFISH_MODE_CTR); $this->encrypt_block_size = 16; break; case 'arcfour': case 'arcfour128': case 'arcfour256': if (!class_exists('Crypt_RC4')) { include_once 'Crypt/RC4.php'; } $this->encrypt = new Crypt_RC4(); break; case 'none'; } switch ($decrypt) { case '3des-cbc': if (!class_exists('Crypt_TripleDES')) { include_once 'Crypt/TripleDES.php'; } $this->decrypt = new Crypt_TripleDES(); break; case '3des-ctr': if (!class_exists('Crypt_TripleDES')) { include_once 'Crypt/TripleDES.php'; } $this->decrypt = new Crypt_TripleDES(CRYPT_DES_MODE_CTR); break; case 'aes256-cbc': case 'aes192-cbc': case 'aes128-cbc': if (!class_exists('Crypt_Rijndael')) { include_once 'Crypt/Rijndael.php'; } $this->decrypt = new Crypt_Rijndael(); $this->decrypt_block_size = 16; break; case 'aes256-ctr': case 'aes192-ctr': case 'aes128-ctr': if (!class_exists('Crypt_Rijndael')) { include_once 'Crypt/Rijndael.php'; } $this->decrypt = new Crypt_Rijndael(CRYPT_RIJNDAEL_MODE_CTR); $this->decrypt_block_size = 16; break; case 'blowfish-cbc': if (!class_exists('Crypt_Blowfish')) { include_once 'Crypt/Blowfish.php'; } $this->decrypt = new Crypt_Blowfish(); $this->decrypt_block_size = 8; break; case 'blowfish-ctr': if (!class_exists('Crypt_Blowfish')) { include_once 'Crypt/Blowfish.php'; } $this->decrypt = new Crypt_Blowfish(CRYPT_BLOWFISH_MODE_CTR); $this->decrypt_block_size = 8; break; case 'twofish128-cbc': case 'twofish192-cbc': case 'twofish256-cbc': case 'twofish-cbc': if (!class_exists('Crypt_Twofish')) { include_once 'Crypt/Twofish.php'; } $this->decrypt = new Crypt_Twofish(); $this->decrypt_block_size = 16; break; case 'twofish128-ctr': case 'twofish192-ctr': case 'twofish256-ctr': if (!class_exists('Crypt_Twofish')) { include_once 'Crypt/Twofish.php'; } $this->decrypt = new Crypt_Twofish(CRYPT_TWOFISH_MODE_CTR); $this->decrypt_block_size = 16; break; case 'arcfour': case 'arcfour128': case 'arcfour256': if (!class_exists('Crypt_RC4')) { include_once 'Crypt/RC4.php'; } $this->decrypt = new Crypt_RC4(); break; case 'none'; } $keyBytes = pack('Na*', strlen($keyBytes), $keyBytes); if ($this->encrypt) { $this->encrypt->enableContinuousBuffer(); $this->encrypt->disablePadding(); $iv = $kexHash->hash($keyBytes . $this->exchange_hash . 'A' . $this->session_id); while ($this->encrypt_block_size > strlen($iv)) { $iv.= $kexHash->hash($keyBytes . $this->exchange_hash . $iv); } $this->encrypt->setIV(substr($iv, 0, $this->encrypt_block_size)); $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'C' . $this->session_id); while ($encryptKeyLength > strlen($key)) { $key.= $kexHash->hash($keyBytes . $this->exchange_hash . $key); } $this->encrypt->setKey(substr($key, 0, $encryptKeyLength)); } if ($this->decrypt) { $this->decrypt->enableContinuousBuffer(); $this->decrypt->disablePadding(); $iv = $kexHash->hash($keyBytes . $this->exchange_hash . 'B' . $this->session_id); while ($this->decrypt_block_size > strlen($iv)) { $iv.= $kexHash->hash($keyBytes . $this->exchange_hash . $iv); } $this->decrypt->setIV(substr($iv, 0, $this->decrypt_block_size)); $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'D' . $this->session_id); while ($decryptKeyLength > strlen($key)) { $key.= $kexHash->hash($keyBytes . $this->exchange_hash . $key); } $this->decrypt->setKey(substr($key, 0, $decryptKeyLength)); } if ($encrypt == 'arcfour128' || $encrypt == 'arcfour256') { $this->encrypt->encrypt(str_repeat("\0", 1536)); } if ($decrypt == 'arcfour128' || $decrypt == 'arcfour256') { $this->decrypt->decrypt(str_repeat("\0", 1536)); } for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_client_to_server); $i++); if ($i == count($mac_algorithms)) { user_error('No compatible client to server message authentication algorithms found'); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } $createKeyLength = 0; switch ($mac_algorithms[$i]) { case 'hmac-sha2-256': $this->hmac_create = new Crypt_Hash('sha256'); $createKeyLength = 32; break; case 'hmac-sha1': $this->hmac_create = new Crypt_Hash('sha1'); $createKeyLength = 20; break; case 'hmac-sha1-96': $this->hmac_create = new Crypt_Hash('sha1-96'); $createKeyLength = 20; break; case 'hmac-md5': $this->hmac_create = new Crypt_Hash('md5'); $createKeyLength = 16; break; case 'hmac-md5-96': $this->hmac_create = new Crypt_Hash('md5-96'); $createKeyLength = 16; } for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_server_to_client); $i++); if ($i == count($mac_algorithms)) { user_error('No compatible server to client message authentication algorithms found'); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } $checkKeyLength = 0; $this->hmac_size = 0; switch ($mac_algorithms[$i]) { case 'hmac-sha2-256': $this->hmac_check = new Crypt_Hash('sha256'); $checkKeyLength = 32; $this->hmac_size = 32; break; case 'hmac-sha1': $this->hmac_check = new Crypt_Hash('sha1'); $checkKeyLength = 20; $this->hmac_size = 20; break; case 'hmac-sha1-96': $this->hmac_check = new Crypt_Hash('sha1-96'); $checkKeyLength = 20; $this->hmac_size = 12; break; case 'hmac-md5': $this->hmac_check = new Crypt_Hash('md5'); $checkKeyLength = 16; $this->hmac_size = 16; break; case 'hmac-md5-96': $this->hmac_check = new Crypt_Hash('md5-96'); $checkKeyLength = 16; $this->hmac_size = 12; } $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'E' . $this->session_id); while ($createKeyLength > strlen($key)) { $key.= $kexHash->hash($keyBytes . $this->exchange_hash . $key); } $this->hmac_create->setKey(substr($key, 0, $createKeyLength)); $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'F' . $this->session_id); while ($checkKeyLength > strlen($key)) { $key.= $kexHash->hash($keyBytes . $this->exchange_hash . $key); } $this->hmac_check->setKey(substr($key, 0, $checkKeyLength)); for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_server_to_client); $i++); if ($i == count($compression_algorithms)) { user_error('No compatible server to client compression algorithms found'); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } $this->decompress = $compression_algorithms[$i] == 'zlib'; for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_client_to_server); $i++); if ($i == count($compression_algorithms)) { user_error('No compatible client to server compression algorithms found'); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } $this->compress = $compression_algorithms[$i] == 'zlib'; return true; } function login($username) { $args = func_get_args(); return call_user_func_array(array(&$this, '_login'), $args); } function _login($username) { if (!($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR)) { if (!$this->_connect()) { return false; } } $args = array_slice(func_get_args(), 1); if (empty($args)) { return $this->_login_helper($username); } foreach ($args as $arg) { if ($this->_login_helper($username, $arg)) { return true; } } return false; } function _login_helper($username, $password = null) { if (!($this->bitmap & NET_SSH2_MASK_CONNECTED)) { return false; } if (!($this->bitmap & NET_SSH2_MASK_LOGIN_REQ)) { $packet = pack('CNa*', NET_SSH2_MSG_SERVICE_REQUEST, strlen('ssh-userauth'), 'ssh-userauth' ); if (!$this->_send_binary_packet($packet)) { return false; } $response = $this->_get_binary_packet(); if ($response === false) { user_error('Connection closed by server'); return false; } extract(unpack('Ctype', $this->_string_shift($response, 1))); if ($type != NET_SSH2_MSG_SERVICE_ACCEPT) { user_error('Expected SSH_MSG_SERVICE_ACCEPT'); return false; } $this->bitmap |= NET_SSH2_MASK_LOGIN_REQ; } if (strlen($this->last_interactive_response)) { return !is_string($password) && !is_array($password) ? false : $this->_keyboard_interactive_process($password); } if (is_object($password)) { switch (strtolower(get_class($password))) { case 'crypt_rsa': return $this->_privatekey_login($username, $password); case 'system_ssh_agent': return $this->_ssh_agent_login($username, $password); } } if (is_array($password)) { if ($this->_keyboard_interactive_login($username, $password)) { $this->bitmap |= NET_SSH2_MASK_LOGIN; return true; } return false; } if (!isset($password)) { $packet = pack('CNa*Na*Na*', NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username), $username, strlen('ssh-connection'), 'ssh-connection', strlen('none'), 'none' ); if (!$this->_send_binary_packet($packet)) { return false; } $response = $this->_get_binary_packet(); if ($response === false) { user_error('Connection closed by server'); return false; } extract(unpack('Ctype', $this->_string_shift($response, 1))); switch ($type) { case NET_SSH2_MSG_USERAUTH_SUCCESS: $this->bitmap |= NET_SSH2_MASK_LOGIN; return true; default: return false; } } $packet = pack('CNa*Na*Na*CNa*', NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username), $username, strlen('ssh-connection'), 'ssh-connection', strlen('password'), 'password', 0, strlen($password), $password ); if (!defined('NET_SSH2_LOGGING')) { $logged = null; } else { $logged = pack('CNa*Na*Na*CNa*', NET_SSH2_MSG_USERAUTH_REQUEST, strlen('username'), 'username', strlen('ssh-connection'), 'ssh-connection', strlen('password'), 'password', 0, strlen('password'), 'password' ); } if (!$this->_send_binary_packet($packet, $logged)) { return false; } $response = $this->_get_binary_packet(); if ($response === false) { user_error('Connection closed by server'); return false; } extract(unpack('Ctype', $this->_string_shift($response, 1))); switch ($type) { case NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ: if (defined('NET_SSH2_LOGGING')) { $this->message_number_log[count($this->message_number_log) - 1] = 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ'; } extract(unpack('Nlength', $this->_string_shift($response, 4))); $this->errors[] = 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ: ' . utf8_decode($this->_string_shift($response, $length)); return $this->_disconnect(NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER); case NET_SSH2_MSG_USERAUTH_FAILURE: extract(unpack('Nlength', $this->_string_shift($response, 4))); $auth_methods = explode(',', $this->_string_shift($response, $length)); extract(unpack('Cpartial_success', $this->_string_shift($response, 1))); $partial_success = $partial_success != 0; if (!$partial_success && in_array('keyboard-interactive', $auth_methods)) { if ($this->_keyboard_interactive_login($username, $password)) { $this->bitmap |= NET_SSH2_MASK_LOGIN; return true; } return false; } return false; case NET_SSH2_MSG_USERAUTH_SUCCESS: $this->bitmap |= NET_SSH2_MASK_LOGIN; return true; } return false; } function _keyboard_interactive_login($username, $password) { $packet = pack('CNa*Na*Na*Na*Na*', NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username), $username, strlen('ssh-connection'), 'ssh-connection', strlen('keyboard-interactive'), 'keyboard-interactive', 0, '', 0, '' ); if (!$this->_send_binary_packet($packet)) { return false; } return $this->_keyboard_interactive_process($password); } function _keyboard_interactive_process() { $responses = func_get_args(); if (strlen($this->last_interactive_response)) { $response = $this->last_interactive_response; } else { $orig = $response = $this->_get_binary_packet(); if ($response === false) { user_error('Connection closed by server'); return false; } } extract(unpack('Ctype', $this->_string_shift($response, 1))); switch ($type) { case NET_SSH2_MSG_USERAUTH_INFO_REQUEST: extract(unpack('Nlength', $this->_string_shift($response, 4))); $this->_string_shift($response, $length); extract(unpack('Nlength', $this->_string_shift($response, 4))); $this->_string_shift($response, $length); extract(unpack('Nlength', $this->_string_shift($response, 4))); $this->_string_shift($response, $length); extract(unpack('Nnum_prompts', $this->_string_shift($response, 4))); for ($i = 0; $i < count($responses); $i++) { if (is_array($responses[$i])) { foreach ($responses[$i] as $key => $value) { $this->keyboard_requests_responses[$key] = $value; } unset($responses[$i]); } } $responses = array_values($responses); if (isset($this->keyboard_requests_responses)) { for ($i = 0; $i < $num_prompts; $i++) { extract(unpack('Nlength', $this->_string_shift($response, 4))); $prompt = $this->_string_shift($response, $length); foreach ($this->keyboard_requests_responses as $key => $value) { if (substr($prompt, 0, strlen($key)) == $key) { $responses[] = $value; break; } } } } if (strlen($this->last_interactive_response)) { $this->last_interactive_response = ''; } else if (defined('NET_SSH2_LOGGING')) { $this->message_number_log[count($this->message_number_log) - 1] = str_replace( 'UNKNOWN', 'NET_SSH2_MSG_USERAUTH_INFO_REQUEST', $this->message_number_log[count($this->message_number_log) - 1] ); } if (!count($responses) && $num_prompts) { $this->last_interactive_response = $orig; return false; } $packet = $logged = pack('CN', NET_SSH2_MSG_USERAUTH_INFO_RESPONSE, count($responses)); for ($i = 0; $i < count($responses); $i++) { $packet.= pack('Na*', strlen($responses[$i]), $responses[$i]); $logged.= pack('Na*', strlen('dummy-answer'), 'dummy-answer'); } if (!$this->_send_binary_packet($packet, $logged)) { return false; } if (defined('NET_SSH2_LOGGING') && NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) { $this->message_number_log[count($this->message_number_log) - 1] = str_replace( 'UNKNOWN', 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE', $this->message_number_log[count($this->message_number_log) - 1] ); } return $this->_keyboard_interactive_process(); case NET_SSH2_MSG_USERAUTH_SUCCESS: return true; case NET_SSH2_MSG_USERAUTH_FAILURE: return false; } return false; } function _ssh_agent_login($username, $agent) { $keys = $agent->requestIdentities(); foreach ($keys as $key) { if ($this->_privatekey_login($username, $key)) { return true; } } return false; } function _privatekey_login($username, $privatekey) { $publickey = $privatekey->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_RAW); if ($publickey === false) { return false; } $publickey = array( 'e' => $publickey['e']->toBytes(true), 'n' => $publickey['n']->toBytes(true) ); $publickey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publickey['e']), $publickey['e'], strlen($publickey['n']), $publickey['n'] ); $part1 = pack('CNa*Na*Na*', NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username), $username, strlen('ssh-connection'), 'ssh-connection', strlen('publickey'), 'publickey' ); $part2 = pack('Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publickey), $publickey); $packet = $part1 . chr(0) . $part2; if (!$this->_send_binary_packet($packet)) { return false; } $response = $this->_get_binary_packet(); if ($response === false) { user_error('Connection closed by server'); return false; } extract(unpack('Ctype', $this->_string_shift($response, 1))); switch ($type) { case NET_SSH2_MSG_USERAUTH_FAILURE: extract(unpack('Nlength', $this->_string_shift($response, 4))); $this->errors[] = 'SSH_MSG_USERAUTH_FAILURE: ' . $this->_string_shift($response, $length); return false; case NET_SSH2_MSG_USERAUTH_PK_OK: if (defined('NET_SSH2_LOGGING') && NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) { $this->message_number_log[count($this->message_number_log) - 1] = str_replace( 'UNKNOWN', 'NET_SSH2_MSG_USERAUTH_PK_OK', $this->message_number_log[count($this->message_number_log) - 1] ); } } $packet = $part1 . chr(1) . $part2; $privatekey->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); $signature = $privatekey->sign(pack('Na*a*', strlen($this->session_id), $this->session_id, $packet)); $signature = pack('Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($signature), $signature); $packet.= pack('Na*', strlen($signature), $signature); if (!$this->_send_binary_packet($packet)) { return false; } $response = $this->_get_binary_packet(); if ($response === false) { user_error('Connection closed by server'); return false; } extract(unpack('Ctype', $this->_string_shift($response, 1))); switch ($type) { case NET_SSH2_MSG_USERAUTH_FAILURE: return false; case NET_SSH2_MSG_USERAUTH_SUCCESS: $this->bitmap |= NET_SSH2_MASK_LOGIN; return true; } return false; } function setTimeout($timeout) { $this->timeout = $this->curTimeout = $timeout; } function getStdError() { return $this->stdErrorLog; } function exec($command, $callback = null) { $this->curTimeout = $this->timeout; $this->is_timeout = false; $this->stdErrorLog = ''; if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { return false; } $this->window_size_server_to_client[NET_SSH2_CHANNEL_EXEC] = $this->window_size; $packet_size = 0x4000; $packet = pack('CNa*N3', NET_SSH2_MSG_CHANNEL_OPEN, strlen('session'), 'session', NET_SSH2_CHANNEL_EXEC, $this->window_size_server_to_client[NET_SSH2_CHANNEL_EXEC], $packet_size); if (!$this->_send_binary_packet($packet)) { return false; } $this->channel_status[NET_SSH2_CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_OPEN; $response = $this->_get_channel_packet(NET_SSH2_CHANNEL_EXEC); if ($response === false) { return false; } if ($this->request_pty === true) { $terminal_modes = pack('C', NET_SSH2_TTY_OP_END); $packet = pack('CNNa*CNa*N5a*', NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_EXEC], strlen('pty-req'), 'pty-req', 1, strlen('vt100'), 'vt100', $this->windowColumns, $this->windowRows, 0, 0, strlen($terminal_modes), $terminal_modes); if (!$this->_send_binary_packet($packet)) { return false; } $response = $this->_get_binary_packet(); if ($response === false) { user_error('Connection closed by server'); return false; } list(, $type) = unpack('C', $this->_string_shift($response, 1)); switch ($type) { case NET_SSH2_MSG_CHANNEL_SUCCESS: break; case NET_SSH2_MSG_CHANNEL_FAILURE: default: user_error('Unable to request pseudo-terminal'); return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); } $this->in_request_pty_exec = true; } $packet = pack('CNNa*CNa*', NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_EXEC], strlen('exec'), 'exec', 1, strlen($command), $command); if (!$this->_send_binary_packet($packet)) { return false; } $this->channel_status[NET_SSH2_CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_REQUEST; $response = $this->_get_channel_packet(NET_SSH2_CHANNEL_EXEC); if ($response === false) { return false; } $this->channel_status[NET_SSH2_CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_DATA; if ($callback === false || $this->in_request_pty_exec) { return true; } $output = ''; while (true) { $temp = $this->_get_channel_packet(NET_SSH2_CHANNEL_EXEC); switch (true) { case $temp === true: return is_callable($callback) ? true : $output; case $temp === false: return false; default: if (is_callable($callback)) { if (call_user_func($callback, $temp) === true) { $this->_close_channel(NET_SSH2_CHANNEL_EXEC); return true; } } else { $output.= $temp; } } } } function _initShell() { if ($this->in_request_pty_exec === true) { return true; } $this->window_size_server_to_client[NET_SSH2_CHANNEL_SHELL] = $this->window_size; $packet_size = 0x4000; $packet = pack('CNa*N3', NET_SSH2_MSG_CHANNEL_OPEN, strlen('session'), 'session', NET_SSH2_CHANNEL_SHELL, $this->window_size_server_to_client[NET_SSH2_CHANNEL_SHELL], $packet_size); if (!$this->_send_binary_packet($packet)) { return false; } $this->channel_status[NET_SSH2_CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_OPEN; $response = $this->_get_channel_packet(NET_SSH2_CHANNEL_SHELL); if ($response === false) { return false; } $terminal_modes = pack('C', NET_SSH2_TTY_OP_END); $packet = pack('CNNa*CNa*N5a*', NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_SHELL], strlen('pty-req'), 'pty-req', 1, strlen('vt100'), 'vt100', $this->windowColumns, $this->windowRows, 0, 0, strlen($terminal_modes), $terminal_modes); if (!$this->_send_binary_packet($packet)) { return false; } $response = $this->_get_binary_packet(); if ($response === false) { user_error('Connection closed by server'); return false; } list(, $type) = unpack('C', $this->_string_shift($response, 1)); switch ($type) { case NET_SSH2_MSG_CHANNEL_SUCCESS: case NET_SSH2_MSG_CHANNEL_FAILURE: break; default: user_error('Unable to request pseudo-terminal'); return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); } $packet = pack('CNNa*C', NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_SHELL], strlen('shell'), 'shell', 1); if (!$this->_send_binary_packet($packet)) { return false; } $this->channel_status[NET_SSH2_CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_REQUEST; $response = $this->_get_channel_packet(NET_SSH2_CHANNEL_SHELL); if ($response === false) { return false; } $this->channel_status[NET_SSH2_CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_DATA; $this->bitmap |= NET_SSH2_MASK_SHELL; return true; } function _get_interactive_channel() { switch (true) { case $this->in_subsystem: return NET_SSH2_CHANNEL_SUBSYSTEM; case $this->in_request_pty_exec: return NET_SSH2_CHANNEL_EXEC; default: return NET_SSH2_CHANNEL_SHELL; } } function read($expect = '', $mode = NET_SSH2_READ_SIMPLE) { $this->curTimeout = $this->timeout; $this->is_timeout = false; if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { user_error('Operation disallowed prior to login()'); return false; } if (!($this->bitmap & NET_SSH2_MASK_SHELL) && !$this->_initShell()) { user_error('Unable to initiate an interactive shell session'); return false; } $channel = $this->_get_interactive_channel(); $match = $expect; while (true) { if ($mode == NET_SSH2_READ_REGEX) { preg_match($expect, $this->interactiveBuffer, $matches); $match = isset($matches[0]) ? $matches[0] : ''; } $pos = strlen($match) ? strpos($this->interactiveBuffer, $match) : false; if ($pos !== false) { return $this->_string_shift($this->interactiveBuffer, $pos + strlen($match)); } $response = $this->_get_channel_packet($channel); if (is_bool($response)) { $this->in_request_pty_exec = false; return $response ? $this->_string_shift($this->interactiveBuffer, strlen($this->interactiveBuffer)) : false; } $this->interactiveBuffer.= $response; } } function write($cmd) { if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { user_error('Operation disallowed prior to login()'); return false; } if (!($this->bitmap & NET_SSH2_MASK_SHELL) && !$this->_initShell()) { user_error('Unable to initiate an interactive shell session'); return false; } return $this->_send_channel_packet($this->_get_interactive_channel(), $cmd); } function startSubsystem($subsystem) { $this->window_size_server_to_client[NET_SSH2_CHANNEL_SUBSYSTEM] = $this->window_size; $packet = pack('CNa*N3', NET_SSH2_MSG_CHANNEL_OPEN, strlen('session'), 'session', NET_SSH2_CHANNEL_SUBSYSTEM, $this->window_size, 0x4000); if (!$this->_send_binary_packet($packet)) { return false; } $this->channel_status[NET_SSH2_CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_OPEN; $response = $this->_get_channel_packet(NET_SSH2_CHANNEL_SUBSYSTEM); if ($response === false) { return false; } $packet = pack('CNNa*CNa*', NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_SUBSYSTEM], strlen('subsystem'), 'subsystem', 1, strlen($subsystem), $subsystem); if (!$this->_send_binary_packet($packet)) { return false; } $this->channel_status[NET_SSH2_CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_REQUEST; $response = $this->_get_channel_packet(NET_SSH2_CHANNEL_SUBSYSTEM); if ($response === false) { return false; } $this->channel_status[NET_SSH2_CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_DATA; $this->bitmap |= NET_SSH2_MASK_SHELL; $this->in_subsystem = true; return true; } function stopSubsystem() { $this->in_subsystem = false; $this->_close_channel(NET_SSH2_CHANNEL_SUBSYSTEM); return true; } function reset() { $this->_close_channel($this->_get_interactive_channel()); } function isTimeout() { return $this->is_timeout; } function disconnect() { $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); if (isset($this->realtime_log_file) && is_resource($this->realtime_log_file)) { fclose($this->realtime_log_file); } } function __destruct() { $this->disconnect(); } function isConnected() { return (bool) ($this->bitmap & NET_SSH2_MASK_CONNECTED); } function _get_binary_packet() { if (!is_resource($this->fsock) || feof($this->fsock)) { user_error('Connection closed prematurely'); $this->bitmap = 0; return false; } $start = strtok(microtime(), ' ') + strtok(''); $raw = fread($this->fsock, $this->decrypt_block_size); if (!strlen($raw)) { return ''; } if ($this->decrypt !== false) { $raw = $this->decrypt->decrypt($raw); } if ($raw === false) { user_error('Unable to decrypt content'); return false; } extract(unpack('Npacket_length/Cpadding_length', $this->_string_shift($raw, 5))); $remaining_length = $packet_length + 4 - $this->decrypt_block_size; if ($remaining_length < -$this->decrypt_block_size || $remaining_length > 0x9000 || $remaining_length % $this->decrypt_block_size != 0) { user_error('Invalid size'); return false; } $buffer = ''; while ($remaining_length > 0) { $temp = fread($this->fsock, $remaining_length); if ($temp === false || feof($this->fsock)) { user_error('Error reading from socket'); $this->bitmap = 0; return false; } $buffer.= $temp; $remaining_length-= strlen($temp); } $stop = strtok(microtime(), ' ') + strtok(''); if (strlen($buffer)) { $raw.= $this->decrypt !== false ? $this->decrypt->decrypt($buffer) : $buffer; } $payload = $this->_string_shift($raw, $packet_length - $padding_length - 1); $padding = $this->_string_shift($raw, $padding_length); if ($this->hmac_check !== false) { $hmac = fread($this->fsock, $this->hmac_size); if ($hmac === false || strlen($hmac) != $this->hmac_size) { user_error('Error reading socket'); $this->bitmap = 0; return false; } elseif ($hmac != $this->hmac_check->hash(pack('NNCa*', $this->get_seq_no, $packet_length, $padding_length, $payload . $padding))) { user_error('Invalid HMAC'); return false; } } $this->get_seq_no++; if (defined('NET_SSH2_LOGGING')) { $current = strtok(microtime(), ' ') + strtok(''); $message_number = isset($this->message_numbers[ord($payload[0])]) ? $this->message_numbers[ord($payload[0])] : 'UNKNOWN (' . ord($payload[0]) . ')'; $message_number = '<- ' . $message_number . ' (since last: ' . round($current - $this->last_packet, 4) . ', network: ' . round($stop - $start, 4) . 's)'; $this->_append_log($message_number, $payload); $this->last_packet = $current; } return $this->_filter($payload); } function _filter($payload) { switch (ord($payload[0])) { case NET_SSH2_MSG_DISCONNECT: $this->_string_shift($payload, 1); extract(unpack('Nreason_code/Nlength', $this->_string_shift($payload, 8))); $this->errors[] = 'SSH_MSG_DISCONNECT: ' . $this->disconnect_reasons[$reason_code] . "\r\n" . utf8_decode($this->_string_shift($payload, $length)); $this->bitmap = 0; return false; case NET_SSH2_MSG_IGNORE: $payload = $this->_get_binary_packet(); break; case NET_SSH2_MSG_DEBUG: $this->_string_shift($payload, 2); extract(unpack('Nlength', $this->_string_shift($payload, 4))); $this->errors[] = 'SSH_MSG_DEBUG: ' . utf8_decode($this->_string_shift($payload, $length)); $payload = $this->_get_binary_packet(); break; case NET_SSH2_MSG_UNIMPLEMENTED: return false; case NET_SSH2_MSG_KEXINIT: if ($this->session_id !== false) { if (!$this->_key_exchange($payload)) { $this->bitmap = 0; return false; } $payload = $this->_get_binary_packet(); } } if (($this->bitmap & NET_SSH2_MASK_CONNECTED) && !($this->bitmap & NET_SSH2_MASK_LOGIN) && ord($payload[0]) == NET_SSH2_MSG_USERAUTH_BANNER) { $this->_string_shift($payload, 1); extract(unpack('Nlength', $this->_string_shift($payload, 4))); $this->banner_message = utf8_decode($this->_string_shift($payload, $length)); $payload = $this->_get_binary_packet(); } if (($this->bitmap & NET_SSH2_MASK_CONNECTED) && ($this->bitmap & NET_SSH2_MASK_LOGIN)) { switch (ord($payload[0])) { case NET_SSH2_MSG_GLOBAL_REQUEST: $this->_string_shift($payload, 1); extract(unpack('Nlength', $this->_string_shift($payload))); $this->errors[] = 'SSH_MSG_GLOBAL_REQUEST: ' . utf8_decode($this->_string_shift($payload, $length)); if (!$this->_send_binary_packet(pack('C', NET_SSH2_MSG_REQUEST_FAILURE))) { return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); } $payload = $this->_get_binary_packet(); break; case NET_SSH2_MSG_CHANNEL_OPEN: $this->_string_shift($payload, 1); extract(unpack('Nlength', $this->_string_shift($payload, 4))); $this->errors[] = 'SSH_MSG_CHANNEL_OPEN: ' . utf8_decode($this->_string_shift($payload, $length)); $this->_string_shift($payload, 4); extract(unpack('Nserver_channel', $this->_string_shift($payload, 4))); $packet = pack('CN3a*Na*', NET_SSH2_MSG_REQUEST_FAILURE, $server_channel, NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED, 0, '', 0, ''); if (!$this->_send_binary_packet($packet)) { return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); } $payload = $this->_get_binary_packet(); break; case NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST: $this->_string_shift($payload, 1); extract(unpack('Nchannel', $this->_string_shift($payload, 4))); extract(unpack('Nwindow_size', $this->_string_shift($payload, 4))); $this->window_size_client_to_server[$channel]+= $window_size; $payload = ($this->bitmap & NET_SSH2_MASK_WINDOW_ADJUST) ? true : $this->_get_binary_packet(); } } return $payload; } function enableQuietMode() { $this->quiet_mode = true; } function disableQuietMode() { $this->quiet_mode = false; } function isQuietModeEnabled() { return $this->quiet_mode; } function enablePTY() { $this->request_pty = true; } function disablePTY() { $this->request_pty = false; } function isPTYEnabled() { return $this->request_pty; } function _get_channel_packet($client_channel, $skip_extended = false) { if (!empty($this->channel_buffers[$client_channel])) { return array_shift($this->channel_buffers[$client_channel]); } while (true) { if ($this->curTimeout) { if ($this->curTimeout < 0) { $this->is_timeout = true; return true; } $read = array($this->fsock); $write = $except = null; $start = strtok(microtime(), ' ') + strtok(''); $sec = floor($this->curTimeout); $usec = 1000000 * ($this->curTimeout - $sec); if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) { $this->is_timeout = true; return true; } $elapsed = strtok(microtime(), ' ') + strtok('') - $start; $this->curTimeout-= $elapsed; } $response = $this->_get_binary_packet(); if ($response === false) { user_error('Connection closed by server'); return false; } if ($client_channel == -1 && $response === true) { return true; } if (!strlen($response)) { return ''; } extract(unpack('Ctype/Nchannel', $this->_string_shift($response, 5))); $this->window_size_server_to_client[$channel]-= strlen($response); if ($this->window_size_server_to_client[$channel] < 0) { $packet = pack('CNN', NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST, $this->server_channels[$channel], $this->window_size); if (!$this->_send_binary_packet($packet)) { return false; } $this->window_size_server_to_client[$channel]+= $this->window_size; } switch ($this->channel_status[$channel]) { case NET_SSH2_MSG_CHANNEL_OPEN: switch ($type) { case NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION: extract(unpack('Nserver_channel', $this->_string_shift($response, 4))); $this->server_channels[$channel] = $server_channel; extract(unpack('Nwindow_size', $this->_string_shift($response, 4))); $this->window_size_client_to_server[$channel] = $window_size; $temp = unpack('Npacket_size_client_to_server', $this->_string_shift($response, 4)); $this->packet_size_client_to_server[$channel] = $temp['packet_size_client_to_server']; return $client_channel == $channel ? true : $this->_get_channel_packet($client_channel, $skip_extended); default: user_error('Unable to open channel'); return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); } break; case NET_SSH2_MSG_CHANNEL_REQUEST: switch ($type) { case NET_SSH2_MSG_CHANNEL_SUCCESS: return true; case NET_SSH2_MSG_CHANNEL_FAILURE: return false; default: user_error('Unable to fulfill channel request'); return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); } case NET_SSH2_MSG_CHANNEL_CLOSE: return $type == NET_SSH2_MSG_CHANNEL_CLOSE ? true : $this->_get_channel_packet($client_channel, $skip_extended); } switch ($type) { case NET_SSH2_MSG_CHANNEL_DATA: extract(unpack('Nlength', $this->_string_shift($response, 4))); $data = $this->_string_shift($response, $length); if ($client_channel == $channel) { return $data; } if (!isset($this->channel_buffers[$channel])) { $this->channel_buffers[$channel] = array(); } $this->channel_buffers[$channel][] = $data; break; case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA: extract(unpack('Ndata_type_code/Nlength', $this->_string_shift($response, 8))); $data = $this->_string_shift($response, $length); $this->stdErrorLog.= $data; if ($skip_extended || $this->quiet_mode) { break; } if ($client_channel == $channel) { return $data; } if (!isset($this->channel_buffers[$channel])) { $this->channel_buffers[$channel] = array(); } $this->channel_buffers[$channel][] = $data; break; case NET_SSH2_MSG_CHANNEL_REQUEST: extract(unpack('Nlength', $this->_string_shift($response, 4))); $value = $this->_string_shift($response, $length); switch ($value) { case 'exit-signal': $this->_string_shift($response, 1); extract(unpack('Nlength', $this->_string_shift($response, 4))); $this->errors[] = 'SSH_MSG_CHANNEL_REQUEST (exit-signal): ' . $this->_string_shift($response, $length); $this->_string_shift($response, 1); extract(unpack('Nlength', $this->_string_shift($response, 4))); if ($length) { $this->errors[count($this->errors)].= "\r\n" . $this->_string_shift($response, $length); } $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$client_channel])); $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel])); $this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_EOF; break; case 'exit-status': extract(unpack('Cfalse/Nexit_status', $this->_string_shift($response, 5))); $this->exit_status = $exit_status; break; default: break; } break; case NET_SSH2_MSG_CHANNEL_CLOSE: $this->curTimeout = 0; if ($this->bitmap & NET_SSH2_MASK_SHELL) { $this->bitmap&= ~NET_SSH2_MASK_SHELL; } if ($this->channel_status[$channel] != NET_SSH2_MSG_CHANNEL_EOF) { $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel])); } $this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_CLOSE; return true; case NET_SSH2_MSG_CHANNEL_EOF: break; default: user_error('Error reading channel data'); return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); } } } function _send_binary_packet($data, $logged = null) { if (!is_resource($this->fsock) || feof($this->fsock)) { user_error('Connection closed prematurely'); $this->bitmap = 0; return false; } $packet_length = strlen($data) + 9; $packet_length+= (($this->encrypt_block_size - 1) * $packet_length) % $this->encrypt_block_size; $padding_length = $packet_length - strlen($data) - 5; $padding = crypt_random_string($padding_length); $packet = pack('NCa*', $packet_length - 4, $padding_length, $data . $padding); $hmac = $this->hmac_create !== false ? $this->hmac_create->hash(pack('Na*', $this->send_seq_no, $packet)) : ''; $this->send_seq_no++; if ($this->encrypt !== false) { $packet = $this->encrypt->encrypt($packet); } $packet.= $hmac; $start = strtok(microtime(), ' ') + strtok(''); $result = strlen($packet) == fputs($this->fsock, $packet); $stop = strtok(microtime(), ' ') + strtok(''); if (defined('NET_SSH2_LOGGING')) { $current = strtok(microtime(), ' ') + strtok(''); $message_number = isset($this->message_numbers[ord($data[0])]) ? $this->message_numbers[ord($data[0])] : 'UNKNOWN (' . ord($data[0]) . ')'; $message_number = '-> ' . $message_number . ' (since last: ' . round($current - $this->last_packet, 4) . ', network: ' . round($stop - $start, 4) . 's)'; $this->_append_log($message_number, isset($logged) ? $logged : $data); $this->last_packet = $current; } return $result; } function _append_log($message_number, $message) { if (strlen($message_number) > 2) { $this->_string_shift($message); } switch (NET_SSH2_LOGGING) { case NET_SSH2_LOG_SIMPLE: $this->message_number_log[] = $message_number; break; case NET_SSH2_LOG_COMPLEX: $this->message_number_log[] = $message_number; $this->log_size+= strlen($message); $this->message_log[] = $message; while ($this->log_size > NET_SSH2_LOG_MAX_SIZE) { $this->log_size-= strlen(array_shift($this->message_log)); array_shift($this->message_number_log); } break; case NET_SSH2_LOG_REALTIME: switch (PHP_SAPI) { case 'cli': $start = $stop = "\r\n"; break; default: $start = '<pre>'; $stop = '</pre>'; } echo $start . $this->_format_log(array($message), array($message_number)) . $stop; @flush(); @ob_flush(); break; case NET_SSH2_LOG_REALTIME_FILE: if (!isset($this->realtime_log_file)) { $filename = NET_SSH2_LOG_REALTIME_FILENAME; $fp = fopen($filename, 'w'); $this->realtime_log_file = $fp; } if (!is_resource($this->realtime_log_file)) { break; } $entry = $this->_format_log(array($message), array($message_number)); if ($this->realtime_log_wrap) { $temp = "<<< START >>>\r\n"; $entry.= $temp; fseek($this->realtime_log_file, ftell($this->realtime_log_file) - strlen($temp)); } $this->realtime_log_size+= strlen($entry); if ($this->realtime_log_size > NET_SSH2_LOG_MAX_SIZE) { fseek($this->realtime_log_file, 0); $this->realtime_log_size = strlen($entry); $this->realtime_log_wrap = true; } fputs($this->realtime_log_file, $entry); } } function _send_channel_packet($client_channel, $data) { while (strlen($data)) { if (!$this->window_size_client_to_server[$client_channel]) { $this->bitmap^= NET_SSH2_MASK_WINDOW_ADJUST; $this->_get_channel_packet(-1); $this->bitmap^= NET_SSH2_MASK_WINDOW_ADJUST; } $max_size = min( $this->packet_size_client_to_server[$client_channel], $this->window_size_client_to_server[$client_channel] ); $temp = $this->_string_shift($data, $max_size); $packet = pack('CN2a*', NET_SSH2_MSG_CHANNEL_DATA, $this->server_channels[$client_channel], strlen($temp), $temp ); $this->window_size_client_to_server[$client_channel]-= strlen($temp); if (!$this->_send_binary_packet($packet)) { return false; } } return true; } function _close_channel($client_channel, $want_reply = false) { $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$client_channel])); if (!$want_reply) { $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$client_channel])); } $this->channel_status[$client_channel] = NET_SSH2_MSG_CHANNEL_CLOSE; $this->curTimeout = 0; while (!is_bool($this->_get_channel_packet($client_channel))); if ($want_reply) { $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$client_channel])); } if ($this->bitmap & NET_SSH2_MASK_SHELL) { $this->bitmap&= ~NET_SSH2_MASK_SHELL; } } function _disconnect($reason) { if ($this->bitmap & NET_SSH2_MASK_CONNECTED) { $data = pack('CNNa*Na*', NET_SSH2_MSG_DISCONNECT, $reason, 0, '', 0, ''); $this->_send_binary_packet($data); $this->bitmap = 0; fclose($this->fsock); return false; } } function _string_shift(&$string, $index = 1) { $substr = substr($string, 0, $index); $string = substr($string, $index); return $substr; } function _define_array() { $args = func_get_args(); foreach ($args as $arg) { foreach ($arg as $key=>$value) { if (!defined($value)) { define($value, $key); } else { break 2; } } } } function getLog() { if (!defined('NET_SSH2_LOGGING')) { return false; } switch (NET_SSH2_LOGGING) { case NET_SSH2_LOG_SIMPLE: return $this->message_number_log; break; case NET_SSH2_LOG_COMPLEX: return $this->_format_log($this->message_log, $this->message_number_log); break; default: return false; } } function _format_log($message_log, $message_number_log) { $output = ''; for ($i = 0; $i < count($message_log); $i++) { $output.= $message_number_log[$i] . "\r\n"; $current_log = $message_log[$i]; $j = 0; do { if (strlen($current_log)) { $output.= str_pad(dechex($j), 7, '0', STR_PAD_LEFT) . '0 '; } $fragment = $this->_string_shift($current_log, $this->log_short_width); $hex = substr(preg_replace_callback('#.#s', array($this, '_format_log_helper'), $fragment), strlen($this->log_boundary)); $raw = preg_replace('#[^\x20-\x7E]|<#', '.', $fragment); $output.= str_pad($hex, $this->log_long_width - $this->log_short_width, ' ') . $raw . "\r\n"; $j++; } while (strlen($current_log)); $output.= "\r\n"; } return $output; } function _format_log_helper($matches) { return $this->log_boundary . str_pad(dechex(ord($matches[0])), 2, '0', STR_PAD_LEFT); } function getErrors() { return $this->errors; } function getLastError() { return $this->errors[count($this->errors) - 1]; } function getServerIdentification() { $this->_connect(); return $this->server_identifier; } function getKexAlgorithms() { $this->_connect(); return $this->kex_algorithms; } function getServerHostKeyAlgorithms() { $this->_connect(); return $this->server_host_key_algorithms; } function getEncryptionAlgorithmsClient2Server() { $this->_connect(); return $this->encryption_algorithms_client_to_server; } function getEncryptionAlgorithmsServer2Client() { $this->_connect(); return $this->encryption_algorithms_server_to_client; } function getMACAlgorithmsClient2Server() { $this->_connect(); return $this->mac_algorithms_client_to_server; } function getMACAlgorithmsServer2Client() { $this->_connect(); return $this->mac_algorithms_server_to_client; } function getCompressionAlgorithmsClient2Server() { $this->_connect(); return $this->compression_algorithms_client_to_server; } function getCompressionAlgorithmsServer2Client() { $this->_connect(); return $this->compression_algorithms_server_to_client; } function getLanguagesServer2Client() { $this->_connect(); return $this->languages_server_to_client; } function getLanguagesClient2Server() { $this->_connect(); return $this->languages_client_to_server; } function getBannerMessage() { return $this->banner_message; } function getServerPublicHostKey() { if (!($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR)) { if (!$this->_connect()) { return false; } } $signature = $this->signature; $server_public_host_key = $this->server_public_host_key; extract(unpack('Nlength', $this->_string_shift($server_public_host_key, 4))); $this->_string_shift($server_public_host_key, $length); if ($this->signature_validated) { return $this->bitmap ? $this->signature_format . ' ' . base64_encode($this->server_public_host_key) : false; } $this->signature_validated = true; switch ($this->signature_format) { case 'ssh-dss': $zero = new Math_BigInteger(); $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); $p = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256); $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); $q = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256); $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); $g = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256); $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); $y = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256); $temp = unpack('Nlength', $this->_string_shift($signature, 4)); if ($temp['length'] != 40) { user_error('Invalid signature'); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } $r = new Math_BigInteger($this->_string_shift($signature, 20), 256); $s = new Math_BigInteger($this->_string_shift($signature, 20), 256); switch (true) { case $r->equals($zero): case $r->compare($q) >= 0: case $s->equals($zero): case $s->compare($q) >= 0: user_error('Invalid signature'); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } $w = $s->modInverse($q); $u1 = $w->multiply(new Math_BigInteger(sha1($this->exchange_hash), 16)); list(, $u1) = $u1->divide($q); $u2 = $w->multiply($r); list(, $u2) = $u2->divide($q); $g = $g->modPow($u1, $p); $y = $y->modPow($u2, $p); $v = $g->multiply($y); list(, $v) = $v->divide($p); list(, $v) = $v->divide($q); if (!$v->equals($r)) { user_error('Bad server signature'); return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE); } break; case 'ssh-rsa': $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); $e = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256); $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); $rawN = $this->_string_shift($server_public_host_key, $temp['length']); $n = new Math_BigInteger($rawN, -256); $nLength = strlen(ltrim($rawN, "\0")); $temp = unpack('Nlength', $this->_string_shift($signature, 4)); $s = new Math_BigInteger($this->_string_shift($signature, $temp['length']), 256); if ($s->compare(new Math_BigInteger()) < 0 || $s->compare($n->subtract(new Math_BigInteger(1))) > 0) { user_error('Invalid signature'); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } $s = $s->modPow($e, $n); $s = $s->toBytes(); $h = pack('N4H*', 0x00302130, 0x0906052B, 0x0E03021A, 0x05000414, sha1($this->exchange_hash)); $h = chr(0x01) . str_repeat(chr(0xFF), $nLength - 2 - strlen($h)) . $h; if ($s != $h) { user_error('Bad server signature'); return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE); } break; default: user_error('Unsupported signature format'); return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE); } return $this->signature_format . ' ' . base64_encode($this->server_public_host_key); } function getExitStatus() { if (is_null($this->exit_status)) { return false; } return $this->exit_status; } function getWindowColumns() { return $this->windowColumns; } function getWindowRows() { return $this->windowRows; } function setWindowColumns($value) { $this->windowColumns = $value; } function setWindowRows($value) { $this->windowRows = $value; } function setWindowSize($columns = 80, $rows = 24) { $this->windowColumns = $columns; $this->windowRows = $rows; } }
/* End of Net-SSH2
Copyright (c) 2015 phpseclib Developer
Released under the MIT license
https://github.com/phpseclib/phpseclib/blob/master/LICENSE
*/
//Core.
if ($argc != 5) { die("Require: prefix start end domain username"); } fwrite(STDOUT, 'ServerPass: '); if (strncasecmp(PHP_OS, 'WIN', 3) === 0) { @flock(STDIN, LOCK_EX); $password = fgets(STDIN); @flock(STDIN, LOCK_UN); } else { system('stty -echo'); @flock(STDIN, LOCK_EX); $password = fgets(STDIN); @flock(STDIN, LOCK_UN); system('stty echo'); } fwrite(STDOUT, "\n"); if (!isset($password)) { die('Error Username'); } $len = strlen($argv[4]); if ($len > 255) { die("Error"); } if ($len !== strspn($host, 'abcdefghijklmnopqrstuvwxyzABCEDFGHIJKLMNOPQRSTUVWXYZ1234567890-.')) { die("Error"); } $labels = explode('.', $host); foreach($labels as $v) { $label_len = strlen($v); if (!$label_len || $label_len > 63) { die("Error"); } } $num = $argv[2]; while($num != $argv[3])) { $ssh = new Net_SSH2($argv[1] . '.'. $num . $argv[4]); $ssh -> login($argv[5], $password);
$ssh -> read('[prompt]');
/* Script */
/*$ssh -> write("sudo apt-get install \n");
$ssh -> read('Password:');
$ssh -> write($password . " \n");
$ssh -> read('[prompt]');
$ssh -> write("echo done,etc..."); */
$ssh -> read('[prompt]');
$ssh -> write("exit");
$num++; } echo "Done Server Building.";
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment