Why adding a PHP script to sudoers file does not work? - php

It seems adding a PHP script to sudoers file has no effect, whereas adding a bash script allows you to run it as root.
To demonstrate that, assume we have the following three scripts:
/var/www/literal.php
exec('sudo whoami', $output, $return_var);
var_dump($output, $return_var);
/var/www/indirect.php
exec('sudo /var/www/script.sh', $output, $return_var);
var_dump($output, $return_var);
/var/www/script.sh
#!/bin/bash
echo "$(whoami)"
Also assume we have the following lines in the sudoers file (added through visudo of course):
www-data ALL=NOPASSWD: /var/www/literal.php
www-data ALL=NOPASSWD: /var/www/script.sh
Browsing to http://localhost/literal.php we get:
array(0) { }
int(1)
Going to http://localhost/indirect.php however we get this:
array(1) {
[0]=> string(4) "root"
}
int(0)
Obviously, the sudoer line worked for the shell script, but did not work for the PHP script. Is this an intentional, by-design limitation, or could I have hope to get it to work? If so, where should I look for causes?

In sudoers file you specify precise command to be run. So /var/www/literal.php at least should have a shebang like #!/usr/bin/php and launched in shell as is by typing /var/www/literal.php then Enter in order to be run by sudo.
When you run that same script "via browser", this isn't happening. Instead the PHP-FPM process is interpreting the script (NGINX passes its filename to PHP-FPM). You may say (although this isn't exactly like this) that the real command being run is more or less /sbin/php-fpm /var/www/literal.php, which of course won't match to what you have in sudoers file.
Whatever command that you want to be run as sudo via PHP script, you need to be placing in sudoers exactly as it will be run when prefixed with sudo, e.g.
www-data ALL=NOPASSWD: /usr/bin/whoami
www-data ALL=NOPASSWD: /var/www/script.sh
Then:
exec('sudo /usr/bin/whoami', $output, $return_var);
Will run successfully when the script is accessed from the browser.
An off-topic, but you should not be running anything as webserver user. The www-data is NGINX/Apache user. The scripts should run under a dedicated "website specific" user, for security purpose. More on that here.

With the explanation provided by #DanilaVershinin in this answer, I thought a recursive approach might work. I tried it and it did! So here it is:
Our PHP script calls itself in CLI if it detects it is being called via the web server:
/var/www/control.php
if (PHP_SAPI !== "cli") {
exec('sudo /usr/bin/php /var/www/control.php param1 param2', $output, $return_var);
echo '<pre>';
var_dump(PHP_SAPI, $output, $return_var);
exit();
}
exec('whoami', $output, $return_var);
var_dump(PHP_SAPI, $argv, $output, $return_var);
And this is the line we need in our sudoers file:
www-data ALL=NOPASSWD: /usr/bin/php /var/www/control.php *
The output we get by going to http://localhost/control.php shows the calling user is root and we have received the parameters (the * at the end of sudoers line is to still match when we have parameters.)
The important concern with this is the security risk. I will share a version of this on Github where the security risk has been mitigated and will provide a link here.

Related

shell_exec() not executing shell script

I've a shell_test.php file in /var/www/html folder with this code:
<?php
shell_exec('/var/www/html/config.sh');
?>
config.sh in the same folder has this code:
#!/bin/sh
sudo -u root kill -SIGHUP $(cat /var/www/html/mosquitto/mosquitto.pid)
When I run ./config.sh from folder, it runs.
When I run command in config.sh file directly in terminal, it
works too.
I've added this into sudoers file so that there is no need of password:
www-data ALL=(ALL) NOPASSWD: /var/www/html/config.sh
The thing is it's working fine when run using terminal in both the mentioned ways. Why is not executing when run in PHP?
Your problem is probably, that it is apache, www-data or some other user that is running your script and you try to run it as root.
Try without sudo -u root and change the group of the file to www-data with:
chown root:www-data your-script
As you say "It isn't outputting anything but my mosquitto broker is resetting every time it runs which lets me know"
I think you should replace
shell_exec('/var/www/html/config.sh');
with
$output = shell_exec('/var/www/html/config.sh');
echo $output;
According to php docs "shell_exec — Execute command via shell and return the complete output as a string"
shell_exec doesn't print by default; you have to store the string output and then use it
I made few changes in codes and it worked.
In shell_test.php, I changed code like this:
<?php
shell_exec('sudo -S ./config.sh');
?>
In config.sh, I changed like this:
#!/bin/sh
sudo kill -SIGHUP $(cat /var/www/html/mosquitto/mosquitto.pid)

