open_basedir setting limits the files that can be accessed by PHP to the specified directory. It should not be possible to access files outside of the directory set as
open_basedir. However, it is still possible to check whether files exist because the file used as client certificate in an SSL connection is not checked against
How open_basedir works
The files that PHP can access can be restricted with the
open_basedir option. For example, if
open_basedir is set to
/home/users/sjoerd, the script can not access any files in
/home/users/john. Here is an example:
<?php ini_set('open_basedir', getcwd()); readfile('/etc/passwd'); ?>
This sets the
open_basedir setting to the current directory and then tries to read the file
/etc/passwd, which is outside of the
open_basedir. This results in the following warnings:
Warning: readfile(): open_basedir restriction in effect. File(/etc/passwd) is not within the allowed path(s): (/test) in test.php on line 3 Warning: readfile(/etc/passwd): failed to open stream: Operation not permitted in test.php on line 3
Checking files outside of the open_basedir
Almost all file access in PHP is checked against the
open_basedir setting. One place where this check is missing is on the client certificate file in a SSL connection.
<?php $context = stream_context_create(array( 'ssl' => array( 'local_cert' => '/etc/passwd' ) )); fopen('https://www.google.com/', 'r', false, $context); ?>
If the file passed as
local_cert does not exist, the connection is set up and no warning is given. However, if the file does exist, the connection is aborted and the following warnings are emitted:
Warning: fopen(): Unable to set local cert chain file `/etc/passwd'; Check that your cafile/capath settings include details of your certificate and its issuer in check.php on line 8 Warning: fopen(): Failed to enable crypto in check.php on line 8 Warning: fopen(https://www.google.com/): failed to open stream: operation failed in check.php on line 8
This difference in behavior makes it possible to check whether a file exists outside of the
open_basedir. By checking the warnings or the HTTPS connection we can check whether the file exists.
open_basedir setting is not really meant for locking in users that can run arbitrary PHP code, but rather as an additional security measure for scripts that handle files. As such, bypassing it with the above example is not really a shocking security vulnerability.
You can check whether files outside the
open_basedir exist, but only if you can run arbitrary PHP code anyway.