2

i have a php code for my website and a friend told me that my code has a local file inclusion vulnerability because im using the " include " method.

can someone help me in fixing it or lead me to where i can find help? i tried a couple of possible ways of fixing it but that didn't work. the problem is with including the language file in my code.

here is the code below to be more clear :

<?php 

if(isSet($_GET['lang']))
$lang = $_GET['lang'];
else $lang='en';

include 'languages/'.$lang.'.php'; 
include("header.php");
?>

P.S i only have 2 language files and they are English = "en.php" and Arabic = "ar.php"

i would really appreciate it if someone could help.

Seven-up
  • 21
  • 3

2 Answers2

2

Do not EVER trust user inputs!

<?php 

if ( isset($_GET['lang']) && $_GET['lang'] == 'en') {
    $lang = 'en';
} else {
    $lang = 'ar';
}

include 'languages/'.$lang.'.php'; 
include("header.php");

?>

Or, preparing for possible additional languages, I would go like this:

<?php 

$lang = !empty($_GET['lang']) ? $_GET['lang'] : 'en';

switch($lang) {
    default:
    case 'en':
        include 'languages/en.php'; 
        break;
    case 'ar':
        include 'languages/ar.php'; 
        break;
}

include("header.php");

?>

This way you can easily add extra languages later on and also always make sure, that only the required file is included.

Peon
  • 7,902
  • 7
  • 59
  • 100
  • Thank you so much Dainis Abols for your replay. The second code worked for me but something was wrong with the first code. – Seven-up May 19 '16 at 10:10
  • missing semicolons, since I didn't actually run the script :D – Peon May 19 '16 at 10:12
1

The vulnerability is that one could send any kind of relative path in $lang. This is especially dangerous if users can upload files and figure out their real path on the server.

Example:

  • A hacker may use some file upload functionality of your site to upload evil.php. The hacker may know/have found out/guess that it's stored at /var/www/uploads/evil.php, and that your application runs in /var/www/html.
  • Now, normally nobody could run this file if /var/www/uploads is not accessible through HTTP.
  • But, it would be possible to open http://example.com/index.php?lang=../../uploads/evil and guess what, it would include languages/../../uploads/evil.php which would resolve to /var/www/uploads/evil.php!

This of course also works without file upload if there are any other files which can be used for exploiting something by getting access to them and calling them, such as maybe files in a normally password-protected directory (phpMyAdmin for example).

And if you now think "that's quite a lot of assumptions and 'may's and 'if's in there, you would need to be very lucky to succeed with this" then watch out - although there are some obvious blatantly open vulnerabilities where you do one URL call and you can, let's say, overtake the server or delete the database, the most dangerous ones are the ones which require multiple puzzle pieces to make an exploit work, because they go undetected for a long time and it can be hard to understand how the server got actually hacked once it happens, and you will naturally have a more experienced and therefore more dangerous (possibly stealth) hacker at your doorstep. If somebody is determined to find a security hole (either because they have an actual goal attacking your site or you, or because they just enjoy owning poor webmasters to push their own ego), they will keep searching and puzzle together whatever is required to achieve what they want.


There are multiple solutions.

As suggested by u_mulder, if you have only ar and en then just check if it's either one.

If you have more languages, you could just create an array with a list of allowed values and check if the sent language is in that array, for example:

$languages = ['de', 'en', 'ar', 'jp', 'fr'];
if(in_array($_GET['lang'], $languages)) {
    $selectedLanguage = $_GET['lang'];
} else {
    $selectedLanguage = 'en'; // default
    // Note that you could also show an error "invalid language" instead
}

If you want to control this by just allowing only the files existing in the folder, you could also just validate that the language contains only letters (or whatever you need, as long as you make sure it may not contain dots or slashes or such):

if(preg_match("/^[a-z]*$/", $_GET['lang'])) { ... }

Note that with this approach you should definitiely also check if the specified file exists, otherwise it would still be possible to have a language-less site by specifying an invalid language (especially since include doesn't throw an error on non-existing files, unlike require).

CherryDT
  • 25,571
  • 5
  • 49
  • 74