What is an RFI?
An RFI (or remote file inclusion) is a web application vulnerability that allows users to include any file that they wish, to be executed by your server. I'll explain more on this later, but this is the simple answer.
When do RFIs occur?
RFIs occur when an include() or require() statement references a variable that is not explicitly defined in the file. Let me explain.
index.php:
// Main page
// Keep copyrights in place
// Awesome PHP Board 1.5
$configfile = '/config/config.php';
//Include the config file
include($configfile);
// Include the core file
include('core.php');
. . .
This file has the $configfile variable defined explicitly. It then includes it, then includes the file core.php. Here's what core.php looks like:
core.php:
// Core functions file
// Awesome PHP Board 1.5
//Include the config file
include($configfile);
// Include the SQL file
include('db.php');
. . .
This file includes $configfile, but it does not define the $configfile variable. Therein lies the problem. During normal execution, the $configfile variable would be defined in index.php, then when core.php was included, it would be available. Thus, the script would execute normally. However, if somoene were to access core.php directly, they might get an error like this:
Warning: include() [function.include]: Failed opening " for inclusion (include_path='.') in C:wwwpublic_htmlcore.php on line 6
As you can see, it's trying to include a file that doesn't exist.
What is the risk of RFIs in code?
While your PHP files may be completely harmless, it's possible to create something that will allow a malicious user to basically take over your website, and possibly the entire server you are hosted on. These files are often called "php shells", and they have all sorts of nasty functions that can compromise your security, such as command execution, file editing, ftp bruteforcing, MySQL dumping and anything else you can think of. If a vulnerability is found in your code, you can bet that it will be released to the security world in general very quickly, probably too quickly to allow all your clients to patch their applications.
How do I eliminate RFIs in my code?
One method that I recommend greatly is simply explicitly defining all include variables per-file. Here are some examples.
$confdir = '../../config/'; $configfile = '../../config/config.php'; include($confdir . 'db.php'); include($configfile);
Another method is to use the die() function if you know the necessary variables are not defined. This is good if you have multiple paths or files that you need to include, and their locations are different per-file.
if(!$configfile || !$confdir){
die('Nice try.');
}
Another popular method is to define an "is_included" variable, and check to see if the file is being accessed legitimately.
page1.php
define('is_included', true);
include('page2.php');
page2.php
if(!defined('is_included')){
die('Hacking attempt');
}
Another method which is mainly used for small websites with a set, known number of pages, is simply to use a switch statement. This is usually used on sites with something like ?p= or ?url= in the URL bar. It looks something like this:
switch($_GET['p']){
case 'home': include('home.php'); break;
case 'email': include('email.php'); break;
default: die('Unknown page');
}
There are definitely other methods, such as using advanced regular expressions to find and remove URLs from your variables, turning off the remote file opening option in php.ini, etc. The best method definitely depends on the project in question, and it is up to you to decide. Always scan your code carefully for these vulnerabilities, and make sure that you take appropriate measures to ensure that your code stays safe.



