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?
-
7No matter what you do, it's never `secure`.. – halfdan Apr 13 '11 at 17:15
6 Answers
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

- 5,084
- 1
- 46
- 65
-
I forgot to mention a wrapper that doesn't take arguments! Making a wrapper script that accepts no arguments reduces the attack surface. Some programs would be able to be manipulated to do bad things if executed with certain arguments. Using a wrapper allows you to allow a program to be launched in a more controlled way. – Caleb Apr 13 '11 at 17:21
-
All files that need root access are located in /var/private-www/, only available by root access. Is it possible to let them use sudo? I tried `http ALL=(ALL) NOPASSWD:/var/private-www/`, but that didn't work. – www.data-blogger.com Apr 13 '11 at 17:24
-
Or just mention using: http://php.net/manual/en/function.escapeshellcmd.php on any arguments you are passing through. – Jim Apr 13 '11 at 17:25
-
No. Wild-carding them like this would introduce more security issues. List them one by one. Also, if you really have more than one of them, I think you need to reconsider your whole architecture. It sounds like you there should be a better way to do this, but since we don't know your situation we can't exactly suggest one. The only hack that comes to mind would be to make your wrapper script decide what to execute based on an argument, but again you introduce security issues by the dozen. – Caleb Apr 13 '11 at 17:27
-
@kevin, also be sure to change `http` to the actual user that is running it (incase it is not `http`) just an FYI. – Jim Apr 13 '11 at 17:28
-
Ok, tried `www-data`, but that didn't work either. But can all PHP scripts access `/var/private-www/` in that case? The system is more secure than it was. At first, all users got SSH access. Now there is a webplatform where users can do SVN stuff and get FTP access. So they can test at our server, and commit when they are satisfied. For this SVN stuff I need root access, but also for MySQL related stuff. That's the case. – www.data-blogger.com Apr 13 '11 at 17:33
-
@kevin I think you need to switch gears here. You shouldn't need root for this. You can setup your repositories to be owned by www-data (or your http user) so that commits and such can be handled through the http daemon without escalated privileges. What do you think you need privileges for mysql for? – Caleb Apr 13 '11 at 17:36
-
For creating/deleting database users. I will use the platform for stuff that I did in shell. This will be easier. Or is it really so bad? – www.data-blogger.com Apr 13 '11 at 17:38
-
@kevin, yes it really is that bad. Don't do it this way. You don't have enough experience to patch up a system after you blow it full of holes with your proposed design. You can create and delete mysql users from a web interface without needing root privileges. Just give the user that your web app connects to the database with GRANT rights on those tables. – Caleb Apr 13 '11 at 17:44
-
Ok. Is it possible to execute tasks as another user? No I tried this, but output was empty: `$output = shell_exec('echo "nivek" | sudo -u kevin -S whoami');`. Why? How can I repair this? – www.data-blogger.com Apr 13 '11 at 17:53
-
Yes, but again why would you want to? And why the echo piped into sudo? Why don't you experiment with sudo from a shell account instead of from php, it would be easier to figure out what is a php problem and what is a sudo config issue. – Caleb Apr 13 '11 at 17:58
-
The thing is, it worked in the shell, but not in PHP. :( Why?? I don't get errors. – www.data-blogger.com Apr 13 '11 at 18:03
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.

- 18,673
- 5
- 49
- 65
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');

- 35,471
- 7
- 34
- 45
-
Thanks, but I found that wasn't working? I tried `system('echo "mypass" | sudo -u root -S mkdir /testdir');`, but `/testdir` didn't exist after I executed the script. – www.data-blogger.com Apr 13 '11 at 17:26
-
@Kevin: You may have to wrap `COMMAND` in quotes, or (if i'm right with my *nix knowledge) you can't create a folder in `/`. – drudge Apr 13 '11 at 17:45
-
2you cannot and should never be able to pipe a string into an interactive password prompt – mschr Jun 09 '12 at 22:40
-
This did help me but i did need to change it like so: `system('echo "PASS" | echo sudo -u root -S COMMAND');` – WolfyD Jun 16 '15 at 07:13
$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;

- 8,587
- 6
- 31
- 38
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.

- 7,255
- 4
- 23
- 38