看板 Bugtraq 關於我們 聯絡資訊
--LZvS9be/3tNcYl/X Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable There is an issue with PHP's session handling in its default configuration = that is also partially pointed out in the manual: http://www.php.net/manual/en/session.configuration.php#ini.session.save-path > Warning > If you leave this set to a world-readable directory, such as /tmp (the > default), other users on the server may be able to hijack sessions by get= ting > the list of files in that directory. Debian uses a directory with mode "rwx--x--t" to get around that =E2=80=93 = this way, an unprivileged user can't list the contents of the directory and the attack the manual mentions doesn't work anymore. But is that secure? No, because any local user can still choose an unused session ID himself, t= hen create a mode 0777 file in that directory with a name matching the session = ID he chose and then fill the file with arbitrary session data. Any PHP instan= ce that uses the same folder for its session storage will then accept the attacker-chosen sessionid and associate the data from the file with it. What this means is that unless the admin of a box running PHP explicitly reconfigured PHP to use a secure folder, any local user can e.g. sign in to= any PHP webapp running on the system which uses sessions as admin by creating a fake admin session. Also, you might be thinking "so what about symlinks? could a local attacker also make the webserver read data from an arbitrary file using a symlink?". The answer to that has two parts. First part: The PHP session code explicit= ly checks for symlinks. Second part: It does this by opening the file, then do= ing fstat() on the open FD. I can't figure out any way for this code path to actually catch anything =E2=80=93 the FD would point to the file to which t= he symlink points, not to the symlink. To test this, simply create a symlink named sess_aaaa in the folder where p= hp stores its sessions that points to a file only accessible for your webserver user. If it contained text before, it will be wiped blank after a request w= ith PHPSESSID=3Daaaa to a script that uses sessions (if the script didn't have = any data it wanted to store). I filed a bug about this in the PHP bugtracker at <https://bugs.php.net/bug.php?id=3D66171> (but it's still marked as private= ), they haven't done anything about it so far. That bug contains a patch I wro= te. The patch should eliminate the issue with symlinks (but hardlinks would pro= bably still work, so I'm not sure how useful that is) and should also make the evil session creation attack at least a bit harder by requiring th= at a session file is owned by the current UID or UID 0. An attacker could still hardlink an existing file over into the directory, but he would at least ne= ed a file on the same partition that is owned by the webserver UID or UID 0 and = that he can write to (directly or through some other process) in order to create= a session with arbitrary data. So you should still change that PHP configurat= ion even with the patch. I'll paste it here so that anyone who wants it can apply it to his system/distribution: diff --git a/ext/session/mod_files.c b/ext/session/mod_files.c index 004d9d4..7a430ef 100644 --- a/ext/session/mod_files.c +++ b/ext/session/mod_files.c @@ -135,22 +135,22 @@ static void ps_files_open(ps_files *data, const char = *key TSRMLS_DC) =20 data->lastkey =3D estrdup(key); =20 + /* O_NOFOLLOW to prevent us from following evil symlinks */ +#ifdef O_NOFOLLOW + data->fd =3D VCWD_OPEN_MODE(buf, O_CREAT | O_RDWR | O_BINAR= Y | O_NOFOLLOW, data->filemode); +#else data->fd =3D VCWD_OPEN_MODE(buf, O_CREAT | O_RDWR | O_BINAR= Y, data->filemode); +#endif =20 if (data->fd !=3D -1) { #ifndef PHP_WIN32 - /* check to make sure that the opened file is not a= symlink, linking to data outside of allowable dirs */ - if (PG(open_basedir)) { - struct stat sbuf; - - if (fstat(data->fd, &sbuf)) { - close(data->fd); - return; - } - if (S_ISLNK(sbuf.st_mode) && php_check_open= _basedir(buf TSRMLS_CC)) { - close(data->fd); - return; - } + /* check that this session file was created by us o= r root =E2=80=93 we + don't want to end up accepting the sessions of a= nother webapp */ + struct stat sbuf; + if (fstat(data->fd, &sbuf) || (sbuf.st_uid !=3D 0 &= & sbuf.st_uid !=3D getuid())) { + close(data->fd); + data->fd =3D -1; + return; } #endif flock(data->fd, LOCK_EX); Of course, the real fix would be to just refuse to start unless the sessions folder is mode 0700 or so. Or maybe to use a setuid helper. ### Disclosure Timeline ### 2013-11-25 filed a bug report (but forgot to include the actual patch) 2013-12-13 asked for a response 2014-02-03 told them they have 14 more days. I notice that I can't see my p= atch in the bugtracker, they confirm and ask me to add it to the bug, which I do 2014-03-04 public disclosure on bugtraq --LZvS9be/3tNcYl/X Content-Type: application/pgp-signature; name="signature.asc" Content-Description: Digital signature -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQIcBAEBAgAGBQJTFjwkAAoJED4KNFJOeCOoVwMP/joPZll1EMR+aVC9lpP01P4V QQVyCWOFKc25pXNVqYaLrxGf3cCY8xteHULy1kMiXXWKX7+cbE5+YDXRZuj/KFEb 5U4EiHK4srDlmuUwWO/1UKFPyBKqUtnD0JqM2rLeZUzaSgAegms+VZyjMFefh+oF z9RFaCIz2kaLqunZwB++9kUOaFXTFL4KEgbOu3tw/TXPbnrCjZGNx0Xk8OEtQOGk FnjDPpPi+Luv4Lrzhi+ulakv0aQbqBkPSh6JpLMEKtq9exdDs4oZjTV02eMN/Tql W39mwk09TfDExtoWoQdPGmoti2QM5IpYjliy5vSKfgcI/+dM+5rqa0/+w0Or91WN iyhlZRrfgNOYueAw9IR75/K+AsmV3eaxFxRrBWCzBeqpey9+1U6qOIpWbtL/Ugqy ke08VCrXeDnV0H8VIWyctVCHAXYPNBajCxvV5rdOA2anJjwR45TweTwnETFLYnVw GsRlAvgZ9SrVuyMDFCSEyL6AiroMYkjlGizaJ3zH1OEm4le6kPZcB31Mor4iBPU7 DqO0XyGq9pxVYHCREf/wf9p7ZLflZpdMO6iPPACXhd/7dYSQYPu8bjl+by/JQSeg PWTtI6uvcoyDvYlJTg9DiXa5h71S0qp7jhXPF6lC9tl1A8WxC+LShRek8ephj67W FIW33/f9idoS57gjbtQ2 =KDcH -----END PGP SIGNATURE----- --LZvS9be/3tNcYl/X--