I. Preface:
Okay, so here it goes.
I knocked my head to the wall several times, after finding out some security issues which cPanel has, like:
So... as you can guess, the best solution is suPHP + open_basedir.
But, as cPanel doesn't offer a solution for this configuration together, I managed to create a solution by my own.
II. Purpose:
This solution secures your server considering two different perspectives:
III. Solution - short description
RECOMANDATION: DO NOT DO THIS UNLESS YOU HAVE SOME LINUX OPERATING KNOWLEDGE;
(but if you own are a “Root Administrator”, I assume you have some
)
The following scripts, were made to monitor the httpd.conf file, so whenever they find a change in it, they generate a separate php ini configuration file, based on the DocumentRoot paths, and loads the open_basedir directive in them, according to the paths from httpd.conf
IV. Solution - long description
This solution was tested with:
...but should work with the most cPanel configurations using suPHP.
1. The first thing to do, is to find out if PHP is configured to scan for additional ini files, other than its main php.ini . To find out this, considering you are logged in the console as root, run the following command:
If your answer is like:
it means that your PHP is configured to look for other php ini files, and you can skip to step 3.
Otherwise, if it looks like this:
get to step 2.
2. You have to recompile Apache and PHP to scan for additional .ini files.
To do this, go in EasyApache from WHM main menu, get to “Exhaustive Options List” tab, and look for “Safe PHP CGI” checkmark, and check it. Then recompile Apache and PHP. Once its done, run again:
If it looks like this, it’s all good:
3. The /usr/local/lib/php.ini.d directory might not exist. Run the following commands to create it:
Note: in this directory, you can load your custom php.ini files, to configure whatever you want on your server; PHP will scan for ini files in this directory, and will load them instantly, basically without restart. (yeah, I wonder too how the hell it works without restart...)
Warning: Be aware of misspelled configuration directives, it might corrupt your PHP server.
4. For future purposes, let's create a file in /usr/local/lib/php.ini.d, named open_basedir.ini;
Execute the following command:
(in order to run the script smoothly for the first time, this file must contain ; character in it, which we just did with the command above)
To see if PHP has already acknowledged the file, run again:
and the result should look like this:
(observe the last line)
5. For future investigation purposes of the generated open_basedir paths which will be written in this file, we create another directory in /usr/local/lib/, named “ops” (ops comes from “old php settings”);
In this directory you will find any old used open_basedir.ini file, which was automatically replaced with a newer version, as to httpd.conf;
The files will be renamed like: open_basedir.ini.2015.01.16_02.42.55 name which will represent the date when they have been first put in use.
6. Enough with PHP ini files configuration. Now, let's get to the bottom of the problem:
We`ll create a directory in /home/, named .sys (yes, the dot is intended), where we will store the content of the project scripts.
These files will do all the job, monitor the httpd.conf file, and generate a php ini file according to the DocumentRoots found in httpd.conf;
Run the following commands:
7. Good. So far we have extracted the script files and made the main file executable. Now it’s time to configure the script. Basically, all you have to configure is your e-mail address where you will receive your daily or the fail report (if case).
Now let’s open the “inc.user-config.php” file, where you will type your own mail address:
And the first lines will look like this:
Now replace the ‘[email protected]’ with your own mail address, between the quotes. Ctrl + X to save, Y to confirm and that’s all.
8. Now, all you have to do left is to install the main script file to the crontab, which will run the script:
Go to the last line, get to a new line, and paste the following code:
Ctrl + X, Y to save… installing new crontab and that’s it.
You will get an e-mail with the first report which will look like this:
which is basically the report of what the script did.
9. You can verify the generated open_basedir.ini configuration file, by running this command:
And it will show you the generated php ini configuration file.
10. You can verify the status of your script anytime by running this command:
It will output the last 30 changes made to httpd.conf, and the last line represents the last time the script verified httpd.conf.
Description of the line:
Also, you will get this report on e-mail everynight at 00:00 AM, server time.
If you are interested in what other files represent in the working directory:
IV. Testing…
Create any PHP file anywhere with <?php phpinfo(); ?> content in it, and search for open_basedir value, and "voila"
Also, try to create a script which tries to get any file from outside of the user directory, and see ^^
V. That's all folks...
I hope you find this script useful for you also, and I didn’t numb your head with so much information.
If anyone of you has any further questions or issues, feel free to ask them, I will respond do them as soon as I can.
Regards,
Adelin a.k.a. likudio
Okay, so here it goes.
I knocked my head to the wall several times, after finding out some security issues which cPanel has, like:
- using only suPHP isn't secure enough (I managed to open root files with suPHP enabled, without open_basedir);
- the open_basedir tweak implemented in WHM limits users only to their working directory, not to the DocumentRoot of the domains that users have, so any script from any domain can navigate to other domain without any issues (see this topic).
- suPHP doesn't work with open_basedir in WHMs default configuration (so you have to use DSO or other handler, which doesn't handle permissions also)
- using only open_basedir without suPHP isn't secure, as if by mistake open_basedir gets disabled, without suPHP any user can navigate anywhere in the server.
So... as you can guess, the best solution is suPHP + open_basedir.
But, as cPanel doesn't offer a solution for this configuration together, I managed to create a solution by my own.
II. Purpose:
This solution secures your server considering two different perspectives:
- Limits a script to navigate outside of it's DocumentRoot (so you can have multiple domains in a cPanel account, which won't be able to get outside of their root directory; currently they are only limited to the Users Directory, so a script can reach wherever it wants in the UsersDir);
- Makes suPHP work with open_basedir together, which wasn’t possible until now using the current WHM configuration;
III. Solution - short description
RECOMANDATION: DO NOT DO THIS UNLESS YOU HAVE SOME LINUX OPERATING KNOWLEDGE;
(but if you own are a “Root Administrator”, I assume you have some
The following scripts, were made to monitor the httpd.conf file, so whenever they find a change in it, they generate a separate php ini configuration file, based on the DocumentRoot paths, and loads the open_basedir directive in them, according to the paths from httpd.conf
IV. Solution - long description
This solution was tested with:
- Easy Apache v3.28.1
- Apache 2.2
- PHP 5.4
- Mod SuPHP 0.7.2
...but should work with the most cPanel configurations using suPHP.
1. The first thing to do, is to find out if PHP is configured to scan for additional ini files, other than its main php.ini . To find out this, considering you are logged in the console as root, run the following command:
Code:
php --ini
Code:
Configuration File (php.ini) Path: /usr/local/lib
Loaded Configuration File: /usr/local/lib/php.ini
Scan for additional .ini files in: /usr/local/lib/php.ini.d
Additional .ini files parsed: (none);
Otherwise, if it looks like this:
Code:
Configuration File (php.ini) Path: /usr/local/lib
Loaded Configuration File: /usr/local/lib/php.ini
Scan for additional .ini files in: (none)
Additional .ini files parsed: (none)
2. You have to recompile Apache and PHP to scan for additional .ini files.
To do this, go in EasyApache from WHM main menu, get to “Exhaustive Options List” tab, and look for “Safe PHP CGI” checkmark, and check it. Then recompile Apache and PHP. Once its done, run again:
Code:
php --ini
Code:
Configuration File (php.ini) Path: /usr/local/lib
Loaded Configuration File: /usr/local/lib/php.ini
Scan for additional .ini files in: /usr/local/lib/php.ini.d
Additional .ini files parsed: (none);
Code:
cd /usr/local/lib/
mkdir php.ini.d
Warning: Be aware of misspelled configuration directives, it might corrupt your PHP server.
4. For future purposes, let's create a file in /usr/local/lib/php.ini.d, named open_basedir.ini;
Execute the following command:
Code:
cd /usr/local/lib/php.ini.d
echo ";" > open_basedir.ini
To see if PHP has already acknowledged the file, run again:
Code:
php --ini
Code:
Configuration File (php.ini) Path: /usr/local/lib
Loaded Configuration File: /usr/local/lib/php.ini
Scan for additional .ini files in: /usr/local/lib/php.ini.d
Additional .ini files parsed: /usr/local/lib/php.ini.d/open_basedir.ini
5. For future investigation purposes of the generated open_basedir paths which will be written in this file, we create another directory in /usr/local/lib/, named “ops” (ops comes from “old php settings”);
Code:
cd /usr/local/lib/
mkdir ops
The files will be renamed like: open_basedir.ini.2015.01.16_02.42.55 name which will represent the date when they have been first put in use.
6. Enough with PHP ini files configuration. Now, let's get to the bottom of the problem:
We`ll create a directory in /home/, named .sys (yes, the dot is intended), where we will store the content of the project scripts.
These files will do all the job, monitor the httpd.conf file, and generate a php ini file according to the DocumentRoots found in httpd.conf;
Run the following commands:
Code:
cd /home/
mkdir .sys
cd .sys
wget http://download.mcbsoft.net/cpanel-openbasedir-project/open_basedir.tar
tar xvf open_basedir.tar
cd open_basedir
chmod +x open_basedir.sh
Now let’s open the “inc.user-config.php” file, where you will type your own mail address:
Code:
nano inc.user-config.php
PHP:
<?php
// write your e-mail address on the line down below, between the quotes.
$CONFIG['WEBMASTER_MAIL'] = '[email protected]';
8. Now, all you have to do left is to install the main script file to the crontab, which will run the script:
Code:
crontab -e
Code:
* * * * * /home/.sys/open_basedir/open_basedir.sh > /dev/null 2>&1
You will get an e-mail with the first report which will look like this:
Code:
2 2015-01-16 02:21:41 | 4~12 2015-01-16 02:43:34
OK -->
Array
(
[STATUS] => 1
[LOG] => Array
(
[0] => Starting $generateINI... 2015-01-16 02:43:34
[1] => Succesfully loaded httpd.conf file, lenght: 55086
[2] => Starting processing the httpd.conf file...
[3] => Counted 4 paths...
[4] => Array
(
[path1] => Array
(
[0] => /home/path1
[1] => /home/path1/public_html
)
[path2] => Array
(
[0] => /home/path2
[1] => /home/path2/public_html
)
[path3] => Array
(
[0] => /home/path3
[1] => /home/path3/public_html
[2] => /home/path3/www_somepath
[3] => /home/path3/www_someotherpath
[4] => /home/path3/www_anotherpathl
[8] => /home/path3/www_x
)
[path4] => Array
(
[0] => /home/path4
[1] => /home/path4/public_html
)
)
[5] => Managed to copy the old open_basedir.ini file contents to /usr/local/lib/ops/open_basedir.ini.2015.01.16_02.42.55
[6] => Succesfully deleted the previous open_basedir.ini file from /usr/local/lib/php.ini.d/
[7] => Successfully written what we had to write...
[8] => End time: 2015-01-16 02:43:34
[9] => Array
(
[PHP_INI_DIR] => /usr/local/lib/php.ini.d/
[OLD_PHP_INI_DIR] => /usr/local/lib/ops/
[HTTPD_CONF_FILE] => /usr/local/apache/conf/httpd.conf
[SETTINGS_INI_NAME] => open_basedir.ini
[STATUS] => 1
[STATUS_FILE] => ./status.log
[FAIL_STATUS_FILE] => ./last_fail.log
[OK_STATUS_FILE] => ./last_ok.log
[HTTPD_MTIME] => ./mtime.dat
[MAIL_STATUS_FILE] => ./mail.dat
[WEBMASTER_MAIL] => [email][email protected][/email]
[ALERT_SUBJECT] => open_basedir.ini status
[COUNT_USERS] => 6
[COUNT_DOMAINS] => 20
)
)
)
<-- OK
FAIL -->
<-- FAIL
9. You can verify the generated open_basedir.ini configuration file, by running this command:
Code:
cat /usr/local/lib/php.ini.d/open_basedir.ini
10. You can verify the status of your script anytime by running this command:
Code:
cat /home/.sys/open_basedir/status.log
Description of the line:
Code:
2 2015-01-16 02:45:16 | 6~21 2015-01-16 02:46:01
- 2 - the first number is the status.
- 0 means no changes found in httpd.conf
- 1 means changes found, but the script failed to generate the open_basedir paths; it will issue a e-mail to your defined address with the fail report. The script sends only one failed e-mail per day.
- 2 means changes found, and the script successfully generated the open_basedir.ini file.
- 2015-01-16 02:45:16 - the first date displayed in the status line, is the last date when httpd.conf was changed and a new open_basedir.ini was generated.
- 6~21 . 6 represents the number of user directories found in httpd.conf, and 21 is the total number of DocumentRoot paths found according to the last changes of the file.
- 2015-01-16 02:46:01 - the last date represents the last time the script ran.
Also, you will get this report on e-mail everynight at 00:00 AM, server time.
If you are interested in what other files represent in the working directory:
- last_fail.log - represents the log with the information of the last failure of generation. (should never fail anyway, but was “failsafe” programmed)
- last_ok.log - represents the log with the information of the last time of a successful ini generation.
IV. Testing…
Create any PHP file anywhere with <?php phpinfo(); ?> content in it, and search for open_basedir value, and "voila"
V. That's all folks...
I hope you find this script useful for you also, and I didn’t numb your head with so much information.
If anyone of you has any further questions or issues, feel free to ask them, I will respond do them as soon as I can.
Regards,
Adelin a.k.a. likudio