0

I want to do some tasks on my server that require root shell access. I want to make a simple API that I can access from PHP.

The things I want to achieve is:

  • clone from one database to another. The databases are owned by different users:

    mysqldump -h localhost -u SOURCE_USER -pSOURCEPASSWD SOURCE_DB | mysql -h localhost -u DEST_USER -pDEST_PASS DEST_DB

  • copy files from one user public_html to another:

    cp -R SOURCE_DIR DEST_DIR

I have working bash-scripts for both those tasks.

I do not want to give PHP full root access to the server, since that would be crazy, but instead:

How can I make specified bash-scripts executable from a PHP-file in one linux-user's public_html directory?

Alternatively: How can I give root shell access (via shell_exec) to ONE specified PHP-file on a server.

OnklMaps
  • 807
  • 8
  • 17
  • 2
    It is always recommended to add your efforts in your post too, kindly do so. – RavinderSingh13 Sep 20 '18 at 10:05
  • 2
    Check the `sudo` utility to grant access to certain commands, php also offers a convenient sudo-extension to interact with that. Or you can use sticky bits in the file system. Both options obviously require that your http server is based on a unixoid operating system (e.g. Linux), but that requirement is typically fulfilled. – arkascha Sep 20 '18 at 10:08
  • @arkascha Thanks! I found a similar question based on your input, and I adapted an answer myself :-) Was it someway similar to what you meant? – OnklMaps Sep 20 '18 at 12:52
  • You don't use the php extension in your answer below but an `exec()`, which is much less elegant, but ok. However you really need to take very good care to secure your script this way, since such setup obviously is a _huge_ security thread... – arkascha Sep 20 '18 at 13:24
  • I dont understand "You don't use the php extension in your answer below". Isn't it quite secure when I only allow sudo for myscript.sh, and nothing else? Lets say I did `$arg = "rm -rf /"; exec("sudo /path/to/myscript.sh && $arg");`. $arg would be ignored, right? – OnklMaps Sep 20 '18 at 13:33

2 Answers2

1

You could use this project: Github. It allows PHP to obtain and interact with a real Bash shell even as root without running the web server as root.

After composer/downloading you would simply use the following code:

//read the documentation: here you get a root shell if you allowed sudo
$shellObj    = \MTS\Factories::getDevices()->getLocalHost()->getShell("bash", true);

//OR if you did not want to give the webserver sudo access, then you can use this syntax:
$shellObj       = \MTS\Factories::getDevices()->getLocalHost()->getShell("bash", false);
\MTS\Factories::getActions()->getRemoteUsers()->changeUser($shellObj, 'root', 'rootPassword');

//In both cases you now have a shell as root. This really is a bash shell, its not just wrapping the PHP shell functions.

//All you have left is to issue commands just like you would on a bash prompt
$strCmd = "mysqldump -h localhost -u SOURCE_USER -pSOURCEPASSWD SOURCE_DB | mysql -h localhost -u DEST_USER -pDEST_PASS DEST_DB";

//for the vast majority of commands that finish within 10 sec you need only issue the command
$return  = $shellObj->exeCmd($strCmd);
echo $return;// return from your command

//However if your command runs for more than 10 sec, you must set a timeout. e.g.
//timeout in miliseconds
$timeout = 20000;
$return  = $shellObj->exeCmd($strCmd, null, $timeout);
echo $return;// return from your command

Feel free to issue more commands on the $shellObj, its a bash shell ready to take orders and as i said ready the documentation.

MerlinTheMagic
  • 575
  • 5
  • 16
  • Nice! Will try that out! I wonder though: if I was to give the web server sudo permission, how would your repo differ from using exec()/shell_exec()? – OnklMaps Sep 23 '18 at 21:09
  • 1
    @OnklMaps exec() and shell_exec() issue single commands, they do not maintain the environment, they operate without TTY, they are not interactive. Those are a few of the differences. This project sets up a real BASH terminal, just like if you sat at the console typing in commands. You get the true string return from the command and on error you get the same result as you would if you stared at the screen (not just the exit code). This is a very different animal. – MerlinTheMagic Sep 23 '18 at 21:14
  • 1
    @OnklMaps most times when you want PHP to do something as root, you build a BASH script and sudo it. That means handling all error logic in BASH as well, because if you let the script error out PHP cannot pick up from where the script ended, again its not interactive. With this project you can break up your long bash scripts and move exception handling to PHP. Issue a command, depending on the return execute the next. The project is supposed to mirror how you would interact with the console. – MerlinTheMagic Sep 23 '18 at 21:18
  • 1
    @OnklMaps in terms of security, letting PHP anywhere near root is scary. Either let PHP have sudo access to python (thats how we build the shell), or pass root credentials to the changeUser() function. You have to pick your poison, there is NO safe way to give PHP root access. – MerlinTheMagic Sep 23 '18 at 21:22
  • 1
    @OnklMaps one last thing, since you are dumping mysql, i thought i would mention that the project can also do SSH to another server and execute commands there. The interface is exactly the same, you just provide the IpAddress and user credentials for the remote server and voila you are executing commands over SSH. It might save you from having to install Apache and PHP on your Database instance. Read the documentation. – MerlinTheMagic Sep 23 '18 at 21:28
0

After an useful comment from arkascha I researched sudo and found Ezequiel Hdez's answer in sudo in php exec() to be useful in finding the answer to my question:

Allow myuser to sudo my shell script by adding in sudoers file (access it by typing visudo):

myuser ALL = NOPASSWD: /path/to/myscript.sh

Make script executable:

chown u+x /path/to/myscript.sh

Then in PHP (from "myuser")

exec("sudo /path/to/myscript.sh argument1 argument2"); 

Now I was able to do whatever I want from PHP, but ONLY via /path/to/myscript.sh

OnklMaps
  • 807
  • 8
  • 17