php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #76362 Bypass open_basedir restriction via scandir and glob://
Submitted: 2018-05-21 14:19 UTC Modified: 2021-07-12 17:23 UTC
From: will at wbowling dot info Assigned:
Status: Verified Package: *Directory/Filesystem functions
PHP Version: 7.2.5 OS: Linux
Private report: No CVE-ID: None
 [2018-05-21 14:19 UTC] will at wbowling dot info
Description:
------------
Calling `scandir` with `glob:///*` will bypass any open_basedir that has been set and list the directories anyway.

$ php --version
PHP 7.2.5 (cli) (built: May  5 2018 00:18:54) ( NTS )

$ php -d open_basedir=/tmp ./poc.php '/'
Warning: scandir(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (/tmp) in /tmp/poc.php on line 1

$ php -d open_basedir=/tmp ./poc.php 'glob:///*'
Array
(
    [0] => bin
    [1] => boot
    [2] => dev
    [3] => etc
    [4] => home
    [5] => lib
    [6] => lib64
    [7] => media
    [8] => mnt
    [9] => opt
    [10] => proc
    [11] => root
    [12] => run
    [13] => sbin
    [14] => srv
    [15] => sys
    [16] => tmp
    [17] => usr
    [18] => var
)
$ php -d open_basedir=/tmp ./poc.php 'glob:///va*/*'
Array
(
    [0] => backups
    [1] => cache
    [2] => lib
    [3] => local
    [4] => lock
    [5] => log
    [6] => mail
    [7] => opt
    [8] => run
    [9] => spool
    [10] => tmp
)

Test script:
---------------
<?php
print_r(scandir($argv[1]));


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2018-05-23 22:09 UTC] cmb@php.net
FWIW, I cannot reproduce this (i.e. the open_basedir restriction
is in effect if I am using a glob stream wrapper).
 [2018-05-23 23:54 UTC] will at wbowling dot info
After a bit more testing it will only bypass the restriction if the current working directory is in the open_basedir:

$ pwd
/tmp
$ php -d open_basedir=/tmp/restrict restrict/poc.php 'glob:///*'
PHP Warning:  scandir(): open_basedir restriction in effect. File(/*) is not within the allowed path(s): (/tmp/restrict) in /tmp/restrict/poc.php on line 2
...

$ cd restrict/
$ php -d open_basedir=/tmp/restrict ./poc.php 'glob:///*'
Array
(
    [0] => bin
    [1] => boot
...
)
 [2018-05-24 15:02 UTC] cmb@php.net
-Status: Open +Status: Verified
 [2018-05-24 15:02 UTC] cmb@php.net
> After a bit more testing it will only bypass the restriction if
> the current working directory is in the open_basedir:

Indeed!
 [2020-05-05 15:04 UTC] cmb@php.net
The problem is in php_check_specific_open_basedir().  When
VCWD_REALPATH() is called[1] the first time, the path is not
resolved. In the following, path_tmp is set to an empty string[2],
and when VCWD_REALPATH() is called again with the empty string, it
resolves to the CWD, which is obviously wrong.

A simple fix would be:


 main/fopen_wrappers.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/main/fopen_wrappers.c b/main/fopen_wrappers.c
index 520edfadbb..6026ba0726 100644
--- a/main/fopen_wrappers.c
+++ b/main/fopen_wrappers.c
@@ -190,7 +190,7 @@ PHPAPI int php_check_specific_open_basedir(const char *basedir, const char *path
 #else
 		path_file = strrchr(path_tmp, DEFAULT_SLASH);
 #endif
-		if (!path_file) {
+		if (!path_file || path_file == path_tmp) {
 			/* none of the path components exist. definitely not in open_basedir.. */
 			return -1;
 		} else {


However, that would break setups where open_basedir=/

[1] <https://github.com/php/php-src/blob/php-7.2.30/main/fopen_wrappers.c#L168>
[2] <https://github.com/php/php-src/blob/php-7.2.30/main/fopen_wrappers.c#L209>
 [2021-07-12 15:38 UTC] cmb@php.net
-Type: Security +Type: Bug
 [2021-07-12 15:38 UTC] cmb@php.net
open_basedir bypasses are not considered to be security issues;
cf. <https://externals.io/message/105606>
and <https://externals.io/message/115406>.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Nov 21 14:01:29 2024 UTC