Best Practice: Managing system programs from PHP site - php

I'm working on a VPN signup site, which is written in PHP and runs on the same Ubuntu server that the VPN server runs on. It allows users to sign up for VPN services, but currently it just emails the support staff their information, and they manually edit the config files on the server. I'm using PPP to handle authentication, so I have a file containing information like below:
# user server password ip
test l2tpd testpassword *
In order for a new user to be added to the VPN service, their details must be appended to the above table, and the command
sudo /etc/init.d/xl2tpd restart
run in order to apply the new changes. What I am looking to do is automate the process. From what I can tell, there are two options. One is to create a shell script, and then use shell_exec('./adduser test testpassword');. The other is to do it directly in PHP, by opening the file, modifying it and saving it again.
From a security and speed point of view, which approach is better, or is there another one which I haven't thought of?

sudo can be configured to execute just a specific command for a specific user, so modifying your sudoers file can mean you can use sudo in a more secure way to execute specific commands.
You could combine this with a wrapper script so that php was only executing a localised script with limited rights.
So your wrapper script, let's call it 'restart_auth.sh` may contain:
#!/bin/sh
sudo /etc/init.d/xl2tpd restart
You would then shell_exec('restart_auth.sh') from php to run that script.
You would edit your sudoers file to allow the user that the script was run as (your php user) to run /etc/init.d/xl2tpd. so if your php user is www_data edit sudoers (using visudo ) to contain:
user host = (www_data) NOPASSWD: /etc/init.d/xl2tpd
Provided no tainted data - that is unvalidated information that may contain shell escape characters - is passed through to a shell exec command then it is secure.
As someone else suggested it may be better to write the data to a pending list then read from that, rather than passing it on a shell_exec() line. However that can still introduce insecurities, so making sure the values you are writing to the file are untainted is the most important thing.
Also never run that full script as root even as a cron job, but instead use the same approach with sudoers to only permit the running script to execute specific commands as root. For instance you could allow sudo "cat changes.txt >> auth_file"

Related

Running command-line application from PHP which can be run with sudo

I am a newbie here, I am having a bash script which can be executed through terminal with sudo permission only. I want to run it from PHP with proper security. I dont know where to start to accomplish this considering security in mind. Should I create a additional user or what Will be the better way to achieve this. I got a reference with Running command-line application from PHP as specific user, but I am using Nginx and the mentioned solution does not work for me.
NGINX is a web server and not the interpreter. It is not very relevant.
In the standard NGINX + PHP-FPM setup, you should have a separate system user for your website anyway. So you don't need to create an extra user just for that command.
Simply ensure that this "website user" is able to sudo run your script, without being prompted for their password. This is achieved by visudo.
example ALL=/path/to/your/script
Where example is the PHP-FPM pool user, aka, the "website user" and the owner of the website's files.

Execute a bat file as a specific user from php

I have setup a web server and based on an HTTP request and need to execute a script as a different user.
So with regard to that, can I run HTTP as the user I need?
Or can I provide password non interactively and include something like below as the first line of the bat file.
runas /user:dmn1\user1 cmd
First of all its not a good idea to execute bat,sh or any other files from the commands can be tricked any ways.
You can use php's exec() to execute system commands.
If you're trying to execute the command as a different user in the web server itself then I don't know how that is done but If you're trying to execute cmd via browser it can be achieved via .hta script which might not work with modern browsers except IE.
Windows lacks built-in sudo-like functionality.
Your options are:
Use a 3rd-party tool such as psexec (requires specifying password in cleartext; might be a bit glithy sometimes) or sudo for windows (allows webserver user unrestricted administrative access - insecure).
Run another web-server instance with the required user credentials on a different port and redirect requests there with .htaccess (this may be very insecure!)
You can only allow local access and use CURL from 1st webserver to make requests to the second one
Open "task scheduler" (taskschd.msc) and create a task, select the user as owner and enter their password.
To run the task use:
schtasks /run /s SERVERNAME /tn "SCHEDULEDTASKNAME"
You cannot pass parameters to the task directly - you can use a file but beware of overlaps if two people access the HTTP simultaneously
Run a BATCH file (or a python/powershell/autoit script) that monitors a directory for files. When a file appears, read parameters from there, run the task, and delete the file.
You can run the "server" script via task scheduler.
HTTP server should then create files in that folder with long random names.
If creating files is undesirable you may be able to use a named pipe or local TCP connection (netcat) or similar
write a system service yourself (you may need a tool such as NSSM to actually make it run as a service )

What are the caveats when leaving apache with ALL(ALL) = ALL?

I'm creating a web app (php) that handles the creation of Drupal sites on a live server.
The system is able to create new sites and give some maintenance on existing ones. And, as this is a web-hosting environment, each folder may belong to a different user.
In order to do that properly I need to let the apache user run some commands as some other user.
What I do to create new files (and interact with git/drush/etc) is something similar to:
$some_command = `echo "PASSWD" | sudo -u USER -S do_something 2>&1; echo $?;`;
I already have a set of commands on the sudoers file that the apache user can run as the git user.
My issue now is that I need to let apache run as ANY user that may have a hosting account on the server.
My idea was to create a apache ALL=(ALL) ALL entry on the sudoers file. I would still leave all those commands asking for the users password.
With that in mind, is this wise to go with this approach? And if not, maybe I could apply the "allow all" policy only to the users that have a hosting account. If so, how do I narrow the policy to only one group?
Thanks
Edit: I though on using suPHP for this, as it allows apache to run each PHP script as its owner. But I would still need to run some other commands as another user (as creating files in someone else's home folder/public_html), so it seems that it isn't an option.
Based on our discussion in comments, I would advise installing something like suPHP so that each of your user's scripts are owned by their actual user and not Apache.
I figure you are having this issue is (maybe) because you want to be able to perform the administrative functions of other user's sites from a web interface. If you have a generic user like apache that other users can run scripts as, allowing that user automatic sudo permission is a bad idea since it could easily be exploited to gain unauthorized access.
To get around that, make sure you run your administrative functions as a special admin user that has permission to modify other people's files. Also make sure to chown any files you create as the appropriate user so they can read/write them. And as long as no other users can access that admin account or run PHP scripts as them, you should be much safer.
If you're running the admin functions from the console then it should be even easier, otherwise just set up a suPHP user to run your master functions from the web and use good credentials for the account.
Doing something like that will be more secure and should allow you to do everything you need without opening things up more than necessary.

how to execute a .exe program by php script

I want to execute a .exe file on my Apache server using a php script.
the procedure is as follow:
user comes, fills a html form
it goses to a php script
php script executes the name.exe file
php prints the output of the name.exe file on the page.
I execute the name.exe normally from windows like this:
run--> cmd--> D:\name [command]
the name.exe needs to communicate with other files like libraries in the same directory.
the complete comand in cmd at windows is like this:
D:\name library.dll [input from user]
then program executes and prints some results in cmd window.
I actually want to run this program on my server form my clients.
I don't know how, but I now there is a way to do this.
Another related question, is there any shell that I can install on Linux server and execute name.exe in it?
Please rethink your solution as this will likely create more problems (particularly security issues) than it solves. By having a PHP script execute your program you run the danger of a user entering the following into your form:
John Doe; rm \windows\*
or
John Doe; rm d:\name\*
You want to limit user input to a very controlled subset so that you won't get malicious command injection.
PHP does provide an exec() but be very careful.
You should escape the user input with escapeshellarg before sending it to the command.
$saferinput = escapeshellarg($input);
system('D:\name library.dll '.$saferinput);
You probably want passthru() or exec().
As for Linux, if name.exe runs well under WINE, you would probably want to use passthru() or shell_exec() and call WINE to run name.exe. I have no idea what name.exe does, so even if it runs under WINE, there's no guarantee that it will actually work.
There is, however no magic shell that allows Linux to execute arbitrary Windows executables.
As noted, be very careful of what you allow to get to exec() or passthru() or anything else that executes code outside of your script. I'm not going to go as far as to say you probably should not be doing whatever it is that you are doing, but I'm not the one working on whatever you are working on :)
This is a very bad idea. Aside from having to grant ridiculous permissions to the user account under which your web server is executing, which effectively gives anyone visiting your site the power to run executables, your run the risk of thread safety issues, file system locking problems, and others.
If you absolutely must use this exe, create a queuing system. Have your site put the form request into a convenient repository (say, a database), and have a service poll the database periodically to run this process. This allows separation of user accounts and associated permissions for the website and the exe, eliminates any concurrent execution issues, and decreases response latency for your site.
Some (cough) languages allow you to create this service and your site code in the same language/techology, but in this case you'll have to break out the .NET or other compiled language in order to create such a service.
I think we can do this by connecting to the server using PHP SSH. There is a library (http://phpseclib.sourceforge.net/) which allows you to connect to the server via SSH. Earlier I tried connecting to the server using telnet and execte .exe. But my school admin has blocked telnet due to security reasons, so I need to work on ssh.

Can PHP restart Apache?

I have a local server which needs to make changes to a virtual hosts apache config file and then restart apache so the new config takes effect.
Can PHP do this? I tried passthru and exec but they didn't work. Maybe the problem is that I'm trying to restart PHP's parent process?
Thanks for any help!!
I've used a cron script (written in PHP, not executed from the webserver) to check a server is up and restart the server.
However, I wouldn't do this from a server-created process, because you know you're about to kill the parent process, which has bad implications for the child.
The simplest method would be to have a file /tmp/RESTART_APACHE which PHP can create, and which the cron script checks for. If the cron script sees the file /tmp/RESTART_APACHE then it does a proper restart of Apache.
Using a cron script will introduce a delay (up to 60s if you run it each minute), but apart from that should work as you want.
Depending on how you intend using this, that may do the trick.
(You probably want to use a different directory than /tmp/ to set permissions and prevent anyone on the server being able to create the file.)
EDIT: Please see Aaron H's comment to this post. I agree with what he says: you really do want to be careful that the ability to restart your webserver is not a service generally available to the public.
Restrict access to the system which can trigger the restart; ensure that the file which triggers the restart has restrictive permissions so only the web process can create that file, and generally be smart.
I've done this for the very exactly thing. However it was solely for a development environment, to quickly create virtual host for our developers on demand. Worked very pleasing well so far.
My approach was to create a new user on the system, give this user sudo rights to reload apache and from Apache->PHP I used SSH to localhost with an authorized key without passphrase to that user, issuing the command.
The reason for this was that I didn't wanted to give the apache user (usually www-data) the power in general to reload itself. I named the new user wwwctrl.
The command I used was:
ssh -i /path/to/key-file wwwctrl#localhost sudo /etc/init.d/apache2 reload
I had to execute this command manually one time as wwwctrl user to have the local host key being added to ~wwwctrl/.ssh/known_hosts.
I used proc_open() to watch the execution of the command.
In fact I was generating a batch of virtual hosts for different Apache installations on different systems so on every system I had this wwwctrl user to reload Apache, basically doing this in a "foreach hosts as host do ... wwwctrl#host#".
Wouldn't you want to pass a 'reload' instead of a 'restart?'
To do this you would need to edit the sudo file and then execute the restart command that is used on your system, using sudo of course. If you give details, I could tell you but do you even have access to do that? Is it hosted? Cron would probably be a better choice here though.
at will be able to do that, not sure if you can schedule down to the second but I guess that depends on the implementation
I would create a daemon to monitor the sites-enabled directory and restart Apache when files are added or modified. Then you don't have to wait up to 60 seconds as with a cron job.
This sorta thing violates the standard chain of command since apache invokes php, not the other way around. I second the cron suggestion. Just set a cron job with sufficient privileges to check for changes to the host file, and restart apache if any are found.

Categories