Phpseclib SSH2 - How to Suppress Sudo Prompt output on Exec - php

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.

Related

PHP shell_exec() unable to run part of shell script

I have encountered a strange problem. I have created a gitlab custom webhook. The webhook service is written in php (gitlab.php). The php script, when called with proper payload, should start an automated deployment. The deployment script is basically a shell script (deploy.sh)
Code of gitlab.php
<?php
$json = file_get_contents('php://input');
// Converts it into a PHP object
$data = json_decode($json, true);
$secret = "";
foreach (getallheaders() as $name => $value) {
if($name=='X-Gitlab-Token') {
$secret = $value;
}
}
if($secret=="mysecretcode" && $data['object_kind']=="push") {
file_put_contents("/opt/lampp/htdocs/autodeploy/autodeploy.log", "Webhook auto deployment started at ". date("Y-m-d H:i:s") . "\n". shell_exec("sh /opt/lampp/htdocs/autodeploy/deploy.sh")."\n**********************************************\n\n", FILE_APPEND);
die("Deployment success");
}
else {
die("Auth token invalid or no triggerable event found");
}
?>
Code of deploy.sh
#!/bin/bash
cd "/opt/lampp/htdocs/nodejs/myapp"
echo "Stopping application..."
forever stop index.js
cd ..
sudo rm -rf myapp
echo "Pulling latest code from gitlab..."
git clone -b "master" https://myusername%40domain.com:MyEncodedPass123#gitlab.com/myusername/myapp.git
cd myapp
echo "Installing dependencies..."
npm install
echo "Starting application..."
forever start index.js
echo "Application started on port 3000."
When I push code to gitlab, it triggers the webhook and initiates the deployment process and I see my webhook file gitlab.php returned success response to Gitlab and has written following output in autodeploy.log file
Webhook auto deployment started at 2021-10-03 13:32:07
Stopping application...
Pulling latest code from gitlab...
Installing dependencies...
Starting application...
Application started on port 3000.
**********************************************
But, the deployment actually never happens. It just runs the echo statements (and may be cd, rm etc as well) and rest of the shell commands are kind of ignored or not executed. It for sure doesn't run the git clone command, because I do not see latest code getting refreshed on my server from gitlab. Not sure though what happens to the npm and forever commands.
By the way, this is a Ubuntu VPS server with latest ApacheFriends XAMPP server installed, php v8. All the three files mentioned above reside at the same path i.e. /opt/lampp/htdocs/autodeploy and my deploy.sh script tries to deploy a separate nodejs application in /opt/lampp/htdocs/nodejs/myapp folder. Strangely enough, when I run deploy.sh directly from terminal it deploys the latest code successfully. Which means, all the statements in the script gets executed as expected. It only fails when executed from the php script using shell_exec() function.
Any clue what could be the reason?
The documentation for shell_exec doesn't state it clearly, but chances are you only get the stdout of your command, not its stderr -- the first comment certainly seems to indicate that, it would also match the "it's the same thing as backtick" decription.
If such is the case, you simply don't have the error messages in your output.
Try running :
shell_exec("sh .../deploy.sh 2>&1")
I also second #phd's suggestion (in the comments to your question) : turn set -e on, at least your script will halt when you get an error.
Chances are your current script would fail at the first line : cd "/opt/lampp/htdocs/nodejs/myapp".
I also strongly advise to drop the sudo in sudo rm -rf ....

Executing shell commands via PHP?

I am trying to ssh to a remote server to check to see if a specific file exists.
I am able to ssh in the command line but whenever I try to with my script it does not return anything / I have to type "exit" and hit enter to get back to the command line.
Steps:
ssh root#website.com
cd ..
ls ATMEXTRACT
I put all of these commands into ouputs so they look like this:
$output = shell_exec("ssh root#website.com");
$ouput1 = shell_exec("cd ..");
$ouput2 = shell_exec("ls *ATMEXTRACT*");
echo($output2);
I am confused as to why this works directly in the command line but is failing in the script. Any help is much appreciated
Here's what you do interactively:
Run ssh root#website.com in the current shell
Input cd .. in ssh
Input ls *ATMEXTRACT* in ssh
Input exit in ssh, which now exits
Find yourself back in your original shell
Here's what you do in your script:
Run ssh root#website.com in a new shell and exit it
Run cd .. in a second shell and exit it
Run ls *ATMEXTRACT* in a third shell and exit it
You could try to open and interact with an ssh command, but you can also just save yourself the trouble and use ssh's command line feature for specifying the commands to run:
$output = shell_exec("ssh root#website.com 'cd .. && ls *ATMEXTRACT*'");
Be aware that this is likely to fail from a PHP website script because you need to set up an authentication mechanism. This true even if ssh root#website.com connects without a password when you manually log in to the web server and try it.
I would recommend you to use ssh2 module of PHP. This will help you to connect any remote server which is reachable through appropriate SSH PORT.
You will need to check, if few modules like OpenSSL and ssh2 are installed on your host server.
if not please check this https://ehikioya.com/install-ssh2-php/ and install above modules.
once these modules are installed and enabled.
follow this code.
$server="website.com";
$server_pwd="Password";
//creating connection using server credentials
$connection = ssh2_connect($server, 22);
//authenticating username and password
if(ssh2_auth_password($connection, 'root', $server_pwd)){
echo "connected"
}else{
echo "could not connect to server";
}
ssh2_exec($connection, "ls /FULL_PATH/ATMEXTRACT"); //run your command here

