Hi,

This post is about some general considerations about inexpediencies
regarding safe_mode and documentation. This is not about the fundamental
flaws regarding safe_mode, but rather some unfortunate side-effects,
that *could be fixed*. Please pour up a nice cup of coffee or tea :) My
questions are at the bottom of this post.


I have recently posted some bug reports regarding security issues on
servers running in safe_mode, regarding multiple users on the same
server that should be entirely separated ("the shared-server security
problem"). The bugs are #28242 and #28932, that has been dismissed
(mainly due to "Administrators are able to configure their way around
these bugs" and "safe_mode is generally flawed in the first place"):

http://bugs.php.net/bug.php?id=28242
http://bugs.php.net/bug.php?id=28932

First of all, let me clarify: I'm an old PHP user (using it with
pleasure since PHP/FI), I have submitted other bugreports with great
success (most recently the wordwrap()-bug which was fixed in CVS by
hard-working PHP-bugfixers about an hour after my report), I am able to
administrate my own server (providing custom setups with
session.save_path, safe_mode and open_basedir), I do know that safe_mode
might be considered a bit of a hack, but basically I'm just concerned
about the solutions that require that every sysadm out there should have
to make custom setups for every single virtual host out there! Of course,
in the perfect world, everybody would have his own server (or jailed or
otherwise totally isolated), but this is not the case.

Even if these bugs are rather to be considered "by design", there might
be a documentation issue. My premise is that the PHP webside is pretty
vague regarding security.

The Safe Mode chapter mentions: "The PHP safe mode is an attempt to
solve the shared-server security problem. It is architecturally
incorrect to try to solve this problem at the PHP level, but since the
alternatives at the web server and OS levels aren't very realistic, many
people, especially ISP's, use safe mode for now." - I assume it means
that even if it is considered architecturally incorrect, it is widely
used, and even if it is flawed, it doesn't mean that we should not fix
any bugs still present.

The Session chapter mentions: "You need to take additional measures to
actively protect the integrity of the session, depending on the value
associated with it." - lacking an explicit note that different virtual
hosts should have different session.save_path.


The two problems are as follows - always in safe_mode:

1) Sessions are shared across sites. A user can read and write to his
own session. (bug #28242)
Test setup: http://stock.ter.dk/session.php

If user A has his website hosted on the same server as user B, user A
can visit user B's website (which is using session), go to his own
website, re-use this session id, read information stored in the session
and even write to the session - and the returning to user B's website.
No file access is required at all, user A would just have to read and
write to $_SESSION. 

This could exploit many sites that store usernames and such in a session.

safe_mode uses the script's UID in many cases, and even adds it to the
realm in HTTP Authentication. A solution might be to add the UID to the
session file (e.g. "sess_1000_af872398..."), thereby separating
different users' scripts' session files.

A current solution is the custom setup where each and every virtual host
has to have it's own session.safe_path. This would be a configuration
hell for all ISP's! Still, I think that this is just avoiding a bug by
configuring.


2) glob() safe_mode check is based on (UID for directory || UID for
first file in pattern), and not just UID for directory. (bug #28932)

Furthermore, no warning is raised if glob() is performed on another
users' directory and there is no match (mearning we know which files
doesn't exist in a directory)

Even more, when safe_mode correctly raises a warning and prohibits glob()
from fetching a file list, it still discloses the first file name.
Basically we would ask "Give me the name of the secret file" and the
answer would be "No, I can't reveal the name of the secret file, since
you don't have access to verysecretfile.txt"

Exploit 1:
$list = glob("/tmp/sess_*");
(this would disclosure the first session file name, e.g. ".. is not
allowed to access /tmp/sess_14758f1afd44c09b7992073ccf00b43d ..")

Combine it with the "session shared across websites"-issue, and one is
now able to read and write not only his own sessions, but also this
session. Furthermore, one could just refine the pattern
(glob("/tmp/sess_1*"), glob("/tmp/sess_2*"), glob("/tmp/sess_3*"),
glob("/tmp/sess_31*"), etc.) and figure out more file names.

Exploit 2:
Create a folder, make it world-writable, create a php-script that writes
to a new php-file in that folder. This new php-file would be owned by
the Apache User, which also owns all session files. With the same code
as above, one is able to retrieve all session names.

Combine it with the "session shared across websites"-issue, and one is
now able to read and write not only his own sessions, but also other
users' sessions!


I believe that these issues are pretty serious and I think it is a pity
that they has been dismissed as "bogus" as they are exploitable. Even if
one can only get a file list (which might not be considered as harmful),
I still don't believe that there is any reason for why a user should be
able to snoop around e.g. in /etc for what configuration files is
present, or /home for usernames (or just a hint of how many users is
present on the server). Especially since opendir() has prevented this
for a long time.

I don't think that there is any reason at all not to perform changes.
glob() could easily be updated by:
1. only check UID for the directory
2. not allowing glob() to run in a foreign directory even if no files
matches the pattern
3. not disclosing actual file names when a warning is raised by glob()

Under any circumstance, since glob() is affected by safe_mode, it should
be added to the documentation under "Functions restricted/disabled by
safe mode":
http://www.php.net/manual/en/features.safe-mode.functions.php


The session issue is more complex. Even if the UID is added to the
session file, one could always create a file with same ownership as the
Apache User (as mentioned in example 2), thereby fopen'ing and
reading/writing the sess-file directly (it would be realistic to guess a
UID in a given time).

Basically I don't like the idea of users being able to access session
files directly, but I haven't got the perfect solution.

Maybe sessions should be stored in a directory of its own, and safe_mode
could for file access functions furthermore perform a realpath-check
preventing scripts to access session files. Maybe there is need for
another default storage mechanism for session. I hope other have better
ideas for this.


Summing up, my basic questions would be:

Even if an administrator is able to put up custom configuration, 
1. Is there any reason for not adding UID or the like to the session
files?
2. Is there any reason for not adding information in the documentation
regarding shared sessions?
3. Is there any reason for not mentioning glob() under "Functions
restricted/disabled by safe mode"?
4. Is there any reason for glob() performing a check on the first file
that matches the pattern, even if this gives arbitrary results?
5. Is there any reason for glob() disclosing file names on warnings?
6. Is there any reason for users to be able to figure out almost any
file name on the system using glob() (which would require less work than
brute force guesses)?

Thanks for reading all of this - and thanks for the hard work developing
PHP :)

-- 
- Peter Brodersen

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to