How to execute shell scripts from php that requires root permissions?

Every time I execute my script with:
exec('sudo profile status-koneksi',$status);
print_r($status);
it always does nothing, I have no idea how to debug this one, my script requires root permission so I appended the following lines to /etc/sudoers file:
Cmnd_Alias ANGEL_BEATS = /usr/bin/profile, /usr/bin/socks, /usr/bin/gsm, /usr/bin/gssh, /usr/bin/ping_loop, /usr/bin/restart-openvpn, /usr/bin/sms.py, /usr/bin/sms_gateway, /usr/bin/socks, /usr/bin/ussd.py, /usr/bin/vpn, /usr/bin/wgetui
ab ALL=NOPASSWD: ANGEL_BEATS
%ab ALL=NOPASSWD: ANGEL_BEATS
However, it works just fine when I execute the command from my terminal:
How do I solve this ?
UPDATE:
As suggested by a comment below, I run this script:
if(exec("sudo sh /usr/bin/profile status-koneksi 2>&1", $output, $return_var)){ print_r($output); print_r($return_var); }
And it returns:
Array ( [0] => sudo: no tty present and no askpass program specified ) 1
Since your script requires root permission to run, it would be nice if you could set the setuid bit. Try this:
chmod u+s <your_script>
More info here (from Wikipedia)

I am passing text from a bash script to php. Everything works except the mount and unmount bash commands. What am I doing wrong?

I have a bash script that mounts a usb drive, reads a text file on the usb drive, and echos that file to the php program that called it. The mount and unmount does not work.
If I mount the usb from command line the php works. Evidence points to the umount and mount not working. Any feedback would be appreciated.
Bash Script: DisplayTextFile.sh
#! /bin/bash
umount /dev/sdc1
mount -t vfat /dev/sdc1 /media/usbdisc -o uid=1000,gid=1000,utf8,dmask=000,fmask=000
$filetoecho=$(</media/usbdisc/textfile.txt)
echo "File Content: $filetoecho"
umount /dev/sdc1
exit $?
PHP that Calls Bash Script:
ob_start();
$command="/bin/bash /path/DisplayTextFile.sh"
passthru($command, &$result);
$filetoecho=ob_get_contents();
ob_end_clean();
As suggested above, I added DisplayTextFile.sh to sudoers at /etc/sudoers and it worked. I used nano to make the following entry:
www-data ALL=(ALL) NPPASSWD: /path/DisplayTextFile.sh
Once that entry was made, the problem was solved. Thanks a bunch.
You probably aren't running as root, try to add your user to the sudoers group (install sudo if you don't have it) and then change your user privileges to use sudo without password.
It's not really safe, so you must know what you're doing.

shell_exec throws: sudo: no tty present and no askpass program specified

I have been trying to execute a script using shell_exec() function in php:
I've written the following lines of code:
$command = "bash /path/to/my/script/ funciton_name() 2>&1";
echo shell_exec($command);
Inside the shell script I'm doing:
sudo rsync -avvc /source/path /destination/path
On executing this on the browser, I get the following error message:
sudo: no tty present and no askpass program specified
When I execute the same shell script on my server, it executes fine.
When I went through similar questions posted on this forum, I realised that I had to add the NOPASSWD line on my server which I found out has already been added in the following format:
User_Alias NOBODY=nobody,apache
NOBODY ALL=(ALL) NOPASSWD : /path/to/my/script
Also when I do:
echo shell_exec("whois");
I get the output as:
apache
Any assistance in overcoming this problem would be of great help.
sudo will require a TTY, even if you have set up it up to be passwordless, unless you explicitly do not require it. But as #Cfreak pointed out, it would be much better (simpler and safer) to avoid sudo by setting correct access rights (read it before continuing) in the first place.
rsync itself will not require root permissions on a sanely configured *nix install. To verify this, you can check that type -a rsync doesn't print anything weird like rsync is aliased to `sudo rsync' and that ls -l $(which rsync) prints sensible permissions (at least rx for everyone).

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