I have a problem doing Sudo command through SSH when connecting from php, but not connection from regular terminal
if i'm connecting on SSH to an AWS machine with Net_SSH2
$ssh = new Net_SSH2($instanceIp);
if ( ! $ssh->login('ec2-user', $key)) {
$logger->error('Login Failed');
}
I'll get this error: sudo: sorry, you must have a tty to run sudo
If I'm connecting directly from terminal
ssh -i ~/Path/to-file-key.pem ec2-user#111.111.11.111
So I can run any sudo command without problems.
I don't want to remove from /etc/sudoers (I don't want to have something to do on the server, I want it to be done by the connection)
Defaults requiretty
Is there a way to do it without that ?
Thanks for your help
If i may quote this article,
Red Hat systems (RHEL, Fedora...) have been known to require a TTY in default sudoers file. That provides no real security benefit and can be safely removed.
Red Hat have acknowledged the problem and it will be removed in future releases.
Therefore, it's safe to remove the "requiretty", that way you won't have a problem to execute sudo commands via SSH.
You may also try running ssh with the -t option(the repercussions of which you can find in the aforementioned article), it forces pseudo-tty allocation, so it might work. I don't know if there's a way to add that option to Net_SSH, but it should be OpenSSH based, so normally, you should.
Worst case scenario, you can allways run the ssh command via exec, but removing require tty seems to be the best option.
The phpseclib docs give an example of how to use 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:~$');
}
http://phpseclib.sourceforge.net/ssh/examples.html#sudo
If you want to try to do it with $ssh->exec (it's not clear what you're doing since you didn't provide the full code in your post) you can do sudo visudo and then add an entry for the username / script that you're wanting to run. eg.
username ALL=(ALL) NOPASSWD: /path/to/script
Alternatively, you could do this:
echo "PASSWORD" | sudo -S /path/to/script
For more information google "sudo in a bash script"
Related
Been wrestling with this one for a little bit. I'm currently working on a PHP application that connects to a custom API as well as performs changes to a server via Phpseclib's SSH2 library.
$ssh = new Net_SSH2($server_name);
if(!$ssh->login("username", "password")) {
$result['result'] = 'ERROR';
$result['message'] = 'Login failed';
} else {
$result['propertyFolderDeleted'] = $ssh->exec("cd /var/www/sites; echo 'password' | sudo -S /usr/local/bin/delete_property.sh -sc $company_name -sp $property_name");
return '{"data":'.json_encode($result).'}';
}
Output generated:
{"data":{"propertyFolderDeleted":"[sudo] password for portals: "}}
Pretty straight-forward, my application uses SSH2 to exec some Bash scripts I have in place on my server. For the most part this works flawlessly, but for some reason, exec-uting this one Bash script ('delete_property.sh') outputs the sudo password prompt as a result.
I've tweaked my request and executing my Bash script via command-line (in Putty) no longer outputs the prompt text upon completion of the Bash script.
Why isn't this the case when using Phpseclib?
Just add the user to the sudorious file.
Open the terminal.
Type "sudo visudo"
Add at the end of the file "youruser ALL=(ALL) NOPASSWD:ALL" and just replace "youruser" with your real user.
Save and exit.
Now every one command with your user which is using sudo will be executed without asking the password.
I am stuck with a problem in php for the last 3 days. couldn't find a solution yet.
I have a Cent OS remote machine and an Ubuntu local machine. I have a php script named test.php in my local machine so that I want to run some Linux commands in the remote machine using that php script. I used phpseclib for connecting to remote machine. The following is the php script test.php.
<?php
include('Net/SSH2.php');
define('NET_SSH2_LOGGING', NET_SSH2_LOG_COMPLEX);
$ssh = new Net_SSH2('10.3.2.0');
if (!$ssh->login('makesubdomain','abcdabcd')) {
exit('Login Failed');
}
echo $ssh->exec('/usr/local/listdomain.backup/test/makedir.sh');
?>
I can't use root user here since root login has been disabled in remote cent os machine.
So I created this makesubdomain user and gave sudo privileges, that too without password by adding makesubdomain ALL=(ALL) NOPASSWD: ALL in /etc/sudoers file.The below one is the shell script which resides in 10.3.2.0
sudo -H sh -c '
mkdir /usr/local/testdir
if [ $? -eq 0 ];then
echo "success";
else
echo "not success";
fi
'
But now when I run the php script from terminal using command php test.php it showing error sudo: sorry, you must have a tty to run sudo. Ultimately, What shall I need to do with test.php and makedir.sh for creating a directory testdir as specified in .sh file using the given php script with user makesubdomain. Please advice as I am a very beginner in php.
(Note : I can run the makedir.sh file successfully in the remote machine, with the command sudo ./makedir as user makesubdomain, that too without prompting sudo password)
EDIT
I had commented Defaults requiretty in /etc/sudoers as given in http://www.unix.com/shell-programming-scripting/201211-sudo-sorry-you-must-have-tty-run-sudo.html, and it is working fine. Can i have any other option without doing this ?
Try calling $ssh->enablePTY() before doing $ssh->exec().
I have a php script which contains su. when I run it in shell it ask for root password and works well. but now I want make an interface for it. as you know all command in php-apache runs as www-data user and this user doesn't have specified password or it's not in sudoers. so I can't use "echo pass | sudo -S ..." because I don't know what is www-data's password and It is not logical on every server set password for www-data or add it in sudoers+nopass, is it?
What solution can you suggest to solve this problem?
one of my commands:
su -c \"/usr/sbin/dmidecode -s baseboard-serial-number | tr \ \-\"
phpseclib should be best library choice as it does not requires any additional extensions.
<?php
include('Net/SSH2.php');
$ssh = new Net_SSH2('example.com');
if (!$ssh->login('user', 'pass')) {
exit('Login Failed');
}
echo $ssh->exec('whoami');
echo $ssh->exec('pwd');
?>
Another alternative is libssh2, but it has to be compiled separately and is notoriously difficult to setup/use.
I recently published a project that allows PHP to obtain and interact with a real Bash shell, you can easily get a shell with root. Get it here: https://github.com/merlinthemagic/MTS
After downloading you would simply use the following code:
$shell = \MTS\Factories::getDevices()->getLocalHost()->getShell('bash', true);
$strCmd = "\"/usr/sbin/dmidecode -s baseboard-serial-number | tr \ \-\"";
$return1 = $shell->exeCmd($strCmd);
echo $return1;// return from your command
I want to execute a command as root with shell_exec. Now I know this is dangerous, but believe me, you need to login with MOD_AUTH and have the right privilleges to come to this page. It's secure. How can I get this done?
You could use the latest SVN version of phpseclib, a pure PHP SSH implementation, to do this. eg.
<?php
include('Net/SSH2.php');
$ssh = new Net_SSH2('www.domain.tld');
$ssh->login('username', 'password');
$ssh->read('[prompt]');
$ssh->write("sudo command\n");
$ssh->read('Password:');
$ssh->write("Password\n");
echo $ssh->read('[prompt]');
?>
The problem isn't that your page is or isn't secure, the problem is that giving a php page the ability to run some sudo command would give it to all pages including any injected code on any insecure page on any site on the server.
That said, it might be best to make a wrapper script that does just the one job that needs doing, then give the http user access to just that ONE command as sudo
http ALL=(ALL) NOPASSWD:/user/local/bin/your_wrapper_script.sh
Definitley not advised. However, you will want to look into editing the sudoers file and add the user php is running as a NOPASSWD for the command you need to run. This will only allow him to sudo that one command with out entering a password.
If you need more commands add more to it. Sudoers Configuration I know that forum/post is debian based but sudo is not strictly debian and that should help you out with the sudo configuration values that you need to put it.
I just Google'd for php sudo shell_exec and this came up as the #1 match:
http://www.php.net/manual/en/function.shell-exec.php#101440
ilya at linemedia dot ru 16-Dec-2010 04:36
sudo can be executed without storing pass in a file
system('echo "PASS" | sudo -u root -S COMMAND');
$aux=echo "admin-pass" | your command;
echo $aux;
/*******************************
************Example*************
*******************************/
Run a Perl script named my_perl_script.pl:
$aux=echo "admin-pass" | sudo -u root -S perl /path-to-the-script/my-perl-script.pl;
echo $aux;
Best way to do it:
$descriptorSpec = array(
0 => STDIN,
1 => STDOUT,
2 => STDERR,
);
if (posix_getuid() === 0) {
echo "Root\n";
} else {
echo "No root\n";
$command = 'sudo ' . PHP_BINARY . ' ' . implode(' ', $_SERVER['argv']);
$pipes = [];
$process = proc_open($command, $descriptorSpec, $pipes);
if (is_resource($process)) {
proc_close($process);
}
}
It runs the same command again, with sudo prefixed.
I'm trying to establish an interactive SSH connection to a remote server using PHP via the command line on Mac OS X 10.6. I'm currently using PHP's proc_open function to execute the following command:
ssh -t -t -p 22 user#server.com
This almost works. The -t -t options are supposed to force a pseudo terminal which they almost do. I am able to enter the SSH password and press enter. However, after pressing enter the terminal appears to simply hang. No output, no nothing - it's as if the SSH session has failed. I can't run commands or anything and have to kill the whole thing using Ctrl+C. I know the login is successful because I can execute a command like ssh -t -t -p 22 user#server.com "ls -la" and get the correct output.
I thought the problem must be related to the fact that I was using standard pipes in my proc_open call, so I replaced them with pty. I get the following error: "pty pseudo terminal not supported on this system..."
Does Mac OS X simply not support pty or pseudo terminals? (I'm pretty new at using all this shell terminology).
Here's the PHP code:
$descriptorspec = array(0 => array("pty"), 1 => array("pty"), 2 => array("pty"));
$cwd = getcwd();
$process = proc_open('ssh -t -t -p 22 user#server.com', $descriptorspec, $pipes, $cwd);
if (is_resource($process))
{
while (true)
{
echo(stream_get_contents($pipes[1]));
$status = proc_get_status($process);
if (! $status["running"])
break;
}
}
(Sorry - cannot for the life of me figure out SO's formatting instructions...)
What am I doing wrong? Why can't I use pty? Is this just impossible on Mac OS X? Thanks for your help!
You should use public key authentication rather than trying to programmatically bypass interactive password authentication.
The password prompt is supposed to be used from a tty and I believe it was made intentionally difficult to use otherwise. Also the -t -t argument only takes effect once you are connected to the remote host. And I don't believe the PHP function proc_open() can run a command inside a virtual terminal.
To setup public key authentication:
# Generate keypair
ssh-keygen -t rsa
# Copy public key to server
scp ~/.ssh/id_rsa.pub example.com:.ssh/authorized_keys
# Now you shouldn't be prompted for a password when connecting to example.com
# from this host and user account.
ssh example.com
# Since the web server (and thus PHP) probably has its own user account...
# Copy the ~/.ssh/id_rsa file somewhere else
cp ~/.ssh/id_rsa /some_path/id_rsa
# Change ownership of the file to the web server account
chown www-data:www-data /some_path/id_rsa
# Fix the file permissions (ssh ignore the keyfile if it is world readable)
chown 600 /some_path/id_rsa
# Try connecting to the server through the web server account
su -c "ssh -i /some_path/id_rsa -o UserKnownHostsFile=/some_path/known_hosts example.com" www-data
# Add the host to the known hosts file when prompted
Alternately, you could use plink (part of PuTTY for Linux) instead of OpenSSH as it can take the password on the command line plink -pw password example.com. But doing so presents a security risk as anyone who runs ps aux on the server can see the password in the process list.
There is also a program called sshpass that takes the password from an environment variable or command argument and passes it to ssh.
It looks like the problem is best solved using PHP's passthru() function. After alot more (rather painful) research I was able to issue a command through this function and could interact with the remote server through the terminal as if I had run ssh and svn export by hand (they both require passwords, therefore were good tests). What I'm going to have to do is construct a (potentially very long) string of commands separated by && and attach them to the end of the ssh command: ssh -t -t -p 22 hostname command1 && command2 ... The output will be sent to my terminal in Mac OS X even though the commands are being executed on the remote server. Looks like this is the solution I was looking for the whole time - pretty simple really! Thanks to everyone who helped me with this. I gave Alexandre the "green checkmark" because he was the only one who kept responding and was quite helpful in deducing the final answer to the problem. Thanks Alexandre!
This is old, but for any googlers out there, here is an actual solution using proc_open:
Pty descriptors are available in PHP, but have to be configured during compilation (see this 10yr old bug report https://bugs.php.net/bug.php?id=33147)
But in python however, we don't have that problem. So instead of running the ssh command directly, run this python script:
import sys
import pty
args = " ".join(sys.argv[1:])
pty.spawn(['/usr/bin/ssh', args])
About pty.spawn from python docs:
Spawn a process, and connect its controlling terminal with the current
process’s standard io. This is often used to baffle programs which
insist on reading from the controlling terminal.
Have you tried the PHP SSH2 extension?
Have you tried phpseclib, a pure PHP SSH implementation?:
<?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("ls -la\n");
echo $ssh->read('username#username:~$');
?>
I wrote a ssh client on php with ssh2 extension, you can take a look to the source code on the github page https://github.com/roke22/PHP-SSH2-Web-Client
Please send some feedback.