Bugtraq entry for glob():

Bugtraq id #12701
Bugtraq posting with further details

Proof of concept for shared session:

This page sets $_SESSION['foo'] and $_SESSION['credit']. This might have been an ordinary page where a user has no access to the session-data.

By looking at the PHPSESSID we could re-use this session-id on another virtual host based on the same webserver (using the same temp-folder for session-data).

As a help, we have provided a link to another virtual host based on the same server with PHPSESSID pre-filled. This could be done manually though, even if session.use_only_cookies is enabled (it would just take a small amount of time to craft a cookie)
Go to other website on same server

For debugging purposes only, we will show the contents of your session ($_SESSION). Of course, a typical site would not reveal this info to the user. This page only sets foo (to value "bar") and credit (to value "20").

foo = bar
credit = 20

If superuser is present and credit has been changed from 20 to 1000000, they has been added and changed from another website:

PHP Session security flaw - bypassing safe_mode and open_basedir


This page concerns a couple of security related flaws in PHP4+PHP5. Some basic understanding of PHP is required.

These pages demonstrate that session-data is available for all virtual hosts on the same webserver. Serverside-session-data for one server is viewable and editable from another virtual host that uses the same temp-folder for session-storage, which would be the case for most web hosting providers.

If your website is based on the same server as other sites, you might be able to trick your way in to otherwise restricted pages on the other sites (using code on your own website to read and manipulate the data). Even if the two different websites are running in Safe Mode you still wouldn't be restricted from performing this operation.

A local solution might be to specify your own session path (or asking your administrator to do so). This solution, however, isn't very realistic in a global perspective. Futhermore, an attacker would still be able to hijack sessions (though not knowing their content).

No global fix:

In reported PHP-bug #28242 it appears that a workaround is encouraged instead, where every administrator has to customize every virtual host block. The problem is as follows:

My hope is that it is possible to convince the fine PHP-crew (no sarcasm, they are doing an excellent job) that there isn't any reason not to add this feature to increase security per default, since a default setup - even in safe mode - currently should be considered insecure.

glob() makes this bug worse:

glob() in safe_mode does not only check UID for directory, but will also work if just the first file in the glob()-result matches the UID. This way all session names can be retrieved fairly easy, meaning that all session data on server (not just our own) would be readable and writable.

It is extremely easy to retrieve a file list, as glob() by nature is pretty flexible, e.g.:
Here we first match files in our own directory (thus making sure the first matched file will be owned by us), and then any other directory - /tmp in this case.

This reported PHP-bug #28932 is also regarded as a headache of the administrator, even if glob() ought to behave the same way as opendir().

Furthermore, even with safe_mode- and open_basedir-restriction, glob() still reveals the first matched name in the warning (e.g. glob("/tmp/sess*") would give ".. is not allowed to access /tmp/sess_11c68bddfd11c68bddfd11c68bddfd11..."). We could just glob sess_1*, sess_2*, sess_3*, sess_30*, etc. for more file names. It should be pretty easy to walk through file names to retrive some sessions without having to bruteforce-guess file names.

Even if another virtual host on the same server has its own session.save_path, pointing at some secret directory, this could easily be found by trigging a session-related error, disclosing the save_path. The easiest way is to enter the site with an invalid PHPSESSID, like ?PHPSESSID=_ - PHP will first yield an error regarding the invalid character, and then at the end of the output: "Failed to write session data (files). Please verify that the current setting of session.save_path is correct (/path/to/session/files)". Then we can just proceed with glob("/path/to/session/files/a*") etc. on the server. Of course, even if session.name has been changed, we might be able to figure out this name by visiting the site as a regular user at first.

Further details:

Read http://news.php.net/php.internals/10849 and http://news.php.net/php.internals/11549 for a detailed description of these bugs.
Look at PHP-bug #28242 (session) and PHP-bug #28932 (glob) for the original bug reports (marked as "bogus")


Peter Brodersen, http://pe.ter.dk/ - last updated: 2005-12-09
Contact me at: php@ter.dk