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