Tải bản đầy đủ (.pdf) (13 trang)

Preventing Code Injection

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (262.02 KB, 13 trang )

C
ode injection is arguably the most dangerous vulnerability that can affect a PHP script.
Unsurprisingly, it’s also caused all too often by a lack of input validation.
In most cases, code injection can be traced to
register_globals
and including a
script based on the value of a variable. For example, many templating systems utilize
GET
/
POST

parameters to choose what template to load. The parameter may be a filename or even a path,
and if the template is a pre-compiled script, as found in Smarty, it may contain PHP code and
necessarily be loaded via
include
or
require
.
You can probably guess where this leads: a clever attacker can hijack this infrastructure
87sand execute an arbitrary local or remote file—in other words, inject code to perform virtu-
ally any task that can be expressed in PHP. An assailant can capture information, modify a da-
tabase, change the contents of local files and scripts, and even compromise an entire system.
Take every precaution possible to reduce and ideally eliminate the threat of code injec-
tion. Thankfully, a fairly limited subset of PHP functions are susceptible to code injection, and
a simple code audit using
grep
can turn up most weaknesses.
4
Preventing
Code Injection
88


Preventing Code Injection
grep –i “\(include\|require\|eval\)” *.php
Here,
grep
detects usage of
require
,
include
, and
eval()
, the three PHP constructs that can
“insert” new code into a script. Once instances of those functions are found, you must secure
each one.
Path Validation
Securing
include
and
require
is a multi-step process. The first step is to better qualify what
script you’re including.
// Bad
require “foo.inc”;
// Good
require “/home/ilia/app/libs/foo.inc”;
require “./libs/foo.inc”;
If you include a file yet omit its full path or a partial path—as shown on line 2 above—you can-
not predict where the file will come from. The file may come from a current directory or it could
come from any of the directories listed in the
ini
directive

include_path
.
Searching for files along the
include_path
isn’t especially fast, but worse, should the
in-
clude_path
change (because it’s modified by a third-party application, say), a vital script may
“disappear” or may be replaced accidentally by another file of the same name.
Whenever possible, provide a full path or at least a partial path to eliminate or reduce am-
biguity.
Using Full Paths
A common way to specify fully-qualified filenames is to store the full path to a specific library
directory in a PHP variable and prefix each filename with that variable.
While this technique prevents ambiguity, it’s not bulletproof. If a logic bug or some other
condition affects the variable, the application may not work or may work improperly. Even a
typo in the variable name (a bug nonetheless) is a real hazard: if
register_globals
is enabled,
a user could inject a value into the errant variable.
A more secure approach places the path to the library directory in a constant. A constant
89Preventing Code Injection
cannot change once it’s been defined. Furthermore, if the constant name is mistyped, there’s
no way to inject a value into. And because an undefined constant is converted to a string of its
own name, an error like a typo typically causes a script to fail, quickly turning up the bug.
This code points out the potential pitfalls and the optimum solution:
$__INC_DIR__ = “/home/ilia/app/libs/”;
require $__INC_DIR_ . “foo.inc”; // code injection, $__INC_DIR_ is not set
// vs
define(‘__INC_DIR__’, “/home/ilia/app/libs/”);

require INC_DIR . “foo.inc”; // fatal error, attempt to open nonexistent file
Avoiding Dynamic Paths
Some of the most dangerous code injections force PHP to retrieve a script from a third-party
server—a veritable Pandora’s Box (or maybe “lion’s den” is a better metaphor).
To load a remote script, an attacker simply injects a URL into a variable that’s used to in-
clude a file. For example, using the code above as a basis, an attacker could pass
__INC_DIR_
= /> via GET or POST to achieve nefarious ends.
Luckily, you can set
allow_url_fopen
to
Off
to prevent this exploit. This
ini
setting can
only be set outside of your script, either inside
php.ini
or in your Apache configuration. Unfor-
tunately, that means that once
allow_url_fopen
is set, your application cannot retrieve remote
files at all.
While the latter restriction may be too onerous for your application, setting
allow_url_fo-
pen
may be perfect for hosting providers, where the feature can be disabled by default and only
enabled for users who need the feature.
Of course, you can still access remote sources, albeit with the use of cURL or via your own
socket code.
Possible Dangers of Remote File Access

