Exemple #1
0
 /**
  * Default Constructor.
  *
  * Connects to an SSHv1 server
  *
  * @param String $host
  * @param optional Integer $port
  * @param optional Integer $timeout
  * @param optional Integer $cipher
  * @return SSH1
  * @access public
  */
 public function __construct($host, $port = 22, $timeout = 10, $cipher = SSH1_CIPHER_3DES)
 {
     $this->protocol_flags = array(1 => 'SSH1_MSG_DISCONNECT', 2 => 'SSH1_SMSG_PUBLIC_KEY', 3 => 'SSH1_CMSG_SESSION_KEY', 4 => 'SSH1_CMSG_USER', 9 => 'SSH1_CMSG_AUTH_PASSWORD', 10 => 'SSH1_CMSG_REQUEST_PTY', 12 => 'SSH1_CMSG_EXEC_SHELL', 13 => 'SSH1_CMSG_EXEC_CMD', 14 => 'SSH1_SMSG_SUCCESS', 15 => 'SSH1_SMSG_FAILURE', 16 => 'SSH1_CMSG_STDIN_DATA', 17 => 'SSH1_SMSG_STDOUT_DATA', 18 => 'SSH1_SMSG_STDERR_DATA', 19 => 'SSH1_CMSG_EOF', 20 => 'SSH1_SMSG_EXITSTATUS', 33 => 'SSH1_CMSG_EXIT_CONFIRMATION');
     $this->_define_array($this->protocol_flags);
     $this->fsock = @fsockopen($host, $port, $errno, $errstr, $timeout);
     if (!$this->fsock) {
         user_error(rtrim("Cannot connect to {$host}. Error {$errno}. {$errstr}"), E_USER_NOTICE);
         return;
     }
     $this->server_identification = $init_line = fgets($this->fsock, 255);
     if (defined('SSH1_LOGGING')) {
         $this->protocol_flags_log[] = '<-';
         $this->protocol_flags_log[] = '->';
         if (SSH1_LOGGING == SSH1_LOG_COMPLEX) {
             $this->message_log[] = $this->server_identification;
             $this->message_log[] = $this->identifier . "\r\n";
         }
     }
     if (!preg_match('#SSH-([0-9\\.]+)-(.+)#', $init_line, $parts)) {
         user_error('Can only connect to SSH servers', E_USER_NOTICE);
         return;
     }
     if ($parts[1][0] != 1) {
         user_error("Cannot connect to SSH {$parts['1']} servers", E_USER_NOTICE);
         return;
     }
     fputs($this->fsock, $this->identifier . "\r\n");
     $response = $this->_get_binary_packet();
     if ($response[SSH1_RESPONSE_TYPE] != SSH1_SMSG_PUBLIC_KEY) {
         user_error('Expected SSH_SMSG_PUBLIC_KEY', E_USER_NOTICE);
         return;
     }
     $anti_spoofing_cookie = $this->_string_shift($response[SSH1_RESPONSE_DATA], 8);
     $this->_string_shift($response[SSH1_RESPONSE_DATA], 4);
     $temp = unpack('nlen', $this->_string_shift($response[SSH1_RESPONSE_DATA], 2));
     $server_key_public_exponent = new BigInteger($this->_string_shift($response[SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
     $this->server_key_public_exponent = $server_key_public_exponent;
     $temp = unpack('nlen', $this->_string_shift($response[SSH1_RESPONSE_DATA], 2));
     $server_key_public_modulus = new BigInteger($this->_string_shift($response[SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
     $this->server_key_public_modulus = $server_key_public_modulus;
     $this->_string_shift($response[SSH1_RESPONSE_DATA], 4);
     $temp = unpack('nlen', $this->_string_shift($response[SSH1_RESPONSE_DATA], 2));
     $host_key_public_exponent = new BigInteger($this->_string_shift($response[SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
     $this->host_key_public_exponent = $host_key_public_exponent;
     $temp = unpack('nlen', $this->_string_shift($response[SSH1_RESPONSE_DATA], 2));
     $host_key_public_modulus = new BigInteger($this->_string_shift($response[SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
     $this->host_key_public_modulus = $host_key_public_modulus;
     $this->_string_shift($response[SSH1_RESPONSE_DATA], 4);
     // get a list of the supported ciphers
     extract(unpack('Nsupported_ciphers_mask', $this->_string_shift($response[SSH1_RESPONSE_DATA], 4)));
     foreach ($this->supported_ciphers as $mask => $name) {
         if (($supported_ciphers_mask & 1 << $mask) == 0) {
             unset($this->supported_ciphers[$mask]);
         }
     }
     // get a list of the supported authentications
     extract(unpack('Nsupported_authentications_mask', $this->_string_shift($response[SSH1_RESPONSE_DATA], 4)));
     foreach ($this->supported_authentications as $mask => $name) {
         if (($supported_authentications_mask & 1 << $mask) == 0) {
             unset($this->supported_authentications[$mask]);
         }
     }
     $session_id = pack('H*', md5($host_key_public_modulus->toBytes() . $server_key_public_modulus->toBytes() . $anti_spoofing_cookie));
     $session_key = '';
     for ($i = 0; $i < 32; $i++) {
         $session_key .= chr(Random(0, 255));
     }
     $double_encrypted_session_key = $session_key ^ str_pad($session_id, 32, chr(0));
     if ($server_key_public_modulus->compare($host_key_public_modulus) < 0) {
         $double_encrypted_session_key = $this->_rsa_crypt($double_encrypted_session_key, array($server_key_public_exponent, $server_key_public_modulus));
         $double_encrypted_session_key = $this->_rsa_crypt($double_encrypted_session_key, array($host_key_public_exponent, $host_key_public_modulus));
     } else {
         $double_encrypted_session_key = $this->_rsa_crypt($double_encrypted_session_key, array($host_key_public_exponent, $host_key_public_modulus));
         $double_encrypted_session_key = $this->_rsa_crypt($double_encrypted_session_key, array($server_key_public_exponent, $server_key_public_modulus));
     }
     $cipher = isset($this->supported_ciphers[$cipher]) ? $cipher : SSH1_CIPHER_3DES;
     $data = pack('C2a*na*N', SSH1_CMSG_SESSION_KEY, $cipher, $anti_spoofing_cookie, 8 * strlen($double_encrypted_session_key), $double_encrypted_session_key, 0);
     if (!$this->_send_binary_packet($data)) {
         user_error('Error sending SSH_CMSG_SESSION_KEY', E_USER_NOTICE);
         return;
     }
     switch ($cipher) {
         //case SSH1_CIPHER_NONE:
         //    $this->crypto = new Crypt_Null();
         //    break;
         case SSH1_CIPHER_DES:
             $this->crypto = new DES();
             $this->crypto->disablePadding();
             $this->crypto->enableContinuousBuffer();
             $this->crypto->setKey(substr($session_key, 0, 8));
             break;
         case SSH1_CIPHER_3DES:
             $this->crypto = new TripleDES(DES_MODE_3CBC);
             $this->crypto->disablePadding();
             $this->crypto->enableContinuousBuffer();
             $this->crypto->setKey(substr($session_key, 0, 24));
             break;
             //case SSH1_CIPHER_RC4:
             //    $this->crypto = new RC4();
             //    $this->crypto->enableContinuousBuffer();
             //    $this->crypto->setKey(substr($session_key, 0,  16));
             //    break;
     }
     $response = $this->_get_binary_packet();
     if ($response[SSH1_RESPONSE_TYPE] != SSH1_SMSG_SUCCESS) {
         user_error('Expected SSH_SMSG_SUCCESS', E_USER_NOTICE);
         return;
     }
     $this->bitmap = SSH1_MASK_CONSTRUCTOR;
 }
Exemple #2
0
 /**
  * RSAVP1
  *
  * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.2 RFC3447#section-5.2.2}.
  *
  * @access private
  * @param BigInteger $s
  * @return BigInteger
  */
 function _rsavp1($s)
 {
     if ($s->compare($this->zero) < 0 || $s->compare($this->modulus) > 0) {
         user_error('Signature representative out of range', E_USER_NOTICE);
         return false;
     }
     return $this->_exponentiate($s);
 }
Exemple #3
0
 /**
  * Returns the server public host key.
  *
  * Caching this the first time you connect to a server and checking the result on subsequent connections
  * is recommended.  Returns false if the server signature is not signed correctly with the public host key.
  *
  * @return Mixed
  * @access public
  */
 function getServerPublicHostKey()
 {
     $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);
     switch ($this->signature_format) {
         case 'ssh-dss':
             $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
             $p = new BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
             $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
             $q = new BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
             $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
             $g = new BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
             $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
             $y = new BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
             /* The value for 'dss_signature_blob' is encoded as a string containing
                r, followed by s (which are 160-bit integers, without lengths or
                padding, unsigned, and in network byte order). */
             $temp = unpack('Nlength', $this->_string_shift($signature, 4));
             if ($temp['length'] != 40) {
                 user_error('Invalid signature', E_USER_NOTICE);
                 return $this->_disconnect(SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
             }
             $r = new BigInteger($this->_string_shift($signature, 20), 256);
             $s = new BigInteger($this->_string_shift($signature, 20), 256);
             if ($r->compare($q) >= 0 || $s->compare($q) >= 0) {
                 user_error('Invalid signature', E_USER_NOTICE);
                 return $this->_disconnect(SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
             }
             $w = $s->modInverse($q);
             $u1 = $w->multiply(new 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', E_USER_NOTICE);
                 return $this->_disconnect(SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
             }
             break;
         case 'ssh-rsa':
             $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
             $e = new BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
             $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
             $n = new BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
             $nLength = $temp['length'];
             /*
             $temp = unpack('Nlength', $this->_string_shift($signature, 4));
             $signature = $this->_string_shift($signature, $temp['length']);
             
             if (!class_exists('RSA')) {
                 require_once('Crypt/RSA.php');
             }
             
             $rsa = new RSA();
             $rsa->setSignatureMode(RSA_SIGNATURE_PKCS1);
             $rsa->loadKey(array('e' => $e, 'n' => $n), RSA_PUBLIC_FORMAT_RAW);
             if (!$rsa->verify($this->exchange_hash, $signature)) {
                 user_error('Bad server signature', E_USER_NOTICE);
                 return $this->_disconnect(SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
             }
             */
             $temp = unpack('Nlength', $this->_string_shift($signature, 4));
             $s = new BigInteger($this->_string_shift($signature, $temp['length']), 256);
             // validate an RSA signature per "8.2 RSASSA-PKCS1-v1_5", "5.2.2 RSAVP1", and "9.1 EMSA-PSS" in the
             // following URL:
             // ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.pdf
             // also, see SSHRSA.c (rsa2_verifysig) in PuTTy's source.
             if ($s->compare(new BigInteger()) < 0 || $s->compare($n->subtract(new BigInteger(1))) > 0) {
                 user_error('Invalid signature', E_USER_NOTICE);
                 return $this->_disconnect(SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
             }
             $s = $s->modPow($e, $n);
             $s = $s->toBytes();
             $h = pack('N4H*', 0x302130, 0x906052b, 0xe03021a, 0x5000414, sha1($this->exchange_hash));
             $h = chr(0x1) . str_repeat(chr(0xff), $nLength - 3 - strlen($h)) . $h;
             if ($s != $h) {
                 user_error('Bad server signature', E_USER_NOTICE);
                 return $this->_disconnect(SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
             }
     }
     return $this->server_public_host_key;
 }