phpseclib not working to execute commands remotely

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().

How can I use PHP to setup an interactive SSH session?

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.

sudo in php exec()

I don't know what the deal is here…
So I want to run an applescript: sudo osascript myscript.scpt
This works fine in the terminal, but not when I execute it via PHP's exec(); nothing happens. The console says
no tty present and no askpass program specified ; TTY=unknown ; …
I did my research, and it seems I'm missing the password for the sudo command. I tried a couple different ways to get around this, including:
writing %admin ALL=(ALL) ALL in /etc/sudoers
and proc_open() instead of exec()
none of which seem to be working, consequently driving me CrAzY!
So basically, is there a clear-cut way to get PHP to execute a simple terminal command?
EDIT: to clarify, myscript.scpt is a simple appleScript that changes the onscreen UI (for a larger project). In theory, simply osascript myscript.scpt should be enough, however the sudo is for some reason necessary to invoke some response from the system. If the sudo could be somehow eliminated, I don't think I would be having this permissions problem.
It sounds like you need to set up passwordless sudo. Try:
%admin ALL=(ALL) NOPASSWD: osascript myscript.scpt
Also comment out the following line (in /etc/sudoers via visudo), if it is there:
Defaults requiretty
I think you can bring specific access to user and command with visudo something like this:
nobody ALL = NOPASSWD: /path/to/osascript myscript.scpt
and with php:
#exec("sudo /path/to/osascript myscript.scpt ");
supposing nobody user is running apache.
php: the bash console is created, and it executes 1st script, which call sudo to the second one, see below:
$dev = $_GET['device'];
$cmd = '/bin/bash /home/www/start.bash '.$dev;
echo $cmd;
shell_exec($cmd);
/home/www/start.bash
#!/bin/bash
/usr/bin/sudo /home/www/myMount.bash $1
myMount.bash:
#!/bin/bash
function error_exit
{
echo "Wrong parameter" 1>&2
exit 1
}
..........
oc, you want to run script from root level without root privileges, to do that create and modify the /etc/sudoers.d/mount file:
www-data ALL=(ALL:ALL) NOPASSWD:/home/www/myMount.bash
dont forget to chmod:
sudo chmod 0440 /etc/sudoers.d/mount
I recently published a project that allows PHP to obtain and interact with a real Bash shell. Get it here: https://github.com/merlinthemagic/MTS
The shell has a pty (pseudo terminal device, same as you would have in i.e. a ssh session), and you can get the shell as root if desired. Not sure you need root to execute your script, but given you mention sudo it is likely.
After downloading you would simply use the following code:
$shell = \MTS\Factories::getDevices()->getLocalHost()->getShell('bash', true);
$return1 = $shell->exeCmd('/path/to/osascript myscript.scpt');
Run sudo visudo command then set -%sudo ALL=(ALL:ALL) to %sudo ALL=(ALL:ALL) NOPASSWD: ALL it will work.
I had a similar situation trying to exec() a backend command and also getting no tty present and no askpass program specified in the web server error log. Original (bad) code:
$output = array();
$return_var = 0;
exec('sudo my_command', $output, $return_var);
A bash wrapper solved this issue, such as:
$output = array();
$return_var = 0;
exec('sudo bash -c "my_command"', $output, $return_var);
Not sure if this will work in every case. Also, be sure to apply the appropriate quoting/escaping rules on my_command portion.
The best secure method is to use the crontab. ie Save all your commands in a database say, mysql table and create a cronjob to read these mysql entreis and execute via exec() or shell_exec(). Please read this link for more detailed information.
killProcess.php
I think directly calling a sudo command might be difficult because you are setting up the whole server to work without a password.
Perhaps as an alternative you could setup a CRONjob as root and monitor a flag file. Once the flag file exists it will run the osascript myscript.scpt and then delete the flag file.
This way you will keep SUDO secure from a config point of view and the server safer. To run the script you just need to touch the flag file from PHP.
It would of course introduce a delay of however many minutes you running the CRON job. It would also mean that you would have to redirect the output to a file and have a async monitor of the output, but it will depend on your application if this is a problem or not.
But it is an alternative that might protect the server.

Categories