Краткое описание проблемы
Как развивались события:
21 сентября мы сообщили об этом разработчикам:
http://bugs.php.net/38915
(сообщение я писал поздно ночью, поэтому за ошибки в тексте просьба сильно не пинать ;)
Никакой реакции от PHP Team в течении почти месяца не было.
Потом мы решили отослать информацию на securityfocus.com, что и было сделано 19 октября
(
http://www.securityfocus.com/archive/1/449234/30/0/threaded)
Ответ разработчиков PHP:
Sorry, but your problem does not imply a bug in PHP itself.
...
Thank you for your interest in PHP.
The opened file descriptors are opened by Apache.
It is the job of Apache to protect them, not something that should be
reinvented in all apache modules.
Not a bug in PHP.
Bernhard Mueller из SEC Consult написал:
Hello,
This is not a new problem (see
http://www.securityfocus.com/bid/9302).
However, we also discovered this a few weeks ago and contacted Apache
and PHP about it. According to Stefan Esser (PHP) its due to Apache's
failure to open file descriptors with the close on exec flag. However,
according to Joe Orton (Apache) won't change this flag because it would
make no difference to Apache's security model («anything you can do in a
sh script spawned by a PHP script you can do directly in the PHP script
anyway»). The bottom line is that this will also work in future, because
neither the Apache team nor the PHP team will fix the issue.
Personally, I'd think that a combination of both measures (close on exec
flag and explicitly closing specific file descriptors by PHP) would make
the most sense.
BTW, with this flaw an attacker can also conveniently change / overwrite
Apache's log files and therefore hide his attack after owning a
PHP-based web application. Here's a quick POC as I haven't seen one
anywhere yet :)
...
Bernhard
Что радует, есть люди, которые не согласны с PHP Group по поводу бага.
20 октября мне пришло письмо от Jeff Lawson из United Devices:
I disagree with PHP's response to your bug
http://bugs.php.net/bug.php?id=38915. Unfortunately, I cannot reopen
your bug since their bug system only allows the bug submitter to reopen
it. If you can do that, then I will be able to add my response to the
bug in support of you. Thanks
>>It should be PHP's responsibility to close all open file handles
(after forking but before the exec).
Keep in mind that PHP is running as a module within the same process
space as Apache, and those private FDs are required for it to operate.
Apache cannot reasonably close and re-open all of those whenever it is
invoking a module's handlers, nor can it reasonably run modules in a
separate process. Modules are intended to be trusted code and so Apache
does not attempt to protect itself from misdesigned modules.
(In the case where PHP is installed as a CGI and not a module, then
Apache does indeed close the private FDs prior to running PHP.)
For example, when a CGI process via Apache's mod_cgi, that module is
responsible for ensuring that it explicitly closes all open files prior
to the exec(). PHP is in a similar situation and should also do the
same when executing sub-processes.
22 октября я изменил статус бага на Open.
Посмотрим, что будет.
30 октября. Jeff Lawson написал свой мнение на bugs.php.net.
14 ноября. Никакой неакции от PHP Group.
Дополнительные материалы
Все статьи Steve Grubb в одном месте
Похожая проблема в My SQL
http://bugs.mysql.com/bug.php?id=3779
Утечка дескрипторов в mod_cgi
Первое упоминание о проблеме (Steve Grubb), 16 jul 2001
Apache HTTPD Bugs Mailing List – Filehandles of logs not closed before exec of cgi scripts (fixed) 19 feb 2003
Apache 2.x leaked descriptors (Steve Grubb) 21 feb 2003
Подробный bug report с рассмотрением исходного кода, 21–23 feb 2003
Discussion on fd leak problematic, 14 mar 2003
Вот здесь довольно хорошо написано
[PATCH] Have logfiles closed on exec
Re: [PATCH] Have logfiles closed on exec
http://sources.zabbadoz.net/patches/apache/
PHP related
Сообщение на bugs.php.net про утечку дескрипторов (Steve Grubb) 7 nov 2002
suPHP (a tool for executing PHP scripts with the permissions of their owners)
Other
ILLC – Inverse Lookup Log Corruption
Some important things
* Apache by itself does not leak fd's, because its ap_cleanup_for_exec() API
has made sure (for ages already) that nothing is passed to exec'ed processes.
* certain 3rd party modules do not use the API correctly (either because
they don't know better, or because they wanted top use existing unsafe
functions like system() and popen()) and do not invoke ap_cleanup_for_exec(),
thus leaking fd's.
The leaked fd's include the server's listener sockets, the accept()ed
request sockets, the access_log file, several lock files.
* By using FD_CLOEXEC with the new ap_note_cleanups_for_*_ex() functions,
we can proactively plug these leakages, even though it would be better if
the 3rd party module authors would do it right in _their_ code.
The apache source code already has hooks for closing these resources. The reason it is not happening is because there is a bug. A trivial patch has been posted and is being discussed with the apache group.
Christian Kratzer (CK Software), 25 feb 2003
Has anyone played with various modules looking to see if anything beyond access or
error logs are available? For example, if you look at mod_php, they leak the file
descriptor from accept() and the descriptor to the php page being executed in addition
to all the other descriptors.
Steve Grubb, 25 feb 2003
I think you can be more inventive on what a malicious script author can if they can run
arbitrary code from a CGI script, under the Apache model: here are some things I can up with:
– using ptrace() on an httpd child: now you can get the httpd child to run arbitrary code,
so fd leaks from child to CGI script are really irrelevant. (This is an old trick: nCipher used
this as a demo of how to extract in-server SSL private keys using a CGI script)
– send signals to the server children: SIGSTOP will make a quick'n'easy Do S.
I'm sure there are more. The bottom line is that you must trust CGI script authors with the
priviledges of the user which httpd runs as.
Joe Orton (redhat.com), 13 mar 2003
My point is that merely fixing these fd leaks does not improve security if you don't trusted
your CGI script authors, since a malicious CGI script can use ptrace() to run arbitrary code in
an httpd process, thereby gaining access to all the log file fds and more.
If you allow PHP scripts to exec/system/etc arbitrary binaries on your system, then the same
applies. PHP safe mode mitigates this somewhat, as I've said above.
Joe Orton (redhat.com), 13 mar 2003
Steve Grubb про утечку FD в модулях:
I would think apache should have a safe and defined interface between itself and modules. I cannot
possibly think of any file descriptor besides 0, 1, &2 that a module would need.
Другие модули
Я протестировал:
– mod_perl (2.0.1) + Perl (5.8.7) – утечка дескрипторов
– mod_python (3.2.10) + Python (2.3.4) – утечка дескрипторов
– mod_tcl (1.0.1) + TCL (8.4.14) – утечка дескрипторов
– mod_ruby (1.2.6) + Ruby (1.8.5) – утечки дескрипторов НЕТ! Перед выполнением внешней программы Ruby закрывает все дескрипторы с номерами, большими 2:
io.c: static VALUE pipe_open(pstr, pname, mode): 3126:
for (fd = 3; fd < NOFILE; fd++) close(fd);
...
rb_proc_exec(pname);
Позиция The Apache Software Foundation
Решил уточнить позицию Apache по данному вопросу:
From: dimmoborgir
To: secutity [at] apache.org
Hello!
There is an old problem with FD leak through mod_php:
bugs.php.net/20302
bugs.php.net/38915
PHP Team don't want to fix the problem («It is the job of Apache to protect them»).
I tested some other modules, they also have this problem:
Perl (5.8.7) + mod_perl (2.0.1)
Python (2.3.4) + mod_python (3.2.10)
TCL (8.4.14) + mod_tcl (1.0.1)
These leaked FD's can be used to write fake messages into Apache's logfiles, to clear logs,
to accept connections on privileged(!) HTTP(S) port. They can be used only in a prorgam,
spawned by PHP script (via exec() or system() functions), they can't be used in a PHP script,
because PHP itself don't have functions to access FD's by number.
So, why not just set FD_CLOEXEC flag on file descriptors to prevent their leakage to
external program? It will increase the security of Apache Web Server (when it works
with mod_php, for example).
Best regards, Dmitry.
From: Joe Orton
To: dimmoborgir
Hi Dmitry,
When scripts are interpreted using dynamically loaded loaded script
interpreters (mod_php, mod_python, PHP via Apache SAPI, etc), the
interpreter executes with the privileges of the httpd child process.
If the intepreter does not sandbox scripts from the environment in
which they run (as you might expect from a system like Java, for
example), the privileges of the httpd children are in effect inherited
directly by the scripts themselves.
Your report makes the implicit assumption that some other security model
exists; that PHP/Perl/... scripts can be run using the in-process
interpreter with some lesser set of privileges than those with which the
httpd child executes. That assumption is false; the vulnerability
described is a necessary consequence of the configuration used.
The specific case of leaking file descriptors to process spawned by
interpreted scripts is particularly moot. On any modern Unix system, a
process can access all its parents fds via e.g. the /proc/ filesystem,
and indeed obtain complete control over its parent via ptrace(). This
is true regardless of what fds are left open when the child process is
exec()ed, and whether or not FD_CLOEXEC is used. So no, using
FD_CLOEXEC does not improve security.
If a different configuration is used, a different security model can
be obtained: for example, by using the PHP interpreter as a CGI
program along with the suexec interfaces in Apache, PHP scripts can
be executed out-of-process under a different uid, and hence a
different set of privileges.
Fast CGI is another popular alternative.
Regards, Joe Orton