phpseclib: SSH2 Examples and Notes

Login:

Action:

<?php
include('Net/SSH2.php');
include('Crypt/RSA.php');
include('File/ANSI.php');

define('NET_SSH2_LOGGING', NET_SSH2_LOG_COMPLEX);

$ssh = new Net_SSH2('www.domain.tld');
if (!$ssh->login('username', 'password')) {
    exit('Login Failed');
}$key = new Crypt_RSA();
$key->loadKey(file_get_contents('privatekey'));
if (!$ssh->login('username', $key)) {
    exit('Login Failed');
}$key = new Crypt_RSA();
$key->setPassword('whatever');
$key->loadKey(file_get_contents('privatekey'));
if (!$ssh->login('username', $key)) {
    exit('Login Failed');
}
// save $ssh->getServerPublicHostKey() if this is your first time connecting
// check $ssh->getServerPublicHostKey() against previously saved value on subsequent connections

echo $ssh->exec('pwd');
echo $ssh->exec('ls -la');echo $ssh->exec('pwd'); // outputs /home/username
$ssh->exec('cd /');
echo $ssh->exec('pwd'); // (despite the previous command) outputs /home/username
echo $ssh->read('username@username:~$');
$ssh->write("ls -la\n");
echo $ssh->read('username@username:~$');echo $sftp->read('username@username:~$');
$sftp->write("sudo ls -la\n");
$output = $sftp->read('#Password:|username@username:~\$#', NET_SSH2_READ_REGEX);
echo $output;
if (preg_match('#Password:#', $lines)) {
    $ssh->write("password\n");
    echo $sftp->read('username@username:~$');
}$ssh->setTimeout(5);
echo $ssh->read();$ansi = new File_ANSI();

$ansi->appendString($ssh->read('username@username:~$'));
$ssh->write("top\n");
$ssh->setTimeout(5);
$ansi->appendString($ssh->read());
echo $ansi->getScreen(); // or $ansi->getHistory()

echo $ssh->getLog();
?>

Successive calls to exec()

If done on an interactive shell, the output you'd receive for the first pwd would (depending on how your system is setup) be different than the output of the second pwd. The above code snippet, however, will yield two identical lines.

The reason for this is that any "state changes" you make to the one-time shell are gone once the exec() has been ran and the channel has been deleted.

sudo with read() / write()

By default, sudo caches passwords for 5 minutes after they've been entered. So while $ssh->read('Password:') will work the first time you try it, it won't work if you try it within a five minutes after having initially ran it.

ANSI Escape Codes

Some commands issued to a terminal may yield ANSI escape codes. eg. ^[[H. These provide the terminal with information on the formating of the characters and their positioning.

Since Net_SSH2 uses vt100 as the "TERM environment variable value" a VT100 terminal emulator is needed to properly handle the ANSI escape codes. File_ANSI aims to be such an emulator. The default screen size is 80x24.

$ansi->getScreen() returns what'd be seen on the current screen. In the case of top this is desirable as it'll produce output like this:

top - 23:39:24 up 77 days,  1:13,  1 user,  load average: 0.00, 0.00, 0.00
Tasks:  45 total,   2 running,  43 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   1740956k total,  1079288k used,   661668k free,   221240k buffers
Swap:        0k total,        0k used,        0k free,   399940k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND            
    1 root      16   0  2128  696  600 S  0.0  0.0   0:01.10 init               
    2 root      RT   0     0    0    0 S  0.0  0.0   0:00.00 migration/0        
    3 root      34  19     0    0    0 S  0.0  0.0   0:00.05 ksoftirqd/0        
    4 root      RT   0     0    0    0 S  0.0  0.0   0:00.01 watchdog/0         
    5 root      10  -5     0    0    0 S  0.0  0.0   0:00.25 events/0           
    6 root      11  -5     0    0    0 S  0.0  0.0   0:00.63 khelper            
    7 root      10  -5     0    0    0 S  0.0  0.0   0:00.00 kthread            
    8 root      14  -5     0    0    0 S  0.0  0.0   0:00.00 xenwatch           
    9 root      10  -5     0    0    0 S  0.0  0.0   0:00.00 xenbus             
   17 root      10  -5     0    0    0 S  0.0  0.0   0:00.00 kblockd/0          
   46 root      20  -5     0    0    0 S  0.0  0.0   0:00.00 aio/0              
   45 root      15   0     0    0    0 S  0.0  0.0   0:00.64 kswapd0            
  562 root      20  -5     0    0    0 S  0.0  0.0   0:00.00 kseriod            
  657 root      15   0     0    0    0 S  0.0  0.0   0:04.23 kjournald          
  718 root      13  -4  2360  656  424 S  0.0  0.0   0:00.18 udevd              
 1592 root      14  -2  2396  848  560 S  0.0  0.0   0:00.03 dhclient           
 1647 root      15   0     0    0    0 S  0.0  0.0   0:00.16 kjournald

In the case of ls, however, it is less desirable. For commands like ls it may be preferable to do $ansi->getHistory(). For top, that'd return the following:

         __|  __|_  )  Fedora 8
         _|  (     /    32-bit
        ___|\___|___|

 Welcome to an EC2 Public Image
                       :-)

    Base

 --[ see /etc/ec2/release-notes ]--

[username@username:~$]$top

top - 23:51:56 up 77 days,  1:25,  1 user,  load average: 0.00, 0.00, 0.00
Tasks:  45 total,   2 running,  43 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   1740956k total,  1079256k used,   661700k free,   221240k buffers
Swap:        0k total,        0k used,        0k free,   399940k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND            
    1 root      16   0  2128  696  600 S  0.0  0.0   0:01.10 init               
    2 root      RT   0     0    0    0 S  0.0  0.0   0:00.00 migration/0        
    3 root      34  19     0    0    0 S  0.0  0.0   0:00.05 ksoftirqd/0        
    4 root      RT   0     0    0    0 S  0.0  0.0   0:00.01 watchdog/0         
    5 root      10  -5     0    0    0 S  0.0  0.0   0:00.25 events/0           
    6 root      11  -5     0    0    0 S  0.0  0.0   0:00.63 khelper            
    7 root      10  -5     0    0    0 S  0.0  0.0   0:00.00 kthread            
    8 root      14  -5     0    0    0 S  0.0  0.0   0:00.00 xenwatch           
    9 root      10  -5     0    0    0 S  0.0  0.0   0:00.00 xenbus             
   17 root      10  -5     0    0    0 S  0.0  0.0   0:00.00 kblockd/0          
   46 root      20  -5     0    0    0 S  0.0  0.0   0:00.00 aio/0              
   45 root      15   0     0    0    0 S  0.0  0.0   0:00.64 kswapd0            
  562 root      20  -5     0    0    0 S  0.0  0.0   0:00.00 kseriod            
  657 root      15   0     0    0    0 S  0.0  0.0   0:04.23 kjournald          
  718 root      13  -4  2360  656  424 S  0.0  0.0   0:00.18 udevd              
 1592 root      14  -2  2396  848  560 S  0.0  0.0   0:00.03 dhclient           
 1647 root      15   0     0    0    0 S  0.0  0.0   0:00.16 kjournald

The history, by default, stores 200 lines (not including the current screen). Both functions return HTML with the various formatting properties specified by HTML. If you don't want HTML and want just the raw text of the terminal without any formatting do htmlspecialchars_decode(strip_tags($ansi->getScreen())).