Another possible danger of remote file access is the ability for an attacker to create a request
loop that forces your server to launch a Denial of Service (DoS) attack upon itself or anoth-
er server. If the attacker can force your application to continually make requests, the target
machine (which may be the same server) rapidly exhausts all available web server processes,
denying access to legitimate visitors. This problem can even be triggered by seemingly safe re-
90
Preventing Code Injection
quests, such as
getimagesize()
. An attacker can specify a URL that redirects the request back
to its originator, thus creating a request loop.
getimagesize(“ // value of _GET[‘img’]
// The web server on very.evil.com would then do something like this
header(“Location: {$_SERVER[‘HTTP_REFERER’]}?img= />The very.evil.com server simply detects a request for the “trick” image and sends the request
back to the originator, providing the same
GET
parameter that triggers an identical request.
Soon enough, all of the web server’s processes are dedicated to the task of fetching
fluffy_bun-
ny.jpg
.
To further complicate matters, just restarting the web server often doesn’t solve the prob-
lem, because a few requests may remain in the buffer and be just enough to resume the attack.
The only sure way to stop such an attack is to shut down the web server and restart it a few sec-
onds later, which clears the buffer. Of course, this is just a temporary solution—until the next
request starts the downward spiral anew.
A partial solution to this problem is to disable
allow_url_fopen
, if the limitations of that
setting mentioned earlier are acceptable for your application.

However, since socket connections and cURL are also susceptible to this form of attack,
an additional form of security is needed: use IP-based access rules to reject requests that origi-
nate from your own server. You can set these rules either in your firewall (say, using Linux’s
iptables
) or in Apache:

# Linux IP tables firewall rule
iptables -A INPUT –s [local_ip_address] --dport www -j DROP
# Apache LIMIT directive
<Directory /home/user/public_html>
Order Allow,Deny
Allow from all
Deny from [local_ip_address]
</Directory>
Both of the configurations shown reject web traffic that originates from the local IP address.
Generally speaking, firewall rules are more efficient than IP-based access set inside the
91Preventing Code Injection
web server. Additionally, you can prevent all forms of protocols in the firewall; Apache only
manages web traffic. However, firewall configuration typically requires root access, something
that is not usually available to most developers or to lessees of a shared host.
When setting up access rules, create rules for all of the IP addresses used to access the site, including the
loopback interface,
127.0.0.1
.
Even with these safety checks in place, it’s still possible to create a request loop: simply add a
proxy server to relay the request:
$_GET[‘var’] = “ />require $_GET[‘var’]; // rinse, lather, repeat...
The example above uses the W3C validator to proxy the request to the intended destination.
The URL is opened by the W3C server, thus completely masking the originator of the request
and easily bypassing the IP-based rules.

Ultimately, the only sure way to avoid a request loop is by not making requests to remote
servers for data, unless you’re requesting a pre-determined URL of a “safe” server, such as an
XML feed from Google, Amazon, or your trusted friend’s RSS feed.
Validating File Names
The filename component of an included file is somewhat less dangerous than the path, as it
can only be used to load existing files from the system. Nonetheless, it can still be used by hack-
ers to perform a whole series of untoward operations.
For example, by pre-pending the file name with a series of
../
strings (referring to the
parent directory of the file), it’s possible to make PHP access directories outside of the direc-
tory structure specified by the script and display contents of any web server readable file on
the system. These can include authentication files such as
/etc/passwd
that contains sensitive
system login information:
$_GET[‘t’] = ‘../../../../etc/passwd’; // injected value
// open a compiled Smarty template based on user provided string.
require “/home/user/app/templates_c/”.$_GET[‘t’];

Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Tải bản đầy đủ ngay
×