Shell_exec disabled when showing not disabled?

My backend template:

php_admin_value[disable_functions] = pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setprioritysystem,passthru,proc_open,popen

here is the screen shot showing phpinfo(); which confirms this

But testing on a blank index.php:


if(function_exists('shell_exec')) {
	echo "shell_exec is enabled";
} else {
	echo "shell_exec is disabled";

outputs shell_exec is disabled

Using Nginx/php-fpm. Any thoughts on where or why this is getting disabled?

It is being disabled by default disable_function conf:

grep disable_function /etc/php/8.2/fpm/php.ini

Thanks @sahsanu That worked!

So I understand correctly it sounds like /etc/php/8.2/fpm/php.ini overrides everything below i.e. hestia backend templates or php.ini in docroot if I was using apache. Is that true?

I would have assumed the hierarchy would be the other way around i.e. lower levels would override the higher levels when present. I tried to search but I couldn’t find a definitive answer. It seems strange the phpinfo() would not display it as disabled. If you can point me to any resource or explain how it works, that would be great!

I’m thinking about just commenting out disable_functions at the /etc/php/8.2/fpm/php.ini level and managing that completely with templates. Do you see any downside to that approach?


Yes and no :wink:

Some directives can be overrided by .htaccess, php.ini files inside docroot , .user.ini or php_value and php_admin_value inside php-fpm templates but others can’t.

As I said above, that’s true for some directives. Here a list of php directives, pay attention to column Changeable and you will see where the value can be overrided.

Meaning of different modes:

INI_USER: Entry can be set in user scripts (like with ini_set()) or in the Windows registry. Entry can be set in .user.ini
INI_PERDIR: Entry can be set in php.ini, .htaccess, httpd.conf or .user.ini
INI_SYSTEM: Entry can be set in php.ini or httpd.conf
INI_ALL: Entry can be set anywhere

Well, if you are sure all your templates will disable all dangerous functions, go ahead but keep in mind that if you forget to add them, your site could be at risk.

Thank you SO much for this answer @sahsanu And I always appreciate the thoroughness of your answers. I learn so much!

There were no links to PHP: List of php.ini directives - Manual in the php manual pages I was looking at, and the changeable column is super helpful! It also solves a long time mystery of trying to use ini_set() some years ago and it wasn’t working. And I gave up.

  1. Do you have any idea why phpinfo() would not display it correctly? Am I missing something or is that very weird design?
  1. Fair. I assume that the danger is contained to what files the site’s linux user can write to. True?

Also I assume I can limit/grant command execute privileges that users have access to via something like shell_exec, but I’m not sure the best way to do that:

It seems like open_basedir would have an impact. :/bin:/usr/bin:/usr/local/bin:/usr/share:/opt For example, I assume I could remove all of this, make a new directory with symlinks back to these directories for only the commands I allowed users to run.

  1. True? Or maybe I don’t understand how open_basedir works…

It also seems like I can grant permissions in the sudoers file for things that I need like:

username ALL= NOPASSWD: /bin/systemctl restart memcached

  1. True?

  2. In short, there are just a couple things the site needs to do via shell_exec like git pull, restart a couple services, access wp cli, etc. It’s been on my list to figure out the best security practices for this rather than leave shell_exec completely open. Any thoughts you have would be appreciated!


1 Like

No idea.

That’s true, but not only write perms, read or execution perms can cause too much damage :wink:

Not true :wink: Let me quote this paragraph from php’s doc:

When a script tries to access the filesystem, for example using include, or fopen(), the location of the file is checked. When the file is outside the specified directory-tree, PHP will refuse to access it. All symbolic links are resolved, so it’s not possible to avoid this restriction with a symlink. If the file doesn’t exist then the symlink couldn’t be resolved and the filename is compared to (a resolved) open_basedir.

So removing the bin directories and adding symlinks to an allowed dir won’t work… fortunately :wink:

Are you sure you need to do that from php? Allowing a web app to run commands with sudo, uff… I wouldn’t do that, too much headaches. Also, you should disable requiretty option for that user to be able to uso sudo without a shell.

Instead of allowing the use of exec, shell_exec, etc., using sudo… I would allow your web app to write some control files inside an specific directory and would create a script that checks those files; if file x exists do y, or if file x exists and contains z do y, etc. and I will add it to cron so it can run every x minutes to perform the required actions, maybe it’s not an elegant or efficient workaround but seems a better security approach (the control of the actions is entirely yours instead of a user launching random commands using your web app). Anyways, I’m not an expert on this so I’m pretty sure others could have better solutions to accomplish those tasks.

Belated thanks for your reply @sahsanu

I’m not sure I was communicating accurately (or thinking it through completely). I was wondering about disabling bin access all together in open_basedir, creating a new directory with simlinks to ONLY the commands that would be accessible and adding that new directory to open_basedir. Are we talking about the same thing?

Also maybe miscommunication with this one? This username ALL= NOPASSWD: /bin/systemctl restart memcached would NOT be added by php. But rather added ahead of time to give access to that user to restart memcached. Are we talking about the same thing?

Thanks for that suggestion. Definitely better security, but unfortunately, the things I need are on demand and running a cron wouldn’t work for my situation.

I appreciate your answers as always!

Yes, we are and as I said, that is not possible.

Yes, we are… again :wink: I didn’t say to create/add the sudo part into sudoers using php but using php to launch something that allows the use of sudo, well it could work but use it only if that’s your last option.

Thanks for the confirmation @sahsanu