Уязвим ли этот скрипт для LFI (внедрение локального файла)?

#php #security #code-injection

#php #Безопасность #внедрение кода

Вопрос:

Мне было интересно, был ли этот небольшой фрагмент подвержен уязвимости локального внедрения файла.

 <?php
$lang = $_GET['lang'];
include '/some/dir/prefix_'.$lang.'whatever';
  

Я знаю, что все, что угодно, можно игнорировать, поместив » (нулевой байт) в запрос. Но если в каталоге /some/ dir / нет подкаталога, начинающегося с ‘prefix_’, может ли произойти эксплойт? Каким образом?

Заранее спасибо за ответ.

Ответ №1:

Вы имеете в виду что-то вроде этого?

 $lang .= 'en/../../../../../etc/passwd' . 0x00;
  

Вы можете избежать этого с помощью

 $path = '/some/dir/prefix_'.$_GET['path'].'whatever';
$path = realpath($path);
if (($path !== false) amp;amp; (strncmp('/dir/some/prefix_', $path, 17) === 0)) {
  // $path is fine
}
  

Это проверяет, существует ли путь и действительно ли он находится в дереве каталогов, что вы разрешаете ему быть. Этого должно быть достаточно.

Комментарии:

1. Да, я имею в виду что-то вроде этого. Но не так. Каталог /some/dir/prefix_xy / не существует. Как файловая система может преобразовать /some/dir/prefix_xy / ../ в /some / dir /?

2. Это был пример. Может быть, можно использовать en вместо xy (я изменил это в своем ответе). Теперь prefix_en существует и .. снова работает нормально. В любом случае, ему нельзя доверять 😉

3. Я цитирую себя: «в каталоге /some/ dir / нет подкаталога, начинающегося с ‘prefix_'». Итак, нет каталога /some /dir/prefix_en/. «Что угодно» указывает на файл.

4. Также проверка может быть неверной. realpath(‘/var/somehing’) может возвращать ‘/mnt/somethingelse/’.

Ответ №2:

Использование пользовательского ввода непосредственно в вашем коде всегда опасно.
Было бы лучше заставить его проверять, находится ли значение в массиве приемлемых значений.

Комментарии:

1. Я знаю, это не дает ответа на мой вопрос, даже отдаленно.

2. этот ответ должен быть принят. Если вы не знаете, как использовать эксплойт, это не значит, что эксплойт непригоден. Правило простое: не доверяйте вводимым пользователем данным. Без каких-либо исключений.

3. Я знаю. Я не использую этот код, я пытаюсь изучить и понять. Мне любопытно. Это не тот ответ, который я ожидал.

4. То, что это был не тот ответ, которого вы не ожидали, не делает его плохим или неправильным. Хотя этот пост не отвечает на поставленный вами вопрос, в нем содержатся хорошие рекомендации по проверке входных данных.

Ответ №3:

Ну, вы можете внести его в белый список, что-то вроде

 $possible_languages = array('en','fr','pt'); #preferably not hardcoded
$lang = $_GET['lang']
if( in_array($lang, $possible_languages) ){
     # do your thing
}
else {
    #error out
}
  

В принципе… никогда не доверяйте пользовательскому вводу.

Комментарии:

1. Тот же комментарий, что и выше (для gnur).