If I do the following command, I get an 'hey' output:
echo shell_exec("echo 'hey'");
But If I do the following command, it will not kill any screen:
echo shell_exec("killall screen");
Or if I do
echo shell_exec("sh /var/www/html/run.sh");
It will not run that file at all (that file does the screen killing aswell)
And If I even get that file with get contents, it successfully reads the content in it.
If it can execute echo so whats wrong?
To run such powerful commands, I had to use this library as stated in this question. This allows me to login into the SSH with root access and execute any command!
function ssh_script($script, $ip, $user, $pass) {
$ssh = new Net_SSH2($ip);
if (!$ssh->login($user, $pass)) {
exit('Login Failed');
}
if ($ssh !== false) {
echo $ssh->exec("sh " . $script);
}
else {
echo "fail";
}
}
Related
I've tried different SSH libraries but they don't seem to work too well in Laravel. Since I got phpseclib to work well, I'm trying to stick with it. But, I'm not seeing a way to have a live output from the SSH connection.
Some things that I plan on running can take up to a few hours to finish but the software being accessed always prints out a percentage of completion that I'd like to utilize to display in the browser.
Currently, I have this:
<?php
use phpseclib\Net\SSH2;
use phpseclib\Crypt\RSA;
$key = new RSA();
$key->loadKey(file_get_contents('key.pem'));
$command = 'ping google.com';
$ssh = new SSH2('awesomeserver.com');
if (!$ssh->login('username', $key))
{
echo 'Login Failed';
}
else
{
echo $ssh->exec($command);
}
?>
This just waits until the command is complete and then just barfs it all onto the screen.
Previously, in the else bracket, I had
while(# ob_end_flush());
$proc = $ssh->exec($command);
while(!feof($proc))
{
echo fread($proc, 4096);
# flush();
}
But, $proc was only recognized as a string instead of a resource, so it didn't work.
Do you all have any other suggestions, other than using a different library?
Thanks!
EDIT (Partial solution):
I eventually got this script to work by utilizing the read() function with this:
while(# ob_end_flush());
$ssh->write($command.'\n');
while($read = $ssh->read())
{
echo $read;
# flush();
}
You could employee a callback. eg.
$ssh->exec('ping 127.0.0.1', function($output) {
echo $output;
});
my ssh script:
include('Net/SSH2.php');
set_include_path(getcwd());
$ssh_host = "myserver.com";
if($ssh_host != null){
$ssh_user = globals::$ssh_logins[$ssh_host];
$ssh = new Net_SSH2($ssh_host);
//$ssh->enablePTY();
if (!$ssh->login($ssh_user['username'], $ssh_user['password'])) {
echo $ssh->isConnected() ? 'bad username or password' : 'unable to establish connection';
}
echo $ssh->exec('sudo bash /myscript.sh');
}else{
echo "no host: " . $ssh_host;
}
when calling:
echo $ssh->exec('sudo bash /myscript.sh');
i get the output:
stdin: is not a tty
sudo: sorry, you must have a tty to run sudo
how do i enable tty on phpseclib?
Sudo is necessary also it is important to retrieve the output. my script returns multiple lines.
Centos 7
PHP 7
interesting link: https://unix.stackexchange.com/questions/136676/sudo-sorry-you-must-have-a-tty-to-run-sudo-when-using-sudo-in-a-remote-scrip?newreg=f31852b195804fd1b988aeb0a9ce59d9
You're on the right track with your $ssh->enablePTY() but once you do that you'll need to do $ssh->read(). Without a PTY $ssh->exec() will return the commands output. If you do $ssh->enablePTY() you'll need to do $ssh->read() to get output.
The reason for this is that with a PTY data can be sent to and from the shell whereas it can't without a PTY. Without a PTY the output you get is the output you get and no input can change that because you can't send input. With a PTY input can change the output.
Also relevant, phpseclib's docs talk about doing sudo with it. From http://phpseclib.sourceforge.net/ssh/examples.html#sudo :
<?php
include('Net/SSH2.php');
$ssh = new Net_SSH2('www.domain.tld');
if (!$ssh->login('username', 'password')) {
exit('Login Failed');
}
echo $ssh->read('username#username:~$');
$ssh->write("sudo ls -la\n");
$output = $ssh->read('#[pP]assword[^:]*:|username#username:~\$#', NET_SSH2_READ_REGEX);
echo $output;
if (preg_match('#[pP]assword[^:]*:#', $output)) {
$ssh->write("password\n");
echo $ssh->read('username#username:~$');
}
If your account doesn't have a password I guess it doesn't matter but if you do have a password then you'll need to do something like the above.
I am having trouble when try to set timeout for my ssh2_exec connection in PHP, so that when there is something wrong when running the command, it will release the executing thread and will not jam the whole web site. I have tried stream_set_timeout($stream,$seconds) but it seems not to work as expected.
Is there any ideas on this?
//run specified command (ssh)
function runCMD($cmd){
if (!($stream = ssh2_exec($this->conn, $cmd )))
{
echo "fail: unable to execute command\n";
fclose($stream);
return ERROR_SSH_EXEC_COMM;
}
sleep(1);
stream_set_timeout($stream,5);//>>not work
stream_set_blocking($stream, true);
$res = stream_get_contents($stream);
return $res;
}
For anyone wondering how to set the timeout, there's a default_socket_timeout variable in php.ini that can be used to set the timeout for any socket-based connections in your current session.
You can check it by simply running
$timeStart = time();
ini_set("default_socket_timeout", 5);
$ssh = ssh2_connect('123.123.123.123');
echo (time() - $timeStart), PHP_EOL;
Here's how you could do that with phpseclib, a pure PHP SSH2 implementation:
<?php
include('Net/SSH2.php');
$ssh = new Net_SSH2('www.domain.tld');
if (!$ssh->login('username', 'password')) {
exit('Login Failed');
}
$ssh->setTimeout(5);
echo $ssh->exec('whatever');
?>
If you want to execute subsequent commands after that one you'll need to do $ssh->reset().
AFAIK, There are no true 'timeout' implementations in the php ssh2 specs.
The only solution that I have found for this problem can be found in this post here:
PHP ssh2_connect() Implement A Timeout
I have an SSH2_Shell session working in PHP. my issue is that i need a command to completely finish before moving onto the next command. Here is my code so far:
$command_capture = "cd /mnt/NADS/scripts/";
$command_capture2 = "./tcpdump.sh $capture_name $sleep";
if (!($connection = ssh2_connect("172.20.1.18", 22))) {
echo "fail: unable to establish connection";
}
if (!ssh2_auth_password($connection, "root", "Hideandseek")) {
echo "fail: unable to authenticate";
}
$stream = ssh2_shell($connection);
fwrite($stream, $command_capture. PHP_EOL);
sleep(1);
fwrite($stream, $command_capture2 . PHP_EOL);
sleep(5);
$data="";
while($buf = stream_get_contents($stream)){
$data.=$buf;
}
echo $data;
fclose($stream);
the tcpdump.sh script is running a lftp command but is not being given anough time to complete. I cant use sleep as it may take longer then the specified time and i dont want to make the user wait if it only needs a few seconds. I have not had luck implementing stream_set_blocking as when i do, it seems to freeze up my browser.
overall, I need a way to detect when a command has finished and move into the next command.
Thanks in advance!
Thanks for the ideas but I think I got it solved. I did an echo of a few special characters when the command finished and then I would search for the characters using strpos(). Another thing I think may have helped was adjusting the max_execution_time setting in the php.ini file. I found that answer here:
http://verysimple.com/2006/03/30/fatal-error-maximum-execution-time-of-30-seconds-exceeded/
And here is my new code
$data="";
while (true){
$data .= stream_get_contents($stream);
if (strpos($data,"XOXO") !== false) {
echo "okay: command finished\n";
break;
}
}
echo $data;
fclose($stream);
I have an SSH2 class that implements the Secure Shell2 over on github .. check out https://github.com/bubba-h57/PHP-SSH2 and see if that helps.
I continue to search for a better way to handle finding the prompts though, so any advice or contribution to that would be welcomed. Hopefully it will help, if nothing more than giving you some ideas.
You could use phpseclib, a pure PHP SSH implementation. eg.
<?php
include('Net/SSH2.php');
$ssh = new Net_SSH2();
$ssh->login('username', 'password');
echo $ssh->exec('command');
echo $ssh->exec('command2');
?>
If you really need shell support you could do the following (with the latest SVN):
<?php
include('Net/SSH2.php');
$ssh = new Net_SSH2();
$ssh->login('username', 'password');
$ssh->read('[prompt]');
$ssh->write("command\n");
echo $ssh->read('[prompt]');
$ssh->write("command\n");
echo $ssh->read('[prompt]');
?>
I am working on a tool that reads an iptables configuration from a remote host over SSH2 using the PECL SSH2 extension. I am able to successfully make the connection to the host, authenticate, and execute commands. The trouble I am having is sometimes the stream doesn't contain any data.
/**
* Load the current firewall configuration
* #return bool
*/
public function loadRules() {
$stream = ssh2_exec($this->connection,"~/iptsave;");
stream_set_blocking($stream,true);
$iptablesSave = stream_get_contents($stream);
if(empty($iptablesSave)) {
return false;
}
parent::restore($iptablesSave);
return true;
}
About 25% of the time, loadRules() returns false, even when connecting to locahost instead of the remote system. I was able to work around the problem by changing the ssh2_exec call to
$stream = ssh2_exec($this->connection,"~/iptsave; sleep .5");
but I am concerned that something is wrong.
phpSecLib may be able to help:
According to this post, it always returns the output, unlike ssh2.so.
I've got the same issue here. Somehow you need to set a delay for getting the result of the stream.
The way you've done it is possible, but you could also set a sleep(1) after the stream_set_block($stream, true) function.
You could try the usleep() function. Haven't tried it yet
May be this will solve the issue:
$stream = ssh2_exec($this->connection,"~/iptsave;");
stream_set_blocking($stream,true);
$stream_out = ssh2_fetch_stream($stream, SSH2_STREAM_STDIO);
$iptablesSave = stream_get_contents($stream);
With some severs you have to use 'interactive shell'. And sometimes you have to set the delay / sleep manually. A working example:
$connection = ssh2_connect($IP, 22);
$auth = ssh2_auth_password($connection, $User, $Pass);
$cmd = "help" . PHP_EOL;
if (!$auth) {
echo "Login Failed;
exit(1);
}
$shell = ssh2_shell($connection);
stream_set_blocking($shell, false); // we will use manual sleep
sleep(1); // This sleep to make sure that you get the prompt back
fwrite ($shell, $cmd . ";" . PHP_EOL);
sleep(1); // This to make sure that the command executes and we get the prompt back again!
while($output = fgets($shell)){
echo $output;
}
fwrite ($shell, "exit;" . PHP_EOL); // If needed
sleep(1);
ssh2_disconnect($connection);
unset($shell);
unset($connection);