Filed under: Web and Application Security
Remote File Inclusion: how the bad guys take control
Remote File Inclusion (RFI) is a type of vulnerability that allows an attacker to include a remote file, usually through a script, on the target Web server. RFI occurs due to the use of user supplied input without proper validation. This can lead to something as minimal as outputting the contents of the file, but depending on the severity, to list a few it can lead to:
- Code execution on the web server
- Denial of Service (DoS)
- Data Theft/Manipulation
While in principle RFI can work against a variety of Web application platforms (like .NET and J2EE) in practice it is one of the most common types of attack against web applications written in PHP (including Mambo, Joomla, components, templates, etc.). PHP is particularly vulnerable to RFI attacks due to the extensive use of “file includes” in PHP programming and due to default server configurations that increase susceptibility to an RFI attack.
Most PHP applications are divided up into a number of files. When the application runs, only those files that are actually needed to perform the requested operation are loaded into memory – thus saving server resources. Different operations may require different files to be loaded or ‘included’ (the command that loads a file is called ‘include’ in PHP). This type of attack would typically happen only if PHP is configured so that both ‘register_globals’ and ‘allow_url_fopen’ are switched on.
An example of how a RFI attack works:
If a Web site is coded in PHP and is using a GET page command:
$file =$_GET['page']; //The page we wish to display
A simple search on Google:
And Joe Hacker is able to find sites that may be vulnerable to an RFI attack by exploiting the query parameter “page”.
This attacker could then insert his malicious script by doing the following:
The text file “evil_script.txt” contains some code that could look something like this:
echo “<script>alert(U 4r3 0wn3d !!);</script>”;
echo “Run command: “.htmlspecialchars($_GET[‘cmd’]);
That when executed properly will allow you to exploit the include function and will test if the site is in fact RFI vulnerable.
So why can an attacker do this? Well the simple answer is because the include() function allows you to link to remote files, and an attacker can take advantage of that feature, as in the example above. Note however that this kind of attack isn’t only open to the include function, require_once() will also work.
Other PHP commands vulnerable to RFI are include_once, fopen, file_get_contents, require and require_once.
A few interesting details: You might be wondering why the script that the attacker uses is a .txt and not a .php file. The answer: if the script was a .php and the attacker’s server had php installed then the script would get executed on the attacker’s server and not the target. You will also notice that there is a “?” at the end of the example above; this is added so that anything that might be already inside the include() function can be removed. By having the “?” on the end of the script we are going to treat the .php as if it is a var that is getting passed to the script.
What you can do to fight RFI on your server:
Preventing remote file include flaws takes some careful planning at the architectural and design phases, through to thorough testing. In general, a well-written application will not use user-supplied input in any filename for any server-based resource (such as images, XML and XSL transform documents, or script inclusions), and will have firewall rules in place preventing new outbound connections to the Internet or internally back to any other server.
The best practice is to use multiple layers of defense against RFI attacks.
Mod Rewrite via .htaccess file (for Apache servers)
Don’t Trust User Input
This type of attack can also be defended against by sanitizing the inputs. Input can also be sanitized directly in the PHP code.
Check all global arrays like $_GET, $_POST, $_REQUEST, $_COOKIE, allow only known variables and make sure that they contain the right type of data. What does this mean? It means that if you have a $_GET[‘id’] variable in your script which has to be an integer, always check it and make sure it is an integer. Also don’t allow other variables in $_GET or other globals, keep only variables that your scripts need. So, if your script only uses only one variable $_GET[‘id’] then dispose other variables.
Windows Based Security
If you are on Windows, and if code changes are not a practical option, then you should consider using a good Web Application Firewall that handles the sanitization of user input for you.
And of course, it’s not a bad idea to use a mixture of server-based and code-based strategies since, as with any Web app vulnerability, this ‘defense in depth’ lowers the odds of something dangerous getting through, because it happens to be a variant that one layer didn’t catch..