SSH1.php 51 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608
  1. <?php
  2. /**
  3. * Pure-PHP implementation of SSHv1.
  4. *
  5. * PHP version 5
  6. *
  7. * Here's a short example of how to use this library:
  8. * <code>
  9. * <?php
  10. * include 'vendor/autoload.php';
  11. *
  12. * $ssh = new \phpseclib\Net\SSH1('www.domain.tld');
  13. * if (!$ssh->login('username', 'password')) {
  14. * exit('Login Failed');
  15. * }
  16. *
  17. * echo $ssh->exec('ls -la');
  18. * ?>
  19. * </code>
  20. *
  21. * Here's another short example:
  22. * <code>
  23. * <?php
  24. * include 'vendor/autoload.php';
  25. *
  26. * $ssh = new \phpseclib\Net\SSH1('www.domain.tld');
  27. * if (!$ssh->login('username', 'password')) {
  28. * exit('Login Failed');
  29. * }
  30. *
  31. * echo $ssh->read('username@username:~$');
  32. * $ssh->write("ls -la\n");
  33. * echo $ssh->read('username@username:~$');
  34. * ?>
  35. * </code>
  36. *
  37. * More information on the SSHv1 specification can be found by reading
  38. * {@link http://www.snailbook.com/docs/protocol-1.5.txt protocol-1.5.txt}.
  39. *
  40. * @category Net
  41. * @package SSH1
  42. * @author Jim Wigginton <terrafrost@php.net>
  43. * @copyright 2007 Jim Wigginton
  44. * @license http://www.opensource.org/licenses/mit-license.html MIT License
  45. * @link http://phpseclib.sourceforge.net
  46. */
  47. namespace phpseclib\Net;
  48. use ParagonIE\ConstantTime\Hex;
  49. use phpseclib\Crypt\DES;
  50. use phpseclib\Crypt\Random;
  51. use phpseclib\Crypt\TripleDES;
  52. use phpseclib\Math\BigInteger;
  53. /**
  54. * Pure-PHP implementation of SSHv1.
  55. *
  56. * @package SSH1
  57. * @author Jim Wigginton <terrafrost@php.net>
  58. * @access public
  59. */
  60. class SSH1
  61. {
  62. /**#@+
  63. * Encryption Methods
  64. *
  65. * @see \phpseclib\Net\SSH1::getSupportedCiphers()
  66. * @access public
  67. */
  68. /**
  69. * No encryption
  70. *
  71. * Not supported.
  72. */
  73. const CIPHER_NONE = 0;
  74. /**
  75. * IDEA in CFB mode
  76. *
  77. * Not supported.
  78. */
  79. const CIPHER_IDEA = 1;
  80. /**
  81. * DES in CBC mode
  82. */
  83. const CIPHER_DES = 2;
  84. /**
  85. * Triple-DES in CBC mode
  86. *
  87. * All implementations are required to support this
  88. */
  89. const CIPHER_3DES = 3;
  90. /**
  91. * TRI's Simple Stream encryption CBC
  92. *
  93. * Not supported nor is it defined in the official SSH1 specs. OpenSSH, however, does define it (see cipher.h),
  94. * although it doesn't use it (see cipher.c)
  95. */
  96. const CIPHER_BROKEN_TSS = 4;
  97. /**
  98. * RC4
  99. *
  100. * Not supported.
  101. *
  102. * @internal According to the SSH1 specs:
  103. *
  104. * "The first 16 bytes of the session key are used as the key for
  105. * the server to client direction. The remaining 16 bytes are used
  106. * as the key for the client to server direction. This gives
  107. * independent 128-bit keys for each direction."
  108. *
  109. * This library currently only supports encryption when the same key is being used for both directions. This is
  110. * because there's only one $crypto object. Two could be added ($encrypt and $decrypt, perhaps).
  111. */
  112. const CIPHER_RC4 = 5;
  113. /**
  114. * Blowfish
  115. *
  116. * Not supported nor is it defined in the official SSH1 specs. OpenSSH, however, defines it (see cipher.h) and
  117. * uses it (see cipher.c)
  118. */
  119. const CIPHER_BLOWFISH = 6;
  120. /**#@-*/
  121. /**#@+
  122. * Authentication Methods
  123. *
  124. * @see \phpseclib\Net\SSH1::getSupportedAuthentications()
  125. * @access public
  126. */
  127. /**
  128. * .rhosts or /etc/hosts.equiv
  129. */
  130. const AUTH_RHOSTS = 1;
  131. /**
  132. * pure RSA authentication
  133. */
  134. const AUTH_RSA = 2;
  135. /**
  136. * password authentication
  137. *
  138. * This is the only method that is supported by this library.
  139. */
  140. const AUTH_PASSWORD = 3;
  141. /**
  142. * .rhosts with RSA host authentication
  143. */
  144. const AUTH_RHOSTS_RSA = 4;
  145. /**#@-*/
  146. /**#@+
  147. * Terminal Modes
  148. *
  149. * @link http://3sp.com/content/developer/maverick-net/docs/Maverick.SSH.PseudoTerminalModesMembers.html
  150. * @access private
  151. */
  152. const TTY_OP_END = 0;
  153. /**#@-*/
  154. /**
  155. * The Response Type
  156. *
  157. * @see \phpseclib\Net\SSH1::_get_binary_packet()
  158. * @access private
  159. */
  160. const RESPONSE_TYPE = 1;
  161. /**
  162. * The Response Data
  163. *
  164. * @see \phpseclib\Net\SSH1::_get_binary_packet()
  165. * @access private
  166. */
  167. const RESPONSE_DATA = 2;
  168. /**#@+
  169. * Execution Bitmap Masks
  170. *
  171. * @see \phpseclib\Net\SSH1::bitmap
  172. * @access private
  173. */
  174. const MASK_CONSTRUCTOR = 0x00000001;
  175. const MASK_CONNECTED = 0x00000002;
  176. const MASK_LOGIN = 0x00000004;
  177. const MASK_SHELL = 0x00000008;
  178. /**#@-*/
  179. /**#@+
  180. * @access public
  181. * @see \phpseclib\Net\SSH1::getLog()
  182. */
  183. /**
  184. * Returns the message numbers
  185. */
  186. const LOG_SIMPLE = 1;
  187. /**
  188. * Returns the message content
  189. */
  190. const LOG_COMPLEX = 2;
  191. /**
  192. * Outputs the content real-time
  193. */
  194. const LOG_REALTIME = 3;
  195. /**
  196. * Dumps the content real-time to a file
  197. */
  198. const LOG_REALTIME_FILE = 4;
  199. /**#@-*/
  200. /**#@+
  201. * @access public
  202. * @see \phpseclib\Net\SSH1::read()
  203. */
  204. /**
  205. * Returns when a string matching $expect exactly is found
  206. */
  207. const READ_SIMPLE = 1;
  208. /**
  209. * Returns when a string matching the regular expression $expect is found
  210. */
  211. const READ_REGEX = 2;
  212. /**#@-*/
  213. /**
  214. * The SSH identifier
  215. *
  216. * @var string
  217. * @access private
  218. */
  219. var $identifier = 'SSH-1.5-phpseclib';
  220. /**
  221. * The Socket Object
  222. *
  223. * @var object
  224. * @access private
  225. */
  226. var $fsock;
  227. /**
  228. * The cryptography object
  229. *
  230. * @var object
  231. * @access private
  232. */
  233. var $crypto = false;
  234. /**
  235. * Execution Bitmap
  236. *
  237. * The bits that are set represent functions that have been called already. This is used to determine
  238. * if a requisite function has been successfully executed. If not, an error should be thrown.
  239. *
  240. * @var int
  241. * @access private
  242. */
  243. var $bitmap = 0;
  244. /**
  245. * The Server Key Public Exponent
  246. *
  247. * Logged for debug purposes
  248. *
  249. * @see self::getServerKeyPublicExponent()
  250. * @var string
  251. * @access private
  252. */
  253. var $server_key_public_exponent;
  254. /**
  255. * The Server Key Public Modulus
  256. *
  257. * Logged for debug purposes
  258. *
  259. * @see self::getServerKeyPublicModulus()
  260. * @var string
  261. * @access private
  262. */
  263. var $server_key_public_modulus;
  264. /**
  265. * The Host Key Public Exponent
  266. *
  267. * Logged for debug purposes
  268. *
  269. * @see self::getHostKeyPublicExponent()
  270. * @var string
  271. * @access private
  272. */
  273. var $host_key_public_exponent;
  274. /**
  275. * The Host Key Public Modulus
  276. *
  277. * Logged for debug purposes
  278. *
  279. * @see self::getHostKeyPublicModulus()
  280. * @var string
  281. * @access private
  282. */
  283. var $host_key_public_modulus;
  284. /**
  285. * Supported Ciphers
  286. *
  287. * Logged for debug purposes
  288. *
  289. * @see self::getSupportedCiphers()
  290. * @var array
  291. * @access private
  292. */
  293. var $supported_ciphers = array(
  294. self::CIPHER_NONE => 'No encryption',
  295. self::CIPHER_IDEA => 'IDEA in CFB mode',
  296. self::CIPHER_DES => 'DES in CBC mode',
  297. self::CIPHER_3DES => 'Triple-DES in CBC mode',
  298. self::CIPHER_BROKEN_TSS => 'TRI\'s Simple Stream encryption CBC',
  299. self::CIPHER_RC4 => 'RC4',
  300. self::CIPHER_BLOWFISH => 'Blowfish'
  301. );
  302. /**
  303. * Supported Authentications
  304. *
  305. * Logged for debug purposes
  306. *
  307. * @see self::getSupportedAuthentications()
  308. * @var array
  309. * @access private
  310. */
  311. var $supported_authentications = array(
  312. self::AUTH_RHOSTS => '.rhosts or /etc/hosts.equiv',
  313. self::AUTH_RSA => 'pure RSA authentication',
  314. self::AUTH_PASSWORD => 'password authentication',
  315. self::AUTH_RHOSTS_RSA => '.rhosts with RSA host authentication'
  316. );
  317. /**
  318. * Server Identification
  319. *
  320. * @see self::getServerIdentification()
  321. * @var string
  322. * @access private
  323. */
  324. var $server_identification = '';
  325. /**
  326. * Protocol Flags
  327. *
  328. * @see self::__construct()
  329. * @var array
  330. * @access private
  331. */
  332. var $protocol_flags = array();
  333. /**
  334. * Protocol Flag Log
  335. *
  336. * @see self::getLog()
  337. * @var array
  338. * @access private
  339. */
  340. var $protocol_flag_log = array();
  341. /**
  342. * Message Log
  343. *
  344. * @see self::getLog()
  345. * @var array
  346. * @access private
  347. */
  348. var $message_log = array();
  349. /**
  350. * Real-time log file pointer
  351. *
  352. * @see self::_append_log()
  353. * @var resource
  354. * @access private
  355. */
  356. var $realtime_log_file;
  357. /**
  358. * Real-time log file size
  359. *
  360. * @see self::_append_log()
  361. * @var int
  362. * @access private
  363. */
  364. var $realtime_log_size;
  365. /**
  366. * Real-time log file wrap boolean
  367. *
  368. * @see self::_append_log()
  369. * @var bool
  370. * @access private
  371. */
  372. var $realtime_log_wrap;
  373. /**
  374. * Interactive Buffer
  375. *
  376. * @see self::read()
  377. * @var array
  378. * @access private
  379. */
  380. var $interactiveBuffer = '';
  381. /**
  382. * Timeout
  383. *
  384. * @see self::setTimeout()
  385. * @access private
  386. */
  387. var $timeout;
  388. /**
  389. * Current Timeout
  390. *
  391. * @see self::_get_channel_packet()
  392. * @access private
  393. */
  394. var $curTimeout;
  395. /**
  396. * Log Boundary
  397. *
  398. * @see self::_format_log()
  399. * @access private
  400. */
  401. var $log_boundary = ':';
  402. /**
  403. * Log Long Width
  404. *
  405. * @see self::_format_log()
  406. * @access private
  407. */
  408. var $log_long_width = 65;
  409. /**
  410. * Log Short Width
  411. *
  412. * @see self::_format_log()
  413. * @access private
  414. */
  415. var $log_short_width = 16;
  416. /**
  417. * Hostname
  418. *
  419. * @see self::__construct()
  420. * @see self::_connect()
  421. * @var string
  422. * @access private
  423. */
  424. var $host;
  425. /**
  426. * Port Number
  427. *
  428. * @see self::__construct()
  429. * @see self::_connect()
  430. * @var int
  431. * @access private
  432. */
  433. var $port;
  434. /**
  435. * Timeout for initial connection
  436. *
  437. * Set by the constructor call. Calling setTimeout() is optional. If it's not called functions like
  438. * exec() won't timeout unless some PHP setting forces it too. The timeout specified in the constructor,
  439. * however, is non-optional. There will be a timeout, whether or not you set it. If you don't it'll be
  440. * 10 seconds. It is used by fsockopen() in that function.
  441. *
  442. * @see self::__construct()
  443. * @see self::_connect()
  444. * @var int
  445. * @access private
  446. */
  447. var $connectionTimeout;
  448. /**
  449. * Default cipher
  450. *
  451. * @see self::__construct()
  452. * @see self::_connect()
  453. * @var int
  454. * @access private
  455. */
  456. var $cipher;
  457. /**
  458. * Default Constructor.
  459. *
  460. * Connects to an SSHv1 server
  461. *
  462. * @param string $host
  463. * @param int $port
  464. * @param int $timeout
  465. * @param int $cipher
  466. * @return \phpseclib\Net\SSH1
  467. * @access public
  468. */
  469. function __construct($host, $port = 22, $timeout = 10, $cipher = self::CIPHER_3DES)
  470. {
  471. $this->protocol_flags = array(
  472. 1 => 'NET_SSH1_MSG_DISCONNECT',
  473. 2 => 'NET_SSH1_SMSG_PUBLIC_KEY',
  474. 3 => 'NET_SSH1_CMSG_SESSION_KEY',
  475. 4 => 'NET_SSH1_CMSG_USER',
  476. 9 => 'NET_SSH1_CMSG_AUTH_PASSWORD',
  477. 10 => 'NET_SSH1_CMSG_REQUEST_PTY',
  478. 12 => 'NET_SSH1_CMSG_EXEC_SHELL',
  479. 13 => 'NET_SSH1_CMSG_EXEC_CMD',
  480. 14 => 'NET_SSH1_SMSG_SUCCESS',
  481. 15 => 'NET_SSH1_SMSG_FAILURE',
  482. 16 => 'NET_SSH1_CMSG_STDIN_DATA',
  483. 17 => 'NET_SSH1_SMSG_STDOUT_DATA',
  484. 18 => 'NET_SSH1_SMSG_STDERR_DATA',
  485. 19 => 'NET_SSH1_CMSG_EOF',
  486. 20 => 'NET_SSH1_SMSG_EXITSTATUS',
  487. 33 => 'NET_SSH1_CMSG_EXIT_CONFIRMATION'
  488. );
  489. $this->_define_array($this->protocol_flags);
  490. $this->host = $host;
  491. $this->port = $port;
  492. $this->connectionTimeout = $timeout;
  493. $this->cipher = $cipher;
  494. }
  495. /**
  496. * Connect to an SSHv1 server
  497. *
  498. * @return bool
  499. * @throws \UnexpectedValueException on receipt of unexpected packets
  500. * @throws \RuntimeException on other errors
  501. * @access private
  502. */
  503. function _connect()
  504. {
  505. $this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $this->connectionTimeout);
  506. if (!$this->fsock) {
  507. throw new \RuntimeException(rtrim("Cannot connect to $host. Error $errno. $errstr"));
  508. }
  509. $this->server_identification = $init_line = fgets($this->fsock, 255);
  510. if (defined('NET_SSH1_LOGGING')) {
  511. $this->_append_log('<-', $this->server_identification);
  512. $this->_append_log('->', $this->identifier . "\r\n");
  513. }
  514. if (!preg_match('#SSH-([0-9\.]+)-(.+)#', $init_line, $parts)) {
  515. throw new \RuntimeException('Can only connect to SSH servers');
  516. }
  517. if ($parts[1][0] != 1) {
  518. throw new \RuntimeException("Cannot connect to $parts[1] servers");
  519. }
  520. fputs($this->fsock, $this->identifier."\r\n");
  521. $response = $this->_get_binary_packet();
  522. if ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_PUBLIC_KEY) {
  523. throw new \UnexpectedValueException('Expected SSH_SMSG_PUBLIC_KEY');
  524. }
  525. $anti_spoofing_cookie = $this->_string_shift($response[self::RESPONSE_DATA], 8);
  526. $this->_string_shift($response[self::RESPONSE_DATA], 4);
  527. $temp = unpack('nlen', $this->_string_shift($response[self::RESPONSE_DATA], 2));
  528. $server_key_public_exponent = new BigInteger($this->_string_shift($response[self::RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
  529. $this->server_key_public_exponent = $server_key_public_exponent;
  530. $temp = unpack('nlen', $this->_string_shift($response[self::RESPONSE_DATA], 2));
  531. $server_key_public_modulus = new BigInteger($this->_string_shift($response[self::RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
  532. $this->server_key_public_modulus = $server_key_public_modulus;
  533. $this->_string_shift($response[self::RESPONSE_DATA], 4);
  534. $temp = unpack('nlen', $this->_string_shift($response[self::RESPONSE_DATA], 2));
  535. $host_key_public_exponent = new BigInteger($this->_string_shift($response[self::RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
  536. $this->host_key_public_exponent = $host_key_public_exponent;
  537. $temp = unpack('nlen', $this->_string_shift($response[self::RESPONSE_DATA], 2));
  538. $host_key_public_modulus = new BigInteger($this->_string_shift($response[self::RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
  539. $this->host_key_public_modulus = $host_key_public_modulus;
  540. $this->_string_shift($response[self::RESPONSE_DATA], 4);
  541. // get a list of the supported ciphers
  542. extract(unpack('Nsupported_ciphers_mask', $this->_string_shift($response[self::RESPONSE_DATA], 4)));
  543. foreach ($this->supported_ciphers as $mask => $name) {
  544. if (($supported_ciphers_mask & (1 << $mask)) == 0) {
  545. unset($this->supported_ciphers[$mask]);
  546. }
  547. }
  548. // get a list of the supported authentications
  549. extract(unpack('Nsupported_authentications_mask', $this->_string_shift($response[self::RESPONSE_DATA], 4)));
  550. foreach ($this->supported_authentications as $mask => $name) {
  551. if (($supported_authentications_mask & (1 << $mask)) == 0) {
  552. unset($this->supported_authentications[$mask]);
  553. }
  554. }
  555. $session_id = md5($host_key_public_modulus->toBytes() . $server_key_public_modulus->toBytes() . $anti_spoofing_cookie, true);
  556. $session_key = Random::string(32);
  557. $double_encrypted_session_key = $session_key ^ str_pad($session_id, 32, chr(0));
  558. if ($server_key_public_modulus->compare($host_key_public_modulus) < 0) {
  559. $double_encrypted_session_key = $this->_rsa_crypt(
  560. $double_encrypted_session_key,
  561. array(
  562. $server_key_public_exponent,
  563. $server_key_public_modulus
  564. )
  565. );
  566. $double_encrypted_session_key = $this->_rsa_crypt(
  567. $double_encrypted_session_key,
  568. array(
  569. $host_key_public_exponent,
  570. $host_key_public_modulus
  571. )
  572. );
  573. } else {
  574. $double_encrypted_session_key = $this->_rsa_crypt(
  575. $double_encrypted_session_key,
  576. array(
  577. $host_key_public_exponent,
  578. $host_key_public_modulus
  579. )
  580. );
  581. $double_encrypted_session_key = $this->_rsa_crypt(
  582. $double_encrypted_session_key,
  583. array(
  584. $server_key_public_exponent,
  585. $server_key_public_modulus
  586. )
  587. );
  588. }
  589. $cipher = isset($this->supported_ciphers[$this->cipher]) ? $this->cipher : self::CIPHER_3DES;
  590. $data = pack('C2a*na*N', NET_SSH1_CMSG_SESSION_KEY, $cipher, $anti_spoofing_cookie, 8 * strlen($double_encrypted_session_key), $double_encrypted_session_key, 0);
  591. if (!$this->_send_binary_packet($data)) {
  592. throw new \RuntimeException('Error sending SSH_CMSG_SESSION_KEY');
  593. }
  594. switch ($cipher) {
  595. //case self::CIPHER_NONE:
  596. // $this->crypto = new \phpseclib\Crypt\Null();
  597. // break;
  598. case self::CIPHER_DES:
  599. $this->crypto = new DES(DES::MODE_CBC);
  600. $this->crypto->disablePadding();
  601. $this->crypto->enableContinuousBuffer();
  602. $this->crypto->setKey(substr($session_key, 0, 8));
  603. // "The iv (initialization vector) is initialized to all zeroes."
  604. $this->crypto->setIV(str_repeat("\0", 8));
  605. break;
  606. case self::CIPHER_3DES:
  607. $this->crypto = new TripleDES(TripleDES::MODE_3CBC);
  608. $this->crypto->disablePadding();
  609. $this->crypto->enableContinuousBuffer();
  610. $this->crypto->setKey(substr($session_key, 0, 24));
  611. // "All three initialization vectors are initialized to zero."
  612. $this->crypto->setIV(str_repeat("\0", 8));
  613. break;
  614. //case self::CIPHER_RC4:
  615. // $this->crypto = new RC4();
  616. // $this->crypto->enableContinuousBuffer();
  617. // $this->crypto->setKey(substr($session_key, 0, 16));
  618. // break;
  619. }
  620. $response = $this->_get_binary_packet();
  621. if ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) {
  622. throw new \UnexpectedValueException('Expected SSH_SMSG_SUCCESS');
  623. }
  624. $this->bitmap = self::MASK_CONNECTED;
  625. return true;
  626. }
  627. /**
  628. * Login
  629. *
  630. * @param string $username
  631. * @param string $password
  632. * @return bool
  633. * @throws \UnexpectedValueException on receipt of unexpected packets
  634. * @throws \RuntimeException on other errors
  635. * @access public
  636. */
  637. function login($username, $password = '')
  638. {
  639. if (!($this->bitmap & self::MASK_CONSTRUCTOR)) {
  640. $this->bitmap |= self::MASK_CONSTRUCTOR;
  641. if (!$this->_connect()) {
  642. return false;
  643. }
  644. }
  645. if (!($this->bitmap & self::MASK_CONNECTED)) {
  646. return false;
  647. }
  648. $data = pack('CNa*', NET_SSH1_CMSG_USER, strlen($username), $username);
  649. if (!$this->_send_binary_packet($data)) {
  650. throw new \RuntimeException('Error sending SSH_CMSG_USER');
  651. }
  652. $response = $this->_get_binary_packet();
  653. if ($response === true) {
  654. return false;
  655. }
  656. if ($response[self::RESPONSE_TYPE] == NET_SSH1_SMSG_SUCCESS) {
  657. $this->bitmap |= self::MASK_LOGIN;
  658. return true;
  659. } elseif ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_FAILURE) {
  660. throw new \UnexpectedValueException('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE');
  661. }
  662. $data = pack('CNa*', NET_SSH1_CMSG_AUTH_PASSWORD, strlen($password), $password);
  663. if (!$this->_send_binary_packet($data)) {
  664. throw new \RuntimeException('Error sending SSH_CMSG_AUTH_PASSWORD');
  665. }
  666. // remove the username and password from the last logged packet
  667. if (defined('NET_SSH1_LOGGING') && NET_SSH1_LOGGING == self::LOG_COMPLEX) {
  668. $data = pack('CNa*', NET_SSH1_CMSG_AUTH_PASSWORD, strlen('password'), 'password');
  669. $this->message_log[count($this->message_log) - 1] = $data;
  670. }
  671. $response = $this->_get_binary_packet();
  672. if ($response === true) {
  673. return false;
  674. }
  675. if ($response[self::RESPONSE_TYPE] == NET_SSH1_SMSG_SUCCESS) {
  676. $this->bitmap |= self::MASK_LOGIN;
  677. return true;
  678. } elseif ($response[self::RESPONSE_TYPE] == NET_SSH1_SMSG_FAILURE) {
  679. return false;
  680. } else {
  681. throw new \UnexpectedValueException('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE');
  682. }
  683. }
  684. /**
  685. * Set Timeout
  686. *
  687. * $ssh->exec('ping 127.0.0.1'); on a Linux host will never return and will run indefinitely. setTimeout() makes it so it'll timeout.
  688. * Setting $timeout to false or 0 will mean there is no timeout.
  689. *
  690. * @param mixed $timeout
  691. */
  692. function setTimeout($timeout)
  693. {
  694. $this->timeout = $this->curTimeout = $timeout;
  695. }
  696. /**
  697. * Executes a command on a non-interactive shell, returns the output, and quits.
  698. *
  699. * An SSH1 server will close the connection after a command has been executed on a non-interactive shell. SSH2
  700. * servers don't, however, this isn't an SSH2 client. The way this works, on the server, is by initiating a
  701. * shell with the -s option, as discussed in the following links:
  702. *
  703. * {@link http://www.faqs.org/docs/bashman/bashref_65.html http://www.faqs.org/docs/bashman/bashref_65.html}
  704. * {@link http://www.faqs.org/docs/bashman/bashref_62.html http://www.faqs.org/docs/bashman/bashref_62.html}
  705. *
  706. * To execute further commands, a new \phpseclib\Net\SSH1 object will need to be created.
  707. *
  708. * Returns false on failure and the output, otherwise.
  709. *
  710. * @see self::interactiveRead()
  711. * @see self::interactiveWrite()
  712. * @param string $cmd
  713. * @return mixed
  714. * @throws \RuntimeException on error sending command
  715. * @access public
  716. */
  717. function exec($cmd, $block = true)
  718. {
  719. if (!($this->bitmap & self::MASK_LOGIN)) {
  720. throw new \RuntimeException('Operation disallowed prior to login()');
  721. }
  722. $data = pack('CNa*', NET_SSH1_CMSG_EXEC_CMD, strlen($cmd), $cmd);
  723. if (!$this->_send_binary_packet($data)) {
  724. throw new \RuntimeException('Error sending SSH_CMSG_EXEC_CMD');
  725. }
  726. if (!$block) {
  727. return true;
  728. }
  729. $output = '';
  730. $response = $this->_get_binary_packet();
  731. if ($response !== false) {
  732. do {
  733. $output.= substr($response[self::RESPONSE_DATA], 4);
  734. $response = $this->_get_binary_packet();
  735. } while (is_array($response) && $response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_EXITSTATUS);
  736. }
  737. $data = pack('C', NET_SSH1_CMSG_EXIT_CONFIRMATION);
  738. // i don't think it's really all that important if this packet gets sent or not.
  739. $this->_send_binary_packet($data);
  740. fclose($this->fsock);
  741. // reset the execution bitmap - a new \phpseclib\Net\SSH1 object needs to be created.
  742. $this->bitmap = 0;
  743. return $output;
  744. }
  745. /**
  746. * Creates an interactive shell
  747. *
  748. * @see self::interactiveRead()
  749. * @see self::interactiveWrite()
  750. * @return bool
  751. * @throws \UnexpectedValueException on receipt of unexpected packets
  752. * @throws \RuntimeException on other errors
  753. * @access private
  754. */
  755. function _initShell()
  756. {
  757. // connect using the sample parameters in protocol-1.5.txt.
  758. // according to wikipedia.org's entry on text terminals, "the fundamental type of application running on a text
  759. // terminal is a command line interpreter or shell". thus, opening a terminal session to run the shell.
  760. $data = pack('CNa*N4C', NET_SSH1_CMSG_REQUEST_PTY, strlen('vt100'), 'vt100', 24, 80, 0, 0, self::TTY_OP_END);
  761. if (!$this->_send_binary_packet($data)) {
  762. throw new \RuntimeException('Error sending SSH_CMSG_REQUEST_PTY');
  763. }
  764. $response = $this->_get_binary_packet();
  765. if ($response === true) {
  766. return false;
  767. }
  768. if ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) {
  769. throw new \UnexpectedValueException('Expected SSH_SMSG_SUCCESS');
  770. }
  771. $data = pack('C', NET_SSH1_CMSG_EXEC_SHELL);
  772. if (!$this->_send_binary_packet($data)) {
  773. throw new \RuntimeException('Error sending SSH_CMSG_EXEC_SHELL');
  774. }
  775. $this->bitmap |= self::MASK_SHELL;
  776. //stream_set_blocking($this->fsock, 0);
  777. return true;
  778. }
  779. /**
  780. * Inputs a command into an interactive shell.
  781. *
  782. * @see self::interactiveWrite()
  783. * @param string $cmd
  784. * @return bool
  785. * @access public
  786. */
  787. function write($cmd)
  788. {
  789. return $this->interactiveWrite($cmd);
  790. }
  791. /**
  792. * Returns the output of an interactive shell when there's a match for $expect
  793. *
  794. * $expect can take the form of a string literal or, if $mode == self::READ__REGEX,
  795. * a regular expression.
  796. *
  797. * @see self::write()
  798. * @param string $expect
  799. * @param int $mode
  800. * @return bool
  801. * @throws \RuntimeException on connection error
  802. * @access public
  803. */
  804. function read($expect, $mode = self::READ__SIMPLE)
  805. {
  806. if (!($this->bitmap & self::MASK_LOGIN)) {
  807. throw new \RuntimeException('Operation disallowed prior to login()');
  808. }
  809. if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
  810. throw new \RuntimeException('Unable to initiate an interactive shell session');
  811. }
  812. $match = $expect;
  813. while (true) {
  814. if ($mode == self::READ__REGEX) {
  815. preg_match($expect, $this->interactiveBuffer, $matches);
  816. $match = isset($matches[0]) ? $matches[0] : '';
  817. }
  818. $pos = strlen($match) ? strpos($this->interactiveBuffer, $match) : false;
  819. if ($pos !== false) {
  820. return $this->_string_shift($this->interactiveBuffer, $pos + strlen($match));
  821. }
  822. $response = $this->_get_binary_packet();
  823. if ($response === true) {
  824. return $this->_string_shift($this->interactiveBuffer, strlen($this->interactiveBuffer));
  825. }
  826. $this->interactiveBuffer.= substr($response[self::RESPONSE_DATA], 4);
  827. }
  828. }
  829. /**
  830. * Inputs a command into an interactive shell.
  831. *
  832. * @see self::interactiveRead()
  833. * @param string $cmd
  834. * @return bool
  835. * @throws \RuntimeException on connection error
  836. * @access public
  837. */
  838. function interactiveWrite($cmd)
  839. {
  840. if (!($this->bitmap & self::MASK_LOGIN)) {
  841. throw new \RuntimeException('Operation disallowed prior to login()');
  842. }
  843. if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
  844. throw new \RuntimeException('Unable to initiate an interactive shell session');
  845. }
  846. $data = pack('CNa*', NET_SSH1_CMSG_STDIN_DATA, strlen($cmd), $cmd);
  847. if (!$this->_send_binary_packet($data)) {
  848. throw new \RuntimeException('Error sending SSH_CMSG_STDIN');
  849. }
  850. return true;
  851. }
  852. /**
  853. * Returns the output of an interactive shell when no more output is available.
  854. *
  855. * Requires PHP 4.3.0 or later due to the use of the stream_select() function. If you see stuff like
  856. * "^[[00m", you're seeing ANSI escape codes. According to
  857. * {@link http://support.microsoft.com/kb/101875 How to Enable ANSI.SYS in a Command Window}, "Windows NT
  858. * does not support ANSI escape sequences in Win32 Console applications", so if you're a Windows user,
  859. * there's not going to be much recourse.
  860. *
  861. * @see self::interactiveRead()
  862. * @return string
  863. * @throws \RuntimeException on connection error
  864. * @access public
  865. */
  866. function interactiveRead()
  867. {
  868. if (!($this->bitmap & self::MASK_LOGIN)) {
  869. throw new \RuntimeException('Operation disallowed prior to login()');
  870. }
  871. if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
  872. throw new \RuntimeException('Unable to initiate an interactive shell session');
  873. }
  874. $read = array($this->fsock);
  875. $write = $except = null;
  876. if (stream_select($read, $write, $except, 0)) {
  877. $response = $this->_get_binary_packet();
  878. return substr($response[self::RESPONSE_DATA], 4);
  879. } else {
  880. return '';
  881. }
  882. }
  883. /**
  884. * Disconnect
  885. *
  886. * @access public
  887. */
  888. function disconnect()
  889. {
  890. $this->_disconnect();
  891. }
  892. /**
  893. * Destructor.
  894. *
  895. * Will be called, automatically, if you're supporting just PHP5. If you're supporting PHP4, you'll need to call
  896. * disconnect().
  897. *
  898. * @access public
  899. */
  900. function __destruct()
  901. {
  902. $this->_disconnect();
  903. }
  904. /**
  905. * Disconnect
  906. *
  907. * @param string $msg
  908. * @access private
  909. */
  910. function _disconnect($msg = 'Client Quit')
  911. {
  912. if ($this->bitmap) {
  913. $data = pack('C', NET_SSH1_CMSG_EOF);
  914. $this->_send_binary_packet($data);
  915. /*
  916. $response = $this->_get_binary_packet();
  917. if ($response === true) {
  918. $response = array(self::RESPONSE_TYPE => -1);
  919. }
  920. switch ($response[self::RESPONSE_TYPE]) {
  921. case NET_SSH1_SMSG_EXITSTATUS:
  922. $data = pack('C', NET_SSH1_CMSG_EXIT_CONFIRMATION);
  923. break;
  924. default:
  925. $data = pack('CNa*', NET_SSH1_MSG_DISCONNECT, strlen($msg), $msg);
  926. }
  927. */
  928. $data = pack('CNa*', NET_SSH1_MSG_DISCONNECT, strlen($msg), $msg);
  929. $this->_send_binary_packet($data);
  930. fclose($this->fsock);
  931. $this->bitmap = 0;
  932. }
  933. }
  934. /**
  935. * Gets Binary Packets
  936. *
  937. * See 'The Binary Packet Protocol' of protocol-1.5.txt for more info.
  938. *
  939. * Also, this function could be improved upon by adding detection for the following exploit:
  940. * http://www.securiteam.com/securitynews/5LP042K3FY.html
  941. *
  942. * @see self::_send_binary_packet()
  943. * @return array
  944. * @access private
  945. */
  946. function _get_binary_packet()
  947. {
  948. if (feof($this->fsock)) {
  949. //user_error('connection closed prematurely');
  950. return false;
  951. }
  952. if ($this->curTimeout) {
  953. $read = array($this->fsock);
  954. $write = $except = null;
  955. $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
  956. $sec = floor($this->curTimeout);
  957. $usec = 1000000 * ($this->curTimeout - $sec);
  958. // on windows this returns a "Warning: Invalid CRT parameters detected" error
  959. if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
  960. //$this->_disconnect('Timeout');
  961. return true;
  962. }
  963. $elapsed = strtok(microtime(), ' ') + strtok('') - $start;
  964. $this->curTimeout-= $elapsed;
  965. }
  966. $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
  967. $temp = unpack('Nlength', fread($this->fsock, 4));
  968. $padding_length = 8 - ($temp['length'] & 7);
  969. $length = $temp['length'] + $padding_length;
  970. $raw = '';
  971. while ($length > 0) {
  972. $temp = fread($this->fsock, $length);
  973. $raw.= $temp;
  974. $length-= strlen($temp);
  975. }
  976. $stop = strtok(microtime(), ' ') + strtok('');
  977. if (strlen($raw) && $this->crypto !== false) {
  978. $raw = $this->crypto->decrypt($raw);
  979. }
  980. $padding = substr($raw, 0, $padding_length);
  981. $type = $raw[$padding_length];
  982. $data = substr($raw, $padding_length + 1, -4);
  983. $temp = unpack('Ncrc', substr($raw, -4));
  984. //if ( $temp['crc'] != $this->_crc($padding . $type . $data) ) {
  985. // user_error('Bad CRC in packet from server');
  986. // return false;
  987. //}
  988. $type = ord($type);
  989. if (defined('NET_SSH1_LOGGING')) {
  990. $temp = isset($this->protocol_flags[$type]) ? $this->protocol_flags[$type] : 'UNKNOWN';
  991. $temp = '<- ' . $temp .
  992. ' (' . round($stop - $start, 4) . 's)';
  993. $this->_append_log($temp, $data);
  994. }
  995. return array(
  996. self::RESPONSE_TYPE => $type,
  997. self::RESPONSE_DATA => $data
  998. );
  999. }
  1000. /**
  1001. * Sends Binary Packets
  1002. *
  1003. * Returns true on success, false on failure.
  1004. *
  1005. * @see self::_get_binary_packet()
  1006. * @param string $data
  1007. * @return bool
  1008. * @access private
  1009. */
  1010. function _send_binary_packet($data)
  1011. {
  1012. if (feof($this->fsock)) {
  1013. //user_error('connection closed prematurely');
  1014. return false;
  1015. }
  1016. $length = strlen($data) + 4;
  1017. $padding = Random::string(8 - ($length & 7));
  1018. $orig = $data;
  1019. $data = $padding . $data;
  1020. $data.= pack('N', $this->_crc($data));
  1021. if ($this->crypto !== false) {
  1022. $data = $this->crypto->encrypt($data);
  1023. }
  1024. $packet = pack('Na*', $length, $data);
  1025. $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
  1026. $result = strlen($packet) == fputs($this->fsock, $packet);
  1027. $stop = strtok(microtime(), ' ') + strtok('');
  1028. if (defined('NET_SSH1_LOGGING')) {
  1029. $temp = isset($this->protocol_flags[ord($orig[0])]) ? $this->protocol_flags[ord($orig[0])] : 'UNKNOWN';
  1030. $temp = '-> ' . $temp .
  1031. ' (' . round($stop - $start, 4) . 's)';
  1032. $this->_append_log($temp, $orig);
  1033. }
  1034. return $result;
  1035. }
  1036. /**
  1037. * Cyclic Redundancy Check (CRC)
  1038. *
  1039. * PHP's crc32 function is implemented slightly differently than the one that SSH v1 uses, so
  1040. * we've reimplemented it. A more detailed discussion of the differences can be found after
  1041. * $crc_lookup_table's initialization.
  1042. *
  1043. * @see self::_get_binary_packet()
  1044. * @see self::_send_binary_packet()
  1045. * @param string $data
  1046. * @return int
  1047. * @access private
  1048. */
  1049. function _crc($data)
  1050. {
  1051. static $crc_lookup_table = array(
  1052. 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
  1053. 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
  1054. 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
  1055. 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
  1056. 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
  1057. 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
  1058. 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
  1059. 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
  1060. 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
  1061. 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
  1062. 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
  1063. 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
  1064. 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
  1065. 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
  1066. 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
  1067. 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
  1068. 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
  1069. 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
  1070. 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
  1071. 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
  1072. 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
  1073. 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
  1074. 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
  1075. 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
  1076. 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
  1077. 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
  1078. 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
  1079. 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
  1080. 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
  1081. 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
  1082. 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
  1083. 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
  1084. 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
  1085. 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
  1086. 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
  1087. 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
  1088. 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
  1089. 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
  1090. 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
  1091. 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
  1092. 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
  1093. 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
  1094. 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
  1095. 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
  1096. 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
  1097. 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
  1098. 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
  1099. 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
  1100. 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
  1101. 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
  1102. 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
  1103. 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
  1104. 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
  1105. 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
  1106. 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
  1107. 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
  1108. 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
  1109. 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
  1110. 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
  1111. 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
  1112. 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
  1113. 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
  1114. 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
  1115. 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
  1116. );
  1117. // For this function to yield the same output as PHP's crc32 function, $crc would have to be
  1118. // set to 0xFFFFFFFF, initially - not 0x00000000 as it currently is.
  1119. $crc = 0x00000000;
  1120. $length = strlen($data);
  1121. for ($i=0; $i<$length; $i++) {
  1122. // We AND $crc >> 8 with 0x00FFFFFF because we want the eight newly added bits to all
  1123. // be zero. PHP, unfortunately, doesn't always do this. 0x80000000 >> 8, as an example,
  1124. // yields 0xFF800000 - not 0x00800000. The following link elaborates:
  1125. // http://www.php.net/manual/en/language.operators.bitwise.php#57281
  1126. $crc = (($crc >> 8) & 0x00FFFFFF) ^ $crc_lookup_table[($crc & 0xFF) ^ ord($data[$i])];
  1127. }
  1128. // In addition to having to set $crc to 0xFFFFFFFF, initially, the return value must be XOR'd with
  1129. // 0xFFFFFFFF for this function to return the same thing that PHP's crc32 function would.
  1130. return $crc;
  1131. }
  1132. /**
  1133. * String Shift
  1134. *
  1135. * Inspired by array_shift
  1136. *
  1137. * @param string $string
  1138. * @param int $index
  1139. * @return string
  1140. * @access private
  1141. */
  1142. function _string_shift(&$string, $index = 1)
  1143. {
  1144. $substr = substr($string, 0, $index);
  1145. $string = substr($string, $index);
  1146. return $substr;
  1147. }
  1148. /**
  1149. * RSA Encrypt
  1150. *
  1151. * Returns mod(pow($m, $e), $n), where $n should be the product of two (large) primes $p and $q and where $e
  1152. * should be a number with the property that gcd($e, ($p - 1) * ($q - 1)) == 1. Could just make anything that
  1153. * calls this call modexp, instead, but I think this makes things clearer, maybe...
  1154. *
  1155. * @see self::__construct()
  1156. * @param BigInteger $m
  1157. * @param array $key
  1158. * @return BigInteger
  1159. * @access private
  1160. */
  1161. function _rsa_crypt($m, $key)
  1162. {
  1163. /*
  1164. $rsa = new RSA();
  1165. $rsa->load($key, 'raw');
  1166. $rsa->setHash('sha1');
  1167. return $rsa->encrypt($m, RSA::PADDING_PKCS1);
  1168. */
  1169. // To quote from protocol-1.5.txt:
  1170. // The most significant byte (which is only partial as the value must be
  1171. // less than the public modulus, which is never a power of two) is zero.
  1172. //
  1173. // The next byte contains the value 2 (which stands for public-key
  1174. // encrypted data in the PKCS standard [PKCS#1]). Then, there are non-
  1175. // zero random bytes to fill any unused space, a zero byte, and the data
  1176. // to be encrypted in the least significant bytes, the last byte of the
  1177. // data in the least significant byte.
  1178. // Presumably the part of PKCS#1 they're refering to is "Section 7.2.1 Encryption Operation",
  1179. // under "7.2 RSAES-PKCS1-v1.5" and "7 Encryption schemes" of the following URL:
  1180. // ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.pdf
  1181. $modulus = $key[1]->toBytes();
  1182. $length = strlen($modulus) - strlen($m) - 3;
  1183. $random = '';
  1184. while (strlen($random) != $length) {
  1185. $block = Random::string($length - strlen($random));
  1186. $block = str_replace("\x00", '', $block);
  1187. $random.= $block;
  1188. }
  1189. $temp = chr(0) . chr(2) . $random . chr(0) . $m;
  1190. $m = new BigInteger($temp, 256);
  1191. $m = $m->modPow($key[0], $key[1]);
  1192. return $m->toBytes();
  1193. }
  1194. /**
  1195. * Define Array
  1196. *
  1197. * Takes any number of arrays whose indices are integers and whose values are strings and defines a bunch of
  1198. * named constants from it, using the value as the name of the constant and the index as the value of the constant.
  1199. * If any of the constants that would be defined already exists, none of the constants will be defined.
  1200. *
  1201. * @param array $array
  1202. * @access private
  1203. */
  1204. function _define_array()
  1205. {
  1206. $args = func_get_args();
  1207. foreach ($args as $arg) {
  1208. foreach ($arg as $key => $value) {
  1209. if (!defined($value)) {
  1210. define($value, $key);
  1211. } else {
  1212. break 2;
  1213. }
  1214. }
  1215. }
  1216. }
  1217. /**
  1218. * Returns a log of the packets that have been sent and received.
  1219. *
  1220. * Returns a string if NET_SSH1_LOGGING == self::LOG_COMPLEX, an array if NET_SSH1_LOGGING == self::LOG_SIMPLE and false if !defined('NET_SSH1_LOGGING')
  1221. *
  1222. * @access public
  1223. * @return array|false|string
  1224. */
  1225. function getLog()
  1226. {
  1227. if (!defined('NET_SSH1_LOGGING')) {
  1228. return false;
  1229. }
  1230. switch (NET_SSH1_LOGGING) {
  1231. case self::LOG_SIMPLE:
  1232. return $this->message_number_log;
  1233. break;
  1234. case self::LOG_COMPLEX:
  1235. return $this->_format_log($this->message_log, $this->protocol_flags_log);
  1236. break;
  1237. default:
  1238. return false;
  1239. }
  1240. }
  1241. /**
  1242. * Formats a log for printing
  1243. *
  1244. * @param array $message_log
  1245. * @param array $message_number_log
  1246. * @access private
  1247. * @return string
  1248. */
  1249. function _format_log($message_log, $message_number_log)
  1250. {
  1251. $output = '';
  1252. for ($i = 0; $i < count($message_log); $i++) {
  1253. $output.= $message_number_log[$i] . "\r\n";
  1254. $current_log = $message_log[$i];
  1255. $j = 0;
  1256. do {
  1257. if (strlen($current_log)) {
  1258. $output.= str_pad(dechex($j), 7, '0', STR_PAD_LEFT) . '0 ';
  1259. }
  1260. $fragment = $this->_string_shift($current_log, $this->log_short_width);
  1261. $hex = substr(preg_replace_callback('#.#s', array($this, '_format_log_helper'), $fragment), strlen($this->log_boundary));
  1262. // replace non ASCII printable characters with dots
  1263. // http://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters
  1264. // also replace < with a . since < messes up the output on web browsers
  1265. $raw = preg_replace('#[^\x20-\x7E]|<#', '.', $fragment);
  1266. $output.= str_pad($hex, $this->log_long_width - $this->log_short_width, ' ') . $raw . "\r\n";
  1267. $j++;
  1268. } while (strlen($current_log));
  1269. $output.= "\r\n";
  1270. }
  1271. return $output;
  1272. }
  1273. /**
  1274. * Helper function for _format_log
  1275. *
  1276. * For use with preg_replace_callback()
  1277. *
  1278. * @param array $matches
  1279. * @access private
  1280. * @return string
  1281. */
  1282. function _format_log_helper($matches)
  1283. {
  1284. return $this->log_boundary . str_pad(dechex(ord($matches[0])), 2, '0', STR_PAD_LEFT);
  1285. }
  1286. /**
  1287. * Return the server key public exponent
  1288. *
  1289. * Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
  1290. * the raw bytes. This behavior is similar to PHP's md5() function.
  1291. *
  1292. * @param bool $raw_output
  1293. * @return string
  1294. * @access public
  1295. */
  1296. function getServerKeyPublicExponent($raw_output = false)
  1297. {
  1298. return $raw_output ? $this->server_key_public_exponent->toBytes() : $this->server_key_public_exponent->toString();
  1299. }
  1300. /**
  1301. * Return the server key public modulus
  1302. *
  1303. * Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
  1304. * the raw bytes. This behavior is similar to PHP's md5() function.
  1305. *
  1306. * @param bool $raw_output
  1307. * @return string
  1308. * @access public
  1309. */
  1310. function getServerKeyPublicModulus($raw_output = false)
  1311. {
  1312. return $raw_output ? $this->server_key_public_modulus->toBytes() : $this->server_key_public_modulus->toString();
  1313. }
  1314. /**
  1315. * Return the host key public exponent
  1316. *
  1317. * Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
  1318. * the raw bytes. This behavior is similar to PHP's md5() function.
  1319. *
  1320. * @param bool $raw_output
  1321. * @return string
  1322. * @access public
  1323. */
  1324. function getHostKeyPublicExponent($raw_output = false)
  1325. {
  1326. return $raw_output ? $this->host_key_public_exponent->toBytes() : $this->host_key_public_exponent->toString();
  1327. }
  1328. /**
  1329. * Return the host key public modulus
  1330. *
  1331. * Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
  1332. * the raw bytes. This behavior is similar to PHP's md5() function.
  1333. *
  1334. * @param bool $raw_output
  1335. * @return string
  1336. * @access public
  1337. */
  1338. function getHostKeyPublicModulus($raw_output = false)
  1339. {
  1340. return $raw_output ? $this->host_key_public_modulus->toBytes() : $this->host_key_public_modulus->toString();
  1341. }
  1342. /**
  1343. * Return a list of ciphers supported by SSH1 server.
  1344. *
  1345. * Just because a cipher is supported by an SSH1 server doesn't mean it's supported by this library. If $raw_output
  1346. * is set to true, returns, instead, an array of constants. ie. instead of array('Triple-DES in CBC mode'), you'll
  1347. * get array(self::CIPHER_3DES).
  1348. *
  1349. * @param bool $raw_output
  1350. * @return array
  1351. * @access public
  1352. */
  1353. function getSupportedCiphers($raw_output = false)
  1354. {
  1355. return $raw_output ? array_keys($this->supported_ciphers) : array_values($this->supported_ciphers);
  1356. }
  1357. /**
  1358. * Return a list of authentications supported by SSH1 server.
  1359. *
  1360. * Just because a cipher is supported by an SSH1 server doesn't mean it's supported by this library. If $raw_output
  1361. * is set to true, returns, instead, an array of constants. ie. instead of array('password authentication'), you'll
  1362. * get array(self::AUTH_PASSWORD).
  1363. *
  1364. * @param bool $raw_output
  1365. * @return array
  1366. * @access public
  1367. */
  1368. function getSupportedAuthentications($raw_output = false)
  1369. {
  1370. return $raw_output ? array_keys($this->supported_authentications) : array_values($this->supported_authentications);
  1371. }
  1372. /**
  1373. * Return the server identification.
  1374. *
  1375. * @return string
  1376. * @access public
  1377. */
  1378. function getServerIdentification()
  1379. {
  1380. return rtrim($this->server_identification);
  1381. }
  1382. /**
  1383. * Logs data packets
  1384. *
  1385. * Makes sure that only the last 1MB worth of packets will be logged
  1386. *
  1387. * @param string $data
  1388. * @access private
  1389. */
  1390. function _append_log($protocol_flags, $message)
  1391. {
  1392. switch (NET_SSH1_LOGGING) {
  1393. // useful for benchmarks
  1394. case self::LOG_SIMPLE:
  1395. $this->protocol_flags_log[] = $protocol_flags;
  1396. break;
  1397. // the most useful log for SSH1
  1398. case self::LOG_COMPLEX:
  1399. $this->protocol_flags_log[] = $protocol_flags;
  1400. $this->_string_shift($message);
  1401. $this->log_size+= strlen($message);
  1402. $this->message_log[] = $message;
  1403. while ($this->log_size > self::LOG_MAX_SIZE) {
  1404. $this->log_size-= strlen(array_shift($this->message_log));
  1405. array_shift($this->protocol_flags_log);
  1406. }
  1407. break;
  1408. // dump the output out realtime; packets may be interspersed with non packets,
  1409. // passwords won't be filtered out and select other packets may not be correctly
  1410. // identified
  1411. case self::LOG_REALTIME:
  1412. echo "<pre>\r\n" . $this->_format_log(array($message), array($protocol_flags)) . "\r\n</pre>\r\n";
  1413. @flush();
  1414. @ob_flush();
  1415. break;
  1416. // basically the same thing as self::LOG_REALTIME with the caveat that self::LOG_REALTIME_FILE
  1417. // needs to be defined and that the resultant log file will be capped out at self::LOG_MAX_SIZE.
  1418. // the earliest part of the log file is denoted by the first <<< START >>> and is not going to necessarily
  1419. // at the beginning of the file
  1420. case self::LOG_REALTIME_FILE:
  1421. if (!isset($this->realtime_log_file)) {
  1422. // PHP doesn't seem to like using constants in fopen()
  1423. $filename = self::LOG_REALTIME_FILE;
  1424. $fp = fopen($filename, 'w');
  1425. $this->realtime_log_file = $fp;
  1426. }
  1427. if (!is_resource($this->realtime_log_file)) {
  1428. break;
  1429. }
  1430. $entry = $this->_format_log(array($message), array($protocol_flags));
  1431. if ($this->realtime_log_wrap) {
  1432. $temp = "<<< START >>>\r\n";
  1433. $entry.= $temp;
  1434. fseek($this->realtime_log_file, ftell($this->realtime_log_file) - strlen($temp));
  1435. }
  1436. $this->realtime_log_size+= strlen($entry);
  1437. if ($this->realtime_log_size > self::LOG_MAX_SIZE) {
  1438. fseek($this->realtime_log_file, 0);
  1439. $this->realtime_log_size = strlen($entry);
  1440. $this->realtime_log_wrap = true;
  1441. }
  1442. fputs($this->realtime_log_file, $entry);
  1443. }
  1444. }
  1